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

pull/2173/head
nick black 3 years ago
commit b3912e96e9
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -21,10 +21,6 @@ steps:
- LDFLAGS=-L/usr/local/lib CFLAGS=-I/usr/local/include python3 setup.py sdist build install
- env LD_LIBRARY_PATH=/usr/local/lib ./notcurses-pydemo > /dev/null
- env LD_LIBRARY_PATH=/usr/local/lib ./ncdirect-pydemo > /dev/null
- cd ../rust
- rustc --version
- cargo build
- cargo t_all
---
kind: pipeline
type: docker
@ -43,10 +39,6 @@ steps:
- ctest --output-on-failure
- make install
- ldconfig
- cd ../rust
- rustc --version
- cargo build
- cargo t_all
- cd ../cffi
- LDFLAGS=-L/usr/local/lib CFLAGS=-I/usr/local/include python3 setup.py sdist build install
- cd ../python

@ -27,8 +27,7 @@ jobs:
libunistring \
ncurses \
pandoc \
readline \
rust
readline
- uses: actions/checkout@v2
@ -69,11 +68,3 @@ jobs:
python3 setup.py build
#sudo python3 setup.py install
#python3 examples/000-print-version.py
- name: rust wrappers
run: |
export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig"
cd rust
rustc --version
cargo build
cargo t_all

@ -81,10 +81,3 @@ jobs:
python3 setup.py build
sudo python3 setup.py install
python3 examples/000-print-version.py
- name: rust wrappers
run: |
cd rust
rustc --version
cargo build
cargo t_all

@ -85,11 +85,3 @@ jobs:
#python3 setup.py install
#notcurses-pydemo > /dev/null
#ncdirect-pydemo > /dev/null
- name: rust wrappers
run: |
cd rust
#rustc --version
#cargo build
#cargo t_all
#mingw-w64-ucrt-x86_64-rust

@ -690,9 +690,9 @@ typedef struct ncinput {
// Read a UTF-32-encoded Unicode codepoint from input. This might only be part
// of a larger EGC. Provide a NULL 'ts' to block at length, and otherwise a
// timespec to bound blocking. Returns a single Unicode code point, or
// (uint32_t)-1 on error. 'sigmask' may be NULL. Returns 0 on a timeout. If an
// event is processed, the return value is the 'id' field from that event.
// 'ni' may be NULL.
// (uint32_t)-1 on error. Returns 0 on a timeout. If an event is processed, the
// return value is the 'id' field from that event. 'ni' may be NULL. 'ts' is an
// *absolute* time relative to gettimeofday() (see pthread_cond_timedwait(3)).
uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts,
ncinput* ni);

@ -1068,10 +1068,9 @@ ncinput_equal_p(const ncinput* n1, const ncinput* n2){
// Read a UTF-32-encoded Unicode codepoint from input. This might only be part
// of a larger EGC. Provide a NULL 'ts' to block at length, and otherwise a
// timespec to bound blocking. Returns a single Unicode code point, or
// (uint32_t)-1 on error. 'sigmask' may be NULL. Returns 0 on a timeout. If an
// event is processed, the return value is the 'id' field from that event.
// 'ni' may be NULL. 'ts' is an *absolute* time relative to gettimeofday()
// (see pthread_cond_timedwait(3)).
// (uint32_t)-1 on error. Returns 0 on a timeout. If an event is processed, the
// return value is the 'id' field from that event. 'ni' may be NULL. 'ts' is an
// *absolute* time relative to gettimeofday() (see pthread_cond_timedwait(3)).
API uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts,
ncinput* ni)
__attribute__ ((nonnull (1)));

@ -1,14 +0,0 @@
[alias]
d = "doc --no-deps"
do = "doc --no-deps --open"
re = "run --example"
rre = "run --release --example"
rqe = "run --quiet --example "
req = "rqe"
# TEST
# fix IO errors: https://github.com/dankamongmen/notcurses/issues/766
t = "test -- --test-threads 1 --nocapture"
t_all = "test --no-fail-fast -- --test-threads 1 --nocapture"

@ -1,48 +0,0 @@
[package]
name = "libnotcurses-sys"
version = "2.4.1"
authors = [
"nick black <dankamongmen@gmail.com>",
"José Luis Cruz <joseluis@andamira.net>"
]
license = "MIT OR Apache-2.0"
edition = "2018"
description = "Low-level Rust bindings for the notcurses C library."
documentation = "https://dankamongmen.github.io/notcurses/rustdoc/libnotcurses_sys/"
repository = "https://github.com/dankamongmen/notcurses"
homepage = "https://nick-black.com/dankwiki/index.php/Notcurses"
readme = "./README.md"
links = "notcurses"
build = "build/build.rs"
categories = [
"external-ffi-bindings",
"command-line-interface",
"visualization",
"multimedia",
"rendering",
]
keywords = ["tui", "cli", "terminal", "ncurses", "ffi"]
include = ["build/", "examples/", "src/", "LICENSE-*", "README.md"]
[dependencies]
libc = { version = "^0.2.80", default-features = false }
cty = "^0.2.1"
[build-dependencies]
bindgen = "^0.57"
pkg-config = "^0.3.18"
[dev-dependencies]
serial_test = "^0.5.0"
serial_test_derive = "^0.5.0"
rand = "^0.8"
# https://doc.rust-lang.org/cargo/reference/profiles.html
[profile.dev]
#
[profile.release]
# opt-level = 0 # [0-*3 | s | z]
# lto = "fat" # [*fat | thin]
# debug = 1 # [*0/false | 1 | 2/true]
# debug-assertions = true # [*false | true]

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -1,25 +0,0 @@
Copyright 2020-2021 José Luis Cruz and Nick Black
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

@ -1,105 +0,0 @@
[![Crate](https://img.shields.io/crates/v/libnotcurses-sys.svg)](https://crates.io/crates/libnotcurses-sys)
[![API](https://docs.rs/libnotcurses-sys/badge.svg)](https://dankamongmen.github.io/notcurses/rustdoc/libnotcurses_sys/)
[![MSRV: 1.48.0](https://flat.badgen.net/badge/MSRV/1.48.0/purple)](https://blog.rust-lang.org/2020/11/19/Rust-1.48.html)
`libnotcurses-sys` is a low-level Rust wrapper for the
[notcurses C library](https://www.github.com/dankamongmen/notcurses/)
This library is built with several layers of zero-overhead abstractions
over the C functions and pointers accessed through FFI.
# How to use this library
There are basically two ways: The [**Rust way**](#1-the-rust-way),
and the [**C way**](#2-the-c-way). (Or a mix of both).
## 1. The Rust way
Where you use the more safely wrapped types, with its methods and constructors,
and painless error handling, like this:
```rust
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let mut nc = Nc::with_flags(NCOPTION_NO_ALTERNATE_SCREEN)?;
let plane = nc.stdplane();
plane.putstr("hello world")?;
nc.render()?;
nc.stop()?;
Ok(())
}
```
Although you still have to manually call the `stop()` method for `Nc`
and `NcDirect` objects, and the `destroy()` method for the rest of types that
allocate, (like `NcPlane`, `NcMenu`…) at the end of their scope, since the Drop
trait is not implemented for any wrapping type in libnotcurses-sys.
But they do implement methods and use `NcResult` as the return type,
for handling errors in the way we are used to in Rust.
For the types that don't allocate, most are based on primitives like `i32`,
`u32`, `u64`… without a name in the C library. In Rust they are type aliased
(e.g.: `NcChannel`, `NcChannelPair`, `NcRgb`, `NcColor`…), to
leverage type checking, and they implement methods through traits
(e.g. `NcChannelMethods` must be in scope to use the `NcChannel` methods.
## 2. The C way
You can always use the C API functions directly if you prefer,
in a very similar way as the C library is used.
It requires the use of unsafe, since most functions are wrapped directly
by `bindgen` marked as such.
Error handling is done this way by checking the returned `NcIntResult`,
or in case of receiving a pointer, by comparing it to `null_mut()`.
### Example
```rust
use core::ptr::{null, null_mut};
use std::process::exit;
use libnotcurses_sys::*;
fn main() {
let options = ffi::notcurses_options {
termtype: null(),
loglevel: 0,
margin_t: 0,
margin_r: 0,
margin_b: 0,
margin_l: 0,
flags: NCOPTION_NO_ALTERNATE_SCREEN,
};
unsafe {
let nc = notcurses_init(&options, null_mut());
if nc == null_mut() {
exit(1);
}
let plane = notcurses_stdplane(nc);
let cols = ncplane_putstr(&mut *plane, "hello world");
if cols < NCRESULT_OK {
notcurses_stop(nc);
exit(cols.abs());
}
if notcurses_stop(nc) < NCRESULT_OK {
exit(2);
}
}
}
```
### The `notcurses` C API docs
- [API reference (man pages)](https://notcurses.com/)
- [Wiki Page](https://nick-black.com/dankwiki/index.php/Notcurses)
- [The Book Guide (pdf)](https://nick-black.com/htp-notcurses.pdf)
- [USAGE.md](https://github.com/dankamongmen/notcurses/blob/master/USAGE.md)
- [HACKING.md](https://github.com/dankamongmen/notcurses/blob/master/doc/HACKING.md)
- [Doxygen Documentation](https://nick-black.com/notcurses/html/index.html)
- [FOSDEM 2021 presentation](https://fosdem.org/2021/schedule/event/notcurses/)

@ -1,99 +0,0 @@
extern crate bindgen;
extern crate pkg_config;
use std::env;
use std::path::PathBuf;
// largely taken from https://rust-lang.github.io/rust-bindgen/tutorial-3.html
fn main() {
let plib = pkg_config::Config::new()
.atleast_version("2.4.1")
.probe("notcurses")
.unwrap();
// Tell cargo to invalidate the built crate whenever the wrapper changes
println!("cargo:rerun-if-changed=build/wrapper.h");
// The bindgen::Builder is the main entry point to bindgen, and lets you
// build up options for the resulting bindings.
//
// https://docs.rs/bindgen/*/bindgen/struct.Builder.html
//
// allow .blacklist_function instead of .blocklist_function for now,
// until we update bindgen to >= 0.58.
#[allow(deprecated)]
let mut builder = bindgen::Builder::default()
.use_core()
.ctypes_prefix("cty")
.clang_arg("-D_XOPEN_SOURCE")
// The input header we would like to generate builder for.
.header("build/wrapper.h")
// generate comments, also from headers and not just doc comments (///)
.generate_comments(true)
.clang_arg("-fretain-comments-from-system-headers")
.clang_arg("-fparse-all-comments")
// Remove warnings about improper_ctypes
.blacklist_function("strtold")
.blacklist_function("wcstold")
.blacklist_function("socketpair")
// only import functions from notcurses public API
.blacklist_function("[^ns].*")
.blacklist_function("n[^co].*")
.blacklist_function("s[^i].*") // allow sig*
// clean more unneeded types
.blacklist_item("B[0-9]+")
.blacklist_item("_BITS.*")
.blacklist_item("_POSIX.*")
.blacklist_item("__[A-Z].*")
.blacklist_item("[ADHJ-MQ-Z].*")
.blacklist_item("IN.*")
.blacklist_item("IP[^R].*")
.blacklist_item("ip.*")
.blacklist_item("m.*")
.blacklist_item("PF.*")
.blacklist_item("MSG_.*")
.blacklist_item("N[^C].*")
.blacklist_type("_bindgen.*")
// https://github.com/dankamongmen/notcurses/pull/1937
// https://github.com/rust-lang/rust-bindgen/issues/1651
.layout_tests(false)
// Don't derive the Copy trait on types with destructors.
.no_copy("ncdirect")
.no_copy("ncdplot")
.no_copy("ncfdplane")
.no_copy("ncmenu")
.no_copy("ncmultiselector")
.no_copy("ncplane")
.no_copy("ncreader")
.no_copy("ncreel")
.no_copy("ncselector")
.no_copy("ncuplot")
.no_copy("ncvisual")
.no_copy("notcurses")
// try to derive more traits
.derive_default(true)
.derive_hash(true)
.derive_partialord(true)
.derive_ord(true)
.derive_partialeq(true)
.derive_eq(true)
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks));
for d in plib.include_paths {
builder = builder.clang_arg(format!("-I{}", d.to_string_lossy()));
}
// Finish the builder and generate the builder.
let bindings = builder
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}

@ -1,2 +0,0 @@
#include <notcurses/notcurses.h>
#include <notcurses/direct.h>

@ -1,22 +0,0 @@
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let dm = NcDirect::new()?;
let (t_rows, t_cols) = dm.dim_yx();
println!("Terminal rows={0}, cols={1}", t_rows, t_cols);
println!(
"Can display UTF-8: {0}
Can open images: {1}
Supports Pixels: {2:?}
Palette size: {3:?}
",
dm.canutf8(),
dm.canopen_images(),
dm.check_pixel_support(),
dm.palette_size(),
);
Ok(())
}

@ -1,61 +0,0 @@
//! Example 'direct-cursor'
//!
//! Explore cursor functions in direct mode
//!
use rand::{thread_rng, Rng};
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let mut rng = thread_rng();
let ncd = NcDirect::new()?;
let cols = ncd.dim_x();
let rows = ncd.dim_y();
println!("terminal size (rows, cols): {}, {}", rows, cols);
let mut channels =
NcChannels::combine(NcChannel::from_rgb(0xAA2244), NcChannel::from_rgb(0x112233));
ncd.putstr(channels, "The current coordinates are")?;
for _n in 0..40 {
ncd.flush()?;
sleep![0, 30];
channels.set_fg_rgb8(
rng.gen_range(0x66..=0xEE),
rng.gen_range(0x66..=0xEE),
rng.gen_range(0x66..=0xEE),
);
channels.set_bg_rgb8(
rng.gen_range(0..=0x9),
rng.gen_range(0..=0x9),
rng.gen_range(0..=0x9),
);
ncd.putstr(channels, ".")?;
}
let (cy, cx) = ncd.cursor_yx()?;
ncd.putstr(channels, &format!(" ({},{})\n", cy, cx))?;
sleep![1];
let sentence = vec![
"And", "now", "I", "will", "clear", "the", "screen", ".", ".", ".",
];
for word in sentence {
channels.set_fg_rgb(channels.fg_rgb().wrapping_sub(0x050505));
channels.set_bg_rgb(channels.bg_rgb().wrapping_add(0x090909));
ncd.putstr(channels, &format!["{} ", word])?;
ncd.flush()?;
sleep![0, 150];
}
sleep![0, 300];
channels.set_fg_rgb(0xFFFFFF);
channels.set_bg_default();
ncd.putstr(channels, "\nbye!\n\n")?;
ncd.flush()?;
sleep![0, 600];
ncd.clear()?;
Ok(())
}

@ -1,38 +0,0 @@
//! Example 'direct-image'
//!
//! Explore image rendering in direct mode
//!
//! NOTE: This example uses the C style with functions.
use core::ptr::{null, null_mut};
use libnotcurses_sys::*;
fn main() {
unsafe {
let ncd = ncdirect_init(null(), null_mut(), 0);
render_image(&mut *ncd, NCBLIT_1x1);
render_image(&mut *ncd, NCBLIT_2x1);
render_image(&mut *ncd, NCBLIT_BRAILLE);
ncdirect_stop(ncd);
}
}
fn render_image(ncd: &mut NcDirect, blit: NcBlitter) {
unsafe {
if ncdirect_render_image(
ncd,
cstring!["image-16x16.png"],
NCALIGN_CENTER,
blit,
NCSCALE_NONE,
) != 0
{
panic!(
"ERROR: ncdirect_render_image(). Make sure you \
are running this example from the examples folder"
);
}
}
}

@ -1,28 +0,0 @@
//! Example 'direct-image'
//!
//! Explore image rendering in direct mode
//!
//! NOTE: This example uses the Rust style with methods.
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let mut dm = NcDirect::new()?;
render_image(&mut dm, NCBLIT_1x1)?;
render_image(&mut dm, NCBLIT_2x1)?;
render_image(&mut dm, NCBLIT_BRAILLE)?;
Ok(())
}
fn render_image(dm: &mut NcDirect, blit: NcBlitter) -> NcResult<()> {
if let Err(nc_error) = dm.render_image("image-16x16.png", NCALIGN_CENTER, blit, NCSCALE_NONE) {
return Err(NcError::with_msg(
nc_error.int,
"ERROR: dmirect_render_image(). Make sure you \
are running this example from the examples folder",
));
}
Ok(())
}

@ -1,43 +0,0 @@
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let nc = Nc::without_altscreen()?;
let (t_rows, t_cols) = nc.term_dim_yx();
println!("Terminal rows={0}, cols={1}", t_rows, t_cols);
println!(
"Can display UTF-8: {0}
Can display braille characters: {1}
Can display sextant characters: {2}
Can display quadrant characters: {3}
Can display half block characters: {4}
Can open images: {5}
Can open videos: {6}
Supports Pixels: {7:?}
Supports True Color: {8}
Supports fading: {9}
Supports changing the palette: {10}
Palette size: {11:?}
",
nc.canutf8(),
nc.canbraille(),
nc.cansextant(),
nc.canquadrant(),
nc.canhalfblock(),
nc.canopen_images(),
nc.canopen_videos(),
nc.check_pixel_support(),
nc.cantruecolor(),
nc.canfade(),
nc.canchangecolor(),
nc.palette_size(),
);
let pixelgeom = nc.stdplane().pixelgeom();
println!("{:#?}", pixelgeom);
nc.render()?;
nc.stop()?;
Ok(())
}

@ -1,37 +0,0 @@
//! Input
//!
//! https://github.com/dankamongmen/notcurses/blob/master/USAGE.md#input
//!
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let mut nc = Nc::with_flags(
NCOPTION_SUPPRESS_BANNERS | NCOPTION_NO_WINCH_SIGHANDLER | NCOPTION_NO_QUIT_SIGHANDLERS,
)?;
println!("Exit with F1\n");
let mut input = NcInput::new_empty();
loop {
let key = notcurses_getc_nblock(&mut nc, &mut input);
if key as i32 != -1 {
println!("'{0}' ({1:x})\n{2:?}", key, key as u32, input);
}
nrs![&mut nc, 0, 10];
match key {
NCKEY_F01 => break,
_ => (),
}
}
println!("\nExiting...");
nrs![&mut nc, 1];
nc.stop()?;
Ok(())
}

@ -1,64 +0,0 @@
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let mut nc = Nc::new()?;
// get the terminal size in character rows & columns
let (t_rows, t_cols) = nc.term_dim_yx();
// the standard plane has the same size
let mut stdplane = nc.stdplane();
assert_eq![(t_rows, t_cols), stdplane.dim_yx()];
// set the standard plane's base cell's foreground and background colors
let channels = NcChannels::from_rgb(0x88aa00, 0x222288);
stdplane.set_base("x", 0, channels)?;
nrs![&mut nc, 0, 500];
// add a green plane to the stdplane's pile
let plane_green = NcPlane::new_bound(&mut stdplane, 0, 0, 16, 30)?;
plane_green.set_base("·", 0, NcChannels::from_rgb(0x224411, 0x229922))?;
nrs![&mut nc, 0, 800];
// add a smaller red plane, a bit displaced to the bottom right
let plane_red = NcPlane::new_bound(&mut stdplane, 8, 12, 10, 20)?;
plane_red.set_base("~", 0, NcChannels::from_rgb(0xaadd2b, 0x882222))?;
nrs![&mut nc, 0, 800];
// write something
plane_green.putstr("PLANE 11111")?;
plane_red.putstr("PLANE 22222")?;
nrs![&mut nc, 0, 800];
// move the green plane down
for _ in 0..16 {
plane_green.move_rel(1, 1)?;
nrs![&mut nc, 0, 30];
}
// and up
for _ in 0..20 {
plane_green.move_rel(-1, -1)?;
nrs![&mut nc, 0, 35];
}
// move the red plane right
for _ in 0..26 {
plane_red.move_rel(0, 1)?;
nrs![&mut nc, 0, 40];
}
sleep![1];
// resize the red plane
plane_red.resize_simple(14, 24)?;
nrs![&mut nc, 0, 300];
plane_red.move_rel(-2, -2)?;
nrs![&mut nc, 0, 300];
plane_red.resize_simple(8, 16)?;
// TODO…
nrs![&mut nc, 3];
nc.stop()?;
Ok(())
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 435 B

@ -1,48 +0,0 @@
//! https://github.com/dankamongmen/notcurses/issues/1832
use libnotcurses_sys::*;
const W: u32 = 32;
const H: u32 = 32;
fn main() -> NcResult<()> {
let mut nc = Nc::new()?;
// create a white rectangle visual for the background
let buffer1 = vec![255; H as usize * W as usize * 3];
let mut bg_plane = NcPlane::new(&mut nc, 0, 0, H, W)?;
let v = NcVisual::from_rgb_packed(buffer1.as_slice(), H, W * 3, W, 255)?;
let vo = NcVisualOptions::with_plane(
&mut bg_plane,
NCSCALE_NONE,
0,
0,
0,
0,
0,
0,
NCBLIT_PIXEL,
0,
0,
);
// create a blue plane for the foreground
let fg_plane = NcPlane::new_bound(&mut bg_plane, 1, 1, 2, 16)?;
fg_plane.set_base(" ", 0, NcChannels::from_rgb(0x88aa00, 0x222288))?;
let mut counter = 0;
for _ in 0..3 {
let _ = fg_plane.putstr_yx(0, 0, &format!["counter: {}", &counter]);
counter += 1;
v.render(nc, &vo)?;
bg_plane.render()?;
bg_plane.rasterize()?;
sleep![1];
}
v.destroy();
bg_plane.destroy()?;
nc.stop()?;
Ok(())
}

@ -1,107 +0,0 @@
//! pixel-cell example
//!
//! Shows how to get the size of a cell in pixels
//!
//! It works on the following terminals:
//! - kitty
//! - xterm (invoked with `xterm -ti vt340`)
//! - alacritty (WIP: https://github.com/ayosec/alacritty/tree/graphics)
use rand::{distributions::Uniform, Rng};
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let mut nc = Nc::new()?;
if nc.check_pixel_support() == NCPIXEL_NONE {
nc.stop()?;
return Err(NcError::new_msg("Current terminal doesn't support pixels."));
}
let mut stdplane = nc.stdplane();
let pg = stdplane.pixelgeom();
// print visual delimiters around our pixelized cell
println!("0▗│▖\n│─ ─\n2▝│▘");
println!("a cell is {}x{} pixels", pg.cell_y, pg.cell_x);
println!("\ninterpolated not-interpolated not-interpolated interpolated");
println!(" SCALE SCALE RESIZE RESIZE");
// fill the buffer with random color pixels
let mut rng = rand::thread_rng();
let range = Uniform::from(50..=180);
let mut buffer = Vec::<u8>::with_capacity((pg.cell_y * pg.cell_x * 4) as usize);
#[allow(unused_parens)]
for _byte in (0..={ pg.cell_y * pg.cell_x }) {
buffer.push(rng.sample(&range));
buffer.push(rng.sample(&range));
buffer.push(rng.sample(&range));
buffer.push(255);
}
// show the newly created ncvisual delimited with the box drawing characters
let v1 = NcVisual::from_rgba(buffer.as_slice(), pg.cell_y, pg.cell_x * 4, pg.cell_x)?;
let voptions =
NcVisualOptions::without_plane(1, 2, 0, 0, pg.cell_y, pg.cell_x, NCBLIT_PIXEL, 0, 0);
v1.render(&mut nc, &voptions)?;
nrs![&mut nc, 1];
// show the ncvisual, scaled with interpolated values
let mut vplane2 = NcPlane::new_bound(&mut stdplane, 7, 4, 5, 4)?;
let voptions2 = NcVisualOptions::with_plane(
&mut vplane2,
NCSCALE_SCALE,
0,
0,
0,
0,
pg.cell_y,
pg.cell_x,
NCBLIT_PIXEL,
0,
0,
);
v1.render(&mut nc, &voptions2)?;
nrs![&mut nc, 0, 250];
// show the ncvisual, scaled without using interpolation
let mut vplane3 = NcPlane::new_bound(&mut stdplane, 7, 19, 5, 4)?;
let voptions3 = NcVisualOptions::with_plane(
&mut vplane3,
NCSCALE_SCALE,
0,
0,
0,
0,
pg.cell_y,
pg.cell_x,
NCBLIT_PIXEL,
NCVISUAL_OPTION_NOINTERPOLATE,
0,
);
v1.render(&mut nc, &voptions3)?;
nrs![&mut nc, 0, 250];
// resize the ncvisual (doesn't use interpolation)
let voptions4 =
NcVisualOptions::without_plane(7, 39, 0, 0, pg.cell_y, pg.cell_x, NCBLIT_PIXEL, 0, 0);
v1.resize_noninterpolative(pg.cell_y * 4, pg.cell_x * 4)?;
v1.render(&mut nc, &voptions4)?;
nrs![&mut nc, 0, 250];
// resize the ncvisual (uses interpolation)
let v5 = NcVisual::from_rgba(buffer.as_slice(), pg.cell_y, pg.cell_x * 4, pg.cell_x)?;
let voptions5 =
NcVisualOptions::without_plane(7, 56, 0, 0, pg.cell_y, pg.cell_x, NCBLIT_PIXEL, 0, 0);
v5.resize(pg.cell_y * 4, pg.cell_x * 4)?;
v5.render(&mut nc, &voptions5)?;
nrs![&mut nc, 0, 250];
sleep![2];
v1.destroy();
v5.destroy();
nc.stop()?;
Ok(())
}

@ -1,25 +0,0 @@
//! based on the proof of concept at ../../src/poc/cjkscroll.c
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let mut nc = Nc::new()?;
let plane = nc.stdplane();
plane.set_scrolling(true);
let mut wc = '\u{4e00}'; // 一
loop {
plane.putchar(wc)?;
wc = core::char::from_u32(wc as u32 + 1).expect("invalid char");
// 龣
if wc == '\u{9fa5}' {
wc = '\u{4e00}';
}
nrs![&mut nc, 0, 0, 30];
}
// nc.stop()?;
}

@ -1,62 +0,0 @@
//! based on the proof of concept at ../../src/poc/direct.c
use core::convert::TryInto;
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let dm = NcDirect::new()?;
let dimy = dm.dim_y() as i32;
let dimx = dm.dim_x() as i32;
for _ in 0..dimy {
for _ in 0..dimx {
printf!("X");
}
}
dm.flush()?;
dm.set_fg_rgb(0xff8080)?;
printf!(" erp erp \n");
dm.set_fg_rgb(0x80ff80)?;
printf!(" erp erp \n");
dm.set_fg_rgb(0xff8080)?;
printf!(" erp erp \n");
dm.cursor_right(dimx / 2)?;
dm.cursor_up(dimy / 2)?;
printf!(" erperperp! \n");
let (mut y, x);
if let Ok((_y, _x)) = dm.cursor_yx() {
y = _y;
x = _x;
printf!("\n\tRead cursor position: y: %d x: %d\n", y, x);
y += 2;
while y > 3 {
let up = if y >= 3 { 3 } else { y };
dm.cursor_up(up.try_into().unwrap_or(0))?;
dm.flush()?;
y -= up;
let newy;
if let Ok((_y, _)) = dm.cursor_yx() {
newy = _y;
} else {
break;
}
if newy != y {
eprintln!("Expected {}, got {}", y, newy);
break;
}
printf!("\n\tRead cursor position: y: %d x: %d\n", newy, x);
y += 2;
}
} else {
return Err(NcError::with_msg(-10, "Couldn't read cursor position."));
}
dm.stop()?;
Ok(())
}

@ -1,24 +0,0 @@
//! based on the proof of concept at ../../src/poc/kittyzapper.c
use libnotcurses_sys::*;
fn main() -> NcResult<()> {
let dm = NcDirect::new()?;
dm.set_fg_rgb8(100, 100, 100)?;
dm.set_bg_rgb8(0xff, 0xff, 0xff)?;
printf!("a");
dm.set_bg_rgb8(0, 0, 0)?;
printf!("b");
printf!(" ");
printf!(" ");
dm.set_bg_rgb8(0, 0, 1)?;
printf!("c");
printf!(" ");
printf!(" ");
dm.set_bg_rgb8(0xff, 0xff, 0xff)?;
printf!("d");
printf!("\n");
Ok(())
}

@ -1,137 +0,0 @@
//! based on the proof of concept at ../../src/poc/menu.c
// FIXME: has bugs, doesn't work well
// probably related to the arrays or the strings...
use libnotcurses_sys::*;
use widgets::*;
fn main() -> NcResult<()> {
let mut nc = Nc::new()?;
nc.mouse_enable()?;
let mut demo_items = [
NcMenuItem::new("Restart", NcInput::with_ctrl('r')),
NcMenuItem::new("Disabled", NcInput::with_ctrl('d')),
];
let mut file_items = [
NcMenuItem::new("New", NcInput::with_ctrl('n')),
NcMenuItem::new("Open", NcInput::with_ctrl('o')),
NcMenuItem::new("Close", NcInput::with_ctrl('c')),
NcMenuItem::new_empty(),
NcMenuItem::new("Quit", NcInput::with_ctrl('q')),
];
let mut help_items = [NcMenuItem::new("About", NcInput::with_ctrl('a'))];
let mut sections = [
NcMenuSection::new("Schwarzgerät", &mut demo_items, NcInput::with_alt('ä')),
NcMenuSection::new("File", &mut file_items, NcInput::with_alt('f')),
NcMenuSection::new_separator(),
// DEBUG: remove alt modifier for now.
NcMenuSection::new("Help", &mut help_items, NcInput::new('h')),
];
let mut mopts = NcMenuOptions::new(&mut sections);
mopts.header_channels_mut().set_fg_rgb(0x00ff00);
mopts.header_channels_mut().set_bg_rgb(0x440000);
mopts.section_channels_mut().set_fg_rgb(0xb0d700);
mopts.section_channels_mut().set_bg_rgb(0x002000);
let stdplane = nc.stdplane();
let (dim_y, _dim_x) = stdplane.dim_yx();
let menu_top = NcMenu::new(stdplane, mopts)?;
menu_top.item_set_status("Schwarzgerät", "Disabled", false)?;
menu_top.item_set_status("Schwarzgerät", "Restart", false)?;
stdplane.set_base("x", 0, NcChannels::from_rgb(0x88aa00, 0x000088))?;
nc.render()?;
stdplane.set_fg_rgb(0x00dddd);
stdplane.putstr_aligned(
dim_y - 1,
NCALIGN_RIGHT,
" -=+ menu poc. press q to exit +=-",
)?;
run_menu(&mut nc, menu_top)?;
stdplane.erase(); // is this needed?
// BUG FIXME: this doesn't show over the menu (at row 0)
stdplane.putstr_aligned(0, NCALIGN_RIGHT, " -=+ menu poc. press q to exit +=-")?;
stdplane.putstr_aligned(1, NCALIGN_CENTER, " -=+ menu poc. press q to exit +=-")?;
stdplane.putstr_aligned(2, NCALIGN_LEFT, " -=+ menu poc. press q to exit +=-")?;
mopts.flags |= NCMENU_OPTION_BOTTOM;
let menu_bottom = NcMenu::new(stdplane, mopts)?;
run_menu(&mut nc, menu_bottom)?;
Ok(())
}
fn run_menu(nc: &mut Nc, menu: &mut NcMenu) -> NcResult<()> {
// yellow rectangle
let planeopts = NcPlaneOptions::new_aligned(10, NCALIGN_CENTER, 3, 40);
let stdplane = nc.stdplane();
let selplane = NcPlane::with_options_bound(stdplane, planeopts)?;
selplane.set_fg_rgb(0);
selplane.set_bg_rgb(0xdddddd);
let mut channels = 0;
channels.set_fg_rgb(0x000088);
channels.set_bg_rgb(0x88aa00);
selplane.set_base(" ", 0, channels)?;
let mut ni = NcInput::new_empty();
let mut keypress: char;
nc.render()?;
loop {
stdplane.erase();
selplane.erase();
keypress = nc.getc_blocking(Some(&mut ni))?;
// DEBUG
stdplane.putstr_yx(2, 0, &format!["{:?}", ni])?;
nc.render()?;
// BUG FIXME: always returns false:
if !menu.offer_input(ni) {
match keypress {
'q' => {
menu.destroy()?;
selplane.destroy()?;
nc.stop()?;
return Ok(());
}
NCKEY_ENTER => {
if let Some(selection) = menu.selected(Some(&mut ni)) {
match selection.as_ref() {
"Quit" => {
menu.destroy()?;
selplane.destroy()?;
nc.stop()?;
return Ok(());
}
_ => (),
}
}
}
_ => (),
}
}
let mut selni = NcInput::new_empty();
if let Some(selitem) = menu.selected(Some(&mut selni)) {
selplane.putstr_aligned(1, NCALIGN_CENTER, &selitem)?;
} else {
// DEBUG
selplane.putstr_aligned(1, NCALIGN_CENTER, "nothing opened")?;
}
nc.render()?;
}
}

@ -1,850 +0,0 @@
//! A selection of the [ffi] bindings intended to be used directly.
//!
//! The full list of bindings is under the [ffi] submodule.
//!
//! The current module publicly re-exports bindgen generated structs, functions,
//! and constants, for their direct usage.
// BUG ISSUES:
// https://github.com/rust-lang/rust-bindgen/issues/1470
#[allow(clippy::all)]
// https://github.com/rust-lang/rust-bindgen/issues/1651
#[allow(unknown_lints, deref_nullptr)]
pub mod ffi {
//! Rust FFI bindings, automatically generated with bindgen.
//!
//! Almost all of the notcurses API functions are reexported to the public
//! API, while structs, enums and constants are type aliased or wrapped up.
//!
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
// Miscellaneous ---------------------------------------------------------------
#[rustfmt::skip]
#[doc(inline)]
pub use ffi::{
// functions
ncstrwidth,
};
// blitset ---------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// blitset,
// cell ------------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// cell,
//
// // constants
// NCALPHA_BLEND,
// NCALPHA_HIGHCONTRAST,
// NCALPHA_OPAQUE,
// NCALPHA_TRANSPARENT,
// NC_BGDEFAULT_MASK,
// NC_BG_ALPHA_MASK,
// NC_BG_PALETTE,
// NC_BG_RGB_MASK,
// NC_FGDEFAULT_MASK,
// NC_FG_ALPHA_MASK,
// NC_FG_PALETTE,
// NC_FG_RGB_MASK,
#[doc(inline)]
pub use ffi::{
// functions
nccell_duplicate,
nccell_extended_gcluster,
nccell_load,
nccell_release,
nccells_double_box,
nccells_rounded_box,
};
// channel ---------------------------------------------------------------------
//
// already wrapped:
//
// // constants
// CHANNEL_ALPHA_MASK,
// ncalign ---------------------------------------------------------------------
//
// already wrapped:
//
// // type definitions
// ncalign_e,
//
// // constants
// ncalign_e_NCALIGN_CENTER,
// ncalign_e_NCALIGN_LEFT,
// ncalign_e_NCALIGN_RIGHT,
// ncalign_e_NCALIGN_UNALIGNED,
// ncblitter -------------------------------------------------------------------
//
// already wrapped:
//
// // type definitions
// ncblitter_e,
//
// // constants
// ncblitter_e_NCBLIT_1x1,
// ncblitter_e_NCBLIT_2x1,
// ncblitter_e_NCBLIT_2x2,
// ncblitter_e_NCBLIT_3x2,
// ncblitter_e_NCBLIT_4x1,
// ncblitter_e_NCBLIT_8x1,
// ncblitter_e_NCBLIT_BRAILLE,
// ncblitter_e_NCBLIT_DEFAULT,
// ncblitter_e_NCBLIT_PIXEL,
#[doc(inline)]
pub use ffi::{
ncblit_bgrx,
ncblit_rgb_loose,
ncblit_rgb_packed,
// functions
ncblit_rgba,
};
// ncbox -----------------------------------------------------------------------
// // constants
// NCBOXCORNER_MASK,
// NCBOXCORNER_SHIFT,
// NCBOXGRAD_BOTTOM,
// NCBOXGRAD_LEFT,
// NCBOXGRAD_RIGHT,
// NCBOXGRAD_TOP,
// NCBOXMASK_BOTTOM,
// NCBOXMASK_LEFT,
// NCBOXMASK_RIGHT,
// NCBOXMASK_TOP,
// nccapabilit* ----------------------------------------------------------------
//
// already wrapped:
//
// // structs
// nccapabilities,
//
// // functions
// nccapability_canchangecolor,
// ncdirect --------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncdirect,
//
// // functions
// ncdirect_canbraille,
// ncdirect_canopen_videos
// ncdirect_canchangecolor,
// ncdirect_canfade,
// ncdirect_canhalfblock,
// ncdirect_canquadrant,
// ncdirect_cantruecolor,
// ncdirect_capabilities,
// ncdirect_hline_interp,
// ncdirect_vline_interp,
//
// // constants
// NCDIRECT_OPTION_INHIBIT_CBREAK,
// NCDIRECT_OPTION_INHIBIT_SETLOCALE,
// NCDIRECT_OPTION_NO_QUIT_SIGHANDLERS,
// NCDIRECT_OPTION_VERBOSE
// NCDIRECT_OPTION_VERY_VERBOSE
#[doc(inline)]
pub use ffi::{
// functions
ncdirect_box,
ncdirect_canget_cursor,
ncdirect_canopen_images,
ncdirect_canutf8,
ncdirect_check_pixel_support,
ncdirect_clear,
ncdirect_core_init,
ncdirect_cursor_disable,
ncdirect_cursor_down,
ncdirect_cursor_enable,
ncdirect_cursor_left,
ncdirect_cursor_move_yx,
ncdirect_cursor_pop,
ncdirect_cursor_push,
ncdirect_cursor_right,
ncdirect_cursor_up,
ncdirect_cursor_yx,
ncdirect_detected_terminal,
ncdirect_dim_x,
ncdirect_dim_y,
ncdirect_double_box,
ncdirect_flush,
ncdirect_get,
ncdirect_init,
ncdirect_inputready_fd,
ncdirect_off_styles,
ncdirect_on_styles,
ncdirect_palette_size,
//W ncdirect_printf_aligned,
ncdirect_putstr,
ncdirect_raster_frame,
ncdirect_readline,
ncdirect_render_frame,
ncdirect_render_image,
ncdirect_rounded_box,
ncdirect_set_bg_default,
ncdirect_set_bg_palindex,
ncdirect_set_bg_rgb,
ncdirect_set_fg_default,
ncdirect_set_fg_palindex,
ncdirect_set_fg_rgb,
ncdirect_set_styles,
ncdirect_stop,
ncdirect_stream,
ncdirect_styles,
ncdirect_supported_styles,
};
// ncdirectf --------------------------------------------------------------------
//
// already wrapped:
//
// // type alias
// ncdirectf,
//
#[doc(inline)]
pub use ffi::{
ncdirectf_free,
// functions
ncdirectf_from_file,
ncdirectf_geom,
ncdirectf_render,
};
// ncfadectx -------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncfadectx,
#[doc(inline)]
pub use ffi::{
// functions
ncfadectx_free,
ncfadectx_iterations,
ncfadectx_setup,
};
// ncinput ---------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncinput,
// ncloglevel ------------------------------------------------------------------
//
// already wrapped:
//
// // type definitions
// ncloglevel_e,
//
// // constants
// ncloglevel_e_NCLOGLEVEL_DEBUG,
// ncloglevel_e_NCLOGLEVEL_ERROR,
// ncloglevel_e_NCLOGLEVEL_FATAL,
// ncloglevel_e_NCLOGLEVEL_INFO,
// ncloglevel_e_NCLOGLEVEL_PANIC,
// ncloglevel_e_NCLOGLEVEL_SILENT,
// ncloglevel_e_NCLOGLEVEL_TRACE,
// ncloglevel_e_NCLOGLEVEL_VERBOSE,
// ncloglevel_e_NCLOGLEVEL_WARNING,
// ncfdplane -------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncfdplane,
// ncfdplane_options,
#[doc(inline)]
pub use ffi::{
// functions
ncfdplane_create,
ncfdplane_destroy,
ncfdplane_plane,
};
// ncmenu ----------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncmenu,
// ncmenu_item,
// ncmenu_options,
// ncmenu_section,
//
// // constants
// NCMENU_OPTION_BOTTOM,
// NCMENU_OPTION_HIDING,
#[doc(inline)]
pub use ffi::{
// functions
ncmenu_create,
ncmenu_destroy,
ncmenu_item_set_status,
ncmenu_mouse_selected,
ncmenu_nextitem,
ncmenu_nextsection,
ncmenu_offer_input,
ncmenu_plane,
ncmenu_previtem,
ncmenu_prevsection,
ncmenu_rollup,
ncmenu_selected,
ncmenu_unroll,
};
// ncmetric --------------------------------------------------------------------
//
// already wrapped:
//
// // functions
// ncmetric
//
// // constants
// PREFIXCOLUMNS,
// PREFIXSTRLEN,
// BPREFIXCOLUMNS,
// BPREFIXSTRLEN,
// IPREFIXCOLUMNS,
// IPREFIXSTRLEN,
// ncmultiselector -------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncmultiselector,
// ncmselector_item,
// ncmultiselector_options,
#[doc(inline)]
pub use ffi::{
// functions
ncmultiselector_create,
ncmultiselector_destroy,
ncmultiselector_offer_input,
ncmultiselector_plane,
ncmultiselector_selected,
};
// ncpile ----------------------------------------------------------------------
#[doc(inline)]
pub use ffi::{
// functions
ncpile_bottom,
ncpile_create,
ncpile_rasterize,
ncpile_render,
ncpile_top,
};
// ncplane ---------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncplane,
// ncplane_options,
//
// // functions
// ncplane_channels,
// ncplane_gradient,
// ncplane_set_bchannel,
// ncplane_set_fchannel,
// ncplane_set_channels,
//
// // constants
// NCPLANE_OPTION_HORALIGNED,
// NCPLANE_OPTION_MARGINALIZED,
// NCPLANE_OPTION_VERALIGNED,
//
// // type alias
// ncdirectv,
#[doc(inline)]
pub use ffi::{
// functions
ncplane_above,
ncplane_abs_x,
ncplane_abs_y,
ncplane_abs_yx,
ncplane_as_rgba,
ncplane_at_cursor,
ncplane_at_cursor_cell,
ncplane_at_yx,
ncplane_at_yx_cell,
ncplane_base,
ncplane_below,
ncplane_box,
ncplane_center_abs,
ncplane_contents,
ncplane_create,
ncplane_cursor_move_yx,
ncplane_cursor_yx,
ncplane_destroy,
ncplane_dim_yx,
ncplane_dup,
ncplane_erase,
ncplane_erase_region,
ncplane_fadein,
ncplane_fadein_iteration,
ncplane_fadeout,
ncplane_fadeout_iteration,
ncplane_format,
ncplane_greyscale,
ncplane_highgradient,
ncplane_highgradient_sized,
ncplane_hline_interp,
ncplane_home,
ncplane_mergedown,
ncplane_mergedown_simple,
ncplane_move_above,
ncplane_move_below,
ncplane_move_bottom,
ncplane_move_top,
ncplane_move_yx,
ncplane_notcurses,
ncplane_notcurses_const,
ncplane_off_styles,
ncplane_on_styles,
ncplane_parent,
ncplane_parent_const,
ncplane_pixelgeom,
ncplane_polyfill_yx,
ncplane_pulse,
ncplane_putc_yx,
ncplane_putchar_stained,
ncplane_putegc_stained,
ncplane_putegc_yx,
ncplane_putnstr_aligned,
ncplane_putnstr_yx,
ncplane_putstr_aligned,
ncplane_putstr_stained,
ncplane_putstr_yx,
ncplane_puttext,
ncplane_putwegc_stained,
ncplane_putwstr_stained,
ncplane_qrcode,
ncplane_reparent,
ncplane_reparent_family,
ncplane_resize,
ncplane_resize_marginalized,
ncplane_resize_maximize,
ncplane_resize_realign,
ncplane_resizecb,
ncplane_rotate_ccw,
ncplane_rotate_cw,
ncplane_scrolling_p,
ncplane_set_base,
ncplane_set_base_cell,
ncplane_set_bg_alpha,
ncplane_set_bg_default,
ncplane_set_bg_palindex,
ncplane_set_bg_rgb,
ncplane_set_bg_rgb8,
ncplane_set_bg_rgb8_clipped,
ncplane_set_fg_alpha,
ncplane_set_fg_default,
ncplane_set_fg_palindex,
ncplane_set_fg_rgb,
ncplane_set_fg_rgb8,
ncplane_set_fg_rgb8_clipped,
ncplane_set_resizecb,
ncplane_set_scrolling,
ncplane_set_styles,
ncplane_set_userptr,
ncplane_stain,
ncplane_styles,
ncplane_styles_off,
ncplane_styles_on,
ncplane_styles_set,
ncplane_translate,
ncplane_translate_abs,
ncplane_userptr,
ncplane_vline_interp,
ncplane_vprintf_aligned,
ncplane_vprintf_stained,
ncplane_vprintf_yx,
ncplane_x,
ncplane_y,
ncplane_yx,
};
// ncplot ----------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncdplot, // f64
// ncuplot, // u64
// ncplot_options,
//
// // constants
// NCPLOT_OPTION_DETECTMAXONLY,
// NCPLOT_OPTION_EXPONENTIALD,
// NCPLOT_OPTION_LABELTICKSD,
// NCPLOT_OPTION_NODEGRADE,
// NCPLOT_OPTION_VERTICALI,
#[doc(inline)]
pub use ffi::{
// functions
ncdplot_add_sample,
ncdplot_create,
ncdplot_destroy,
ncdplot_plane,
ncdplot_sample,
ncdplot_set_sample,
ncuplot_add_sample,
ncuplot_create,
ncuplot_destroy,
ncuplot_plane,
ncuplot_sample,
ncuplot_set_sample,
};
// ncreader --------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncreader,
// ncreader_options,
//
// // constants
// NCREADER_OPTION_CURSOR,
// NCREADER_OPTION_HORSCROLL,
// NCREADER_OPTION_NOCMDKEYS,
// NCREADER_OPTION_VERSCROLL,
#[doc(inline)]
pub use ffi::{
// functions
ncreader_clear,
ncreader_contents,
ncreader_create,
ncreader_destroy,
ncreader_move_down,
ncreader_move_left,
ncreader_move_right,
ncreader_move_up,
ncreader_offer_input,
ncreader_plane,
ncreader_write_egc,
};
// ncprogbar -------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncprogbar,
// ncprogbar_options,
//
// // constants
// NCPROGBAR_OPTION_RETROGRADE,
#[doc(inline)]
pub use ffi::{
// functions
ncprogbar_create,
ncprogbar_destroy,
ncprogbar_plane,
ncprogbar_progress,
ncprogbar_set_progress,
};
// ncreel ----------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncreel,
// ncreel_options,
//
// // constants
// NCREEL_OPTION_CIRCULAR,
// NCREEL_OPTION_INFINITESCROLL,
#[doc(inline)]
pub use ffi::{
// functions
ncreel_add,
ncreel_create,
ncreel_del,
ncreel_destroy,
ncreel_focused,
ncreel_next,
ncreel_offer_input,
ncreel_plane,
ncreel_prev,
ncreel_redraw,
ncreel_tabletcount,
};
// ncscale ---------------------------------------------------------------------
//
// already wrapped:
//
// // type definitions
// ncscale_e,
//
// // constants
// ncscale_e_NCSCALE_NONE,
// ncscale_e_NCSCALE_SCALE,
// ncscale_e_NCSCALE_STRETCH,
// ncscale_e_NCSCALE_NONE_HIRES,
// ncscale_e_NCSCALE_SCALE_HIRES,
// ncselector ------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncselector,
// ncselector_item,
// ncselector_options,
#[doc(inline)]
pub use ffi::{
// functions
ncselector_additem,
ncselector_create,
ncselector_delitem,
ncselector_destroy,
ncselector_nextitem,
ncselector_offer_input,
ncselector_plane,
ncselector_previtem,
ncselector_selected,
};
// ncstats ---------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncstats,
// ncstyle ---------------------------------------------------------------------
//
// already wrapped:
//
// // constants
// NCSTYLE_MASK,
// NCSTYLE_ITALIC,
// NCSTYLE_UNDERLINE,
// NCSTYLE_UNDERCURL,
// NCSTYLE_BOLD,
// NCSTYLE_STRUCK,
// NCSTYLE_NONE,
// nctablet --------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// nctablet,
#[doc(inline)]
pub use ffi::{
// functions
nctablet_plane,
nctablet_userptr,
};
// nctree ----------------------------------------------------------------------
//
// // structs
// nctree,
// nctree_item,
// nctree_options,
//
#[doc(inline)]
pub use ffi::{
// functions
nctree_create,
nctree_destroy,
nctree_focused,
nctree_goto,
nctree_next,
nctree_offer_input,
nctree_plane,
nctree_prev,
nctree_redraw,
};
// ncvgeom ---------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncvgeom
// ncvisual --------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncvisual,
// ncvisual_options,
//
// // constants
// NCVISUAL_OPTION_ADDALPHA,
// NCVISUAL_OPTION_BLEND,
// NCVISUAL_OPTION_CHILDPLANE
// NCVISUAL_OPTION_HORALIGNED
// NCVISUAL_OPTION_NODEGRADE,
// NCVISUAL_OPTION_NOINTERPOLATE
// NCVISUAL_OPTION_VERALIGNED,
#[doc(inline)]
pub use ffi::{
// functions
ncvisual_at_yx,
ncvisual_blitter_geom,
ncvisual_decode,
ncvisual_decode_loop,
ncvisual_destroy,
ncvisual_from_bgra,
ncvisual_from_file,
ncvisual_from_plane,
ncvisual_from_rgb_loose,
ncvisual_from_rgb_packed,
ncvisual_from_rgba,
ncvisual_media_defblitter,
ncvisual_polyfill_yx,
ncvisual_render,
ncvisual_resize,
ncvisual_resize_noninterpolative,
ncvisual_rotate,
ncvisual_set_yx,
ncvisual_simple_streamer,
ncvisual_stream,
ncvisual_subtitle,
};
// notcurses -------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// notcurses,
// notcurses_options,
//
// // constants
// NCOPTION_INHIBIT_SETLOCALE,
// NCOPTION_NO_ALTERNATE_SCREEN,
// NCOPTION_NO_CLEAR_BITMAPS
// NCOPTION_NO_FONT_CHANGES,
// NCOPTION_NO_QUIT_SIGHANDLERS,
// NCOPTION_NO_WINCH_SIGHANDLER,
// NCOPTION_PRESERVE_CURSOR,
// NCOPTION_SUPPRESS_BANNERS,
#[doc(inline)]
pub use ffi::{
// functions
notcurses_at_yx,
notcurses_bottom,
notcurses_canbraille,
notcurses_canchangecolor,
notcurses_canfade,
notcurses_canhalfblock,
notcurses_canopen_images,
notcurses_canopen_videos,
notcurses_canquadrant,
notcurses_cansextant,
notcurses_cantruecolor,
notcurses_canutf8,
notcurses_check_pixel_support,
notcurses_core_init,
notcurses_cursor_disable,
notcurses_cursor_enable,
notcurses_cursor_yx,
notcurses_debug,
notcurses_detected_terminal,
notcurses_drop_planes,
notcurses_get,
notcurses_init,
notcurses_inputready_fd,
notcurses_lex_blitter,
notcurses_lex_margins,
notcurses_lex_scalemode,
notcurses_linesigs_disable,
notcurses_linesigs_enable,
notcurses_mouse_disable,
notcurses_mouse_enable,
notcurses_palette_size,
notcurses_refresh,
notcurses_render,
notcurses_render_to_buffer,
notcurses_render_to_file,
notcurses_stats,
notcurses_stats_alloc,
notcurses_stats_reset,
notcurses_stdplane,
notcurses_stdplane_const,
notcurses_stop,
notcurses_str_blitter,
notcurses_str_scalemode,
notcurses_supported_styles,
notcurses_top,
notcurses_ucs32_to_utf8,
notcurses_version,
notcurses_version_components,
};
// palette ---------------------------------------------------------------------
//
// already wrapped:
//
// // structs
// ncpalette,
#[doc(inline)]
pub use ffi::{
// functions
ncpalette_free,
ncpalette_new,
ncpalette_use,
// constants
NCPALETTESIZE,
};
// fade callback ---------------------------------------------------------------
//
// already wrapped:
//
// // types
// fadecb,

@ -1,75 +0,0 @@
//! `NcBoxMask`
/// Controls the drawing of borders, gradients and corners.
///
/// NcBoxMax is defined in the least significant byte, where bits [3, 0] are
/// are a border mask, and bits [7, 4] are a gradient mask.
///
/// The drawing of the corners is defined in the second byte,
/// see [`NCBOXCORNER_MASK`].
///
/// ## Diagram
///
/// ```txt
/// NCBOXMASK_TOP 0x0001 0b00000001
/// NCBOXMASK_RIGHT 0x0002 0b00000010
/// NCBOXMASK_BOTTOM 0x0004 0b00000100
/// NCBOXMASK_LEFT 0x0008 0b00001000
///
/// NCBOXGRAD_TOP 0x0010 0b00010000
/// NCBOXGRAD_RIGHT 0x0020 0b00100000
/// NCBOXGRAD_BOTTOM 0x0040 0b01000000
/// NCBOXGRAD_LEFT 0x0080 0b10000000
///
/// NCBOXCORNER_MASK 0x0300 0b00000111_00000000
///
/// NCBOXCORNER_SHIFT 8
/// ```
///
/// ## Bit masks
///
/// - [NCBOXMASK_TOP]
/// - [NCBOXMASK_RIGHT]
/// - [NCBOXMASK_BOTTOM]
/// - [NCBOXMASK_LEFT]
///
/// - [NCBOXGRAD_TOP]
/// - [NCBOXGRAD_RIGHT]
/// - [NCBOXGRAD_BOTTOM]
/// - [NCBOXGRAD_LEFT]
///
/// - [NCBOXCORNER_MASK]
/// - [NCBOXCORNER_SHIFT]
///
pub type NcBoxMask = u32;
/// [NcBoxMask] top gradient mask.
pub const NCBOXGRAD_TOP: NcBoxMask = crate::bindings::ffi::NCBOXGRAD_TOP;
/// [NcBoxMask] right gradient mask.
pub const NCBOXGRAD_RIGHT: NcBoxMask = crate::bindings::ffi::NCBOXGRAD_RIGHT;
/// [NcBoxMask] bottom gradient mask.
pub const NCBOXGRAD_BOTTOM: NcBoxMask = crate::bindings::ffi::NCBOXGRAD_BOTTOM;
/// [NcBoxMask] left gradient mask.
pub const NCBOXGRAD_LEFT: NcBoxMask = crate::bindings::ffi::NCBOXGRAD_LEFT;
/// [NcBoxMask] top border mask.
pub const NCBOXMASK_TOP: NcBoxMask = crate::bindings::ffi::NCBOXMASK_TOP;
/// [NcBoxMask] right border mask.
pub const NCBOXMASK_RIGHT: NcBoxMask = crate::bindings::ffi::NCBOXMASK_RIGHT;
/// [NcBoxMask] bottom border mask.
pub const NCBOXMASK_BOTTOM: NcBoxMask = crate::bindings::ffi::NCBOXMASK_BOTTOM;
/// [NcBoxMask] left border mask.
pub const NCBOXMASK_LEFT: NcBoxMask = crate::bindings::ffi::NCBOXMASK_LEFT;
/// [NcBoxMask] corner mask to control the drawing of boxes corners.
///
/// By default, vertexes are drawn whether their connecting edges are drawn
/// or not. The value of the bits control this, and are interpreted as the
/// number of connecting edges necessary to draw a given corner.
///
/// At 0 (the default), corners are always drawn. At 3, corners are never drawn
/// (since at most 2 edges can touch a box's corner).
pub const NCBOXCORNER_MASK: NcBoxMask = crate::bindings::ffi::NCBOXCORNER_MASK;
/// The number of bits [NCBOXCORNER_MASK] is shifted in [NcBoxMask].
pub const NCBOXCORNER_SHIFT: NcBoxMask = crate::bindings::ffi::NCBOXCORNER_SHIFT;

@ -1,26 +0,0 @@
//! `NcCapabilities`
use crate::NcPalette;
use core::mem::size_of;
/// Capabilities, derived from terminfo, environment variables, and queries.
pub type NcCapabilities = crate::bindings::ffi::nccapabilities;
/// Can we set the "hardware" palette?
///
/// Requires the "ccc" terminfo capability, and that the number of colors
/// supported is at least the size of our `NcPalette` structure.
#[inline]
pub fn nccapability_canchangecolor(caps: &NcCapabilities) -> bool {
if !caps.can_change_colors {
return false;
}
// CHECK this does the same as:
// if(caps.colors < sizeof(p->chans) / sizeof(*p->chans)){
//
if (caps.colors as usize) < size_of::<NcPalette>() / size_of::<u32>() {
return false;
}
true
}

@ -1,471 +0,0 @@
//! `NcCell` methods and associated functions.
use crate::{
cstring, error, nccell_load, NcAlphaBits, NcCell, NcChannels, NcComponent, NcEgcBackstop,
NcPaletteIndex, NcPlane, NcResult, NcRgb, NcStyle, NCRESULT_ERR,
};
#[allow(unused_imports)] // for the doc comments
use crate::NcChannel;
/// # NcCell constructors
impl NcCell {
/// New `NcCell`, expects a 7-bit [`char`].
#[inline]
#[allow(clippy::unnecessary_cast)]
pub const fn from_char7b(ch: char) -> Self {
NcCell {
gcluster: (ch as u32).to_le(),
gcluster_backstop: 0 as NcEgcBackstop,
width: 0_u8,
stylemask: 0 as NcStyle,
channels: 0 as NcChannels,
}
}
/// New `NcCell`, expects an [`NcPlane`] and a [`char`].
#[inline]
pub fn from_char(ch: char, plane: &mut NcPlane) -> Self {
let mut cell = Self::new();
let result = unsafe { nccell_load(plane, &mut cell, cstring![ch.to_string()]) };
// TEMP solution for:
// https://github.com/dankamongmen/notcurses/pull/1937/checks?check_run_id=3093152924#step:11:339
#[cfg(not(target_os = "macos"))]
debug_assert_ne![NCRESULT_ERR, result];
cell
}
/// New `NcCell`, expects an [`NcPlane`] and a &[`str`].
#[inline]
pub fn from_str(plane: &mut NcPlane, string: &str) -> Self {
let mut cell = Self::new();
let result = unsafe { nccell_load(plane, &mut cell, cstring![string]) };
debug_assert_ne![NCRESULT_ERR, result];
cell
}
/// New empty `NcCell`.
#[inline]
pub const fn new() -> Self {
Self::from_char7b(0 as char)
}
/// Breaks the UTF-8 string in `egc` down, setting up this `NcCell`,
/// and returns the number of bytes copied out of `egc`.
///
/// The styling of the cell is left untouched, but any resources are released.
/// *C style function: [nccell_load()][crate::nccell_load].*
pub fn load(plane: &mut NcPlane, cell: &mut NcCell, egc: &str) -> NcResult<u32> {
let bytes = unsafe { crate::nccell_load(plane, cell, cstring![egc]) };
error![
bytes,
&format!["NcCell.load(NcPlane, NcCell, {:?})", egc],
bytes as u32
]
}
/// Same as [load][NcCell#method.load], plus blasts the styling with
/// `style` and `channels`.
///
/// - Breaks the UTF-8 string in `gcluster` down, setting up this NcCell.
/// - Returns the number of bytes copied out of `gcluster`.
/// - Any resources are released.
/// - Blasts the styling with `style` and `channels`.
///
/// *C style function: [nccell_prime()][crate::nccell_prime].*
pub fn prime(
plane: &mut NcPlane,
cell: &mut NcCell,
gcluster: &str,
style: NcStyle,
channels: NcChannels,
) -> NcResult<u32> {
let bytes = crate::nccell_prime(plane, cell, gcluster, style, channels);
error![bytes, "", bytes as u32]
}
/// Duplicate this `NcCell` into another one.
///
/// Both must be or will be bound to `common_plane`.
///
/// *C style function: [nccell_duplicate()][crate::nccell_duplicate].*
pub fn duplicate(&self, target: &mut NcCell, common_plane: &mut NcPlane) -> NcResult<()> {
error![unsafe { crate::nccell_duplicate(common_plane, target, self) }]
}
/// Initializes (zeroes out) this `NcCell`.
///
/// *C style function: [nccell_init()][crate::nccell_init].*
#[inline]
pub fn init(&mut self) {
crate::nccell_init(self);
}
/// Releases resources held by the current cell in the [NcPlane] `plane`.
///
/// *C style function: [nccell_release()][crate::nccell_release].*
pub fn release(&mut self, plane: &mut NcPlane) {
unsafe {
crate::nccell_release(plane, self);
}
}
}
// -----------------------------------------------------------------------------
/// ## NcCell methods: bg|fg `NcChannel`s manipulation.
impl NcCell {
/// Returns the [`NcChannels`] of this `NcCell`.
///
/// *(No equivalent C style function)*
pub fn channels(&mut self, plane: &mut NcPlane) -> NcChannels {
let (mut _styles, mut channels) = (0, 0);
let _char = crate::nccell_extract(plane, self, &mut _styles, &mut channels);
channels
}
/// Extracts the background [`NcAlphaBits`] (shifted to LSBs).
///
/// *C style function: [nccell_bg_alpha()][crate::nccell_bg_alpha].*
pub fn bg_alpha(&self) -> NcAlphaBits {
crate::nccell_bg_alpha(self)
}
/// Is the background [`NcChannel`] using the "default background color"?
///
/// *C style function: [nccell_bg_default_p()][crate::nccell_bg_default_p].*
pub fn bg_default_p(&self) -> bool {
crate::nccell_bg_default_p(self)
}
/// Gets the [`NcPaletteIndex`] of the background [`NcChannel`].
///
/// *C style function: [nccell_bg_palindex()][crate::nccell_bg_palindex].*
pub fn bg_palindex(&self) -> NcPaletteIndex {
crate::nccell_bg_palindex(self)
}
/// Is the background [`NcChannel`] using an [`NcPaletteIndex`] indexed
/// [`NcPalette`][crate::NcPalette] color?
///
/// *C style function: [nccell_bg_palindex_p()][crate::nccell_bg_palindex_p].*
pub fn bg_palindex_p(&self) -> bool {
crate::nccell_bg_palindex_p(self)
}
/// Gets the background [`NcRgb`] (shifted to LSBs).
///
/// *C style function: [nccell_bg_rgb()][crate::nccell_bg_rgb].*
pub fn bg_rgb(&self) -> NcRgb {
crate::nccell_bg_rgb(self)
}
/// Gets the background RGB [`NcComponent`]s.
///
/// *C style function: [nccell_bg_rgb8()][crate::nccell_bg_rgb8].*
pub fn bg_rgb8(&self) -> (NcComponent, NcComponent, NcComponent) {
let (mut r, mut g, mut b) = (0, 0, 0);
crate::nccell_bg_rgb8(self, &mut r, &mut g, &mut b);
(r, g, b)
}
/// Extracts the foreground [`NcAlphaBits`] (shifted to LSBs).
///
/// *C style function: [nccell_fg_alpha()][crate::nccell_fg_alpha].*
pub fn fg_alpha(&self) -> NcAlphaBits {
crate::nccell_fg_alpha(self)
}
/// Is the foreground [`NcChannel`] using the "default foreground color"?
///
/// *C style function: [nccell_fg_default_p()][crate::nccell_fg_default_p].*
pub fn fg_default_p(&self) -> bool {
crate::nccell_fg_default_p(self)
}
/// Gets the [`NcPaletteIndex`] of the foreground [`NcChannel`].
///
/// *C style function: [nccell_fg_palindex()][crate::nccell_fg_palindex].*
pub fn fg_palindex(&self) -> NcPaletteIndex {
crate::nccell_fg_palindex(self)
}
/// Is the foreground [`NcChannel`] using an [`NcPaletteIndex`] indexed
/// [`NcPalette`][crate::NcPalette] color?
///
/// *C style function: [nccell_fg_palindex_p()][crate::nccell_fg_palindex_p].*
pub fn fg_palindex_p(&self) -> bool {
crate::nccell_fg_palindex_p(self)
}
/// Gets the foreground [`NcRgb`] (shifted to LSBs).
///
/// *C style function: [nccell_fg_rgb()][crate::nccell_fg_rgb].*
pub fn fg_rgb(&self) -> NcRgb {
crate::nccell_fg_rgb(self)
}
/// Gets the foreground RGB [`NcComponent`]s.
///
/// *C style function: [nccell_fg_rgb8()][crate::nccell_fg_rgb8].*
pub fn fg_rgb8(&self) -> (NcComponent, NcComponent, NcComponent) {
let (mut r, mut g, mut b) = (0, 0, 0);
crate::nccell_fg_rgb8(self, &mut r, &mut g, &mut b);
(r, g, b)
}
/// Sets the background [`NcAlphaBits`].
///
/// *C style function: [nccell_set_bg_alpha()][crate::nccell_set_bg_alpha].*
pub fn set_bg_alpha(&mut self, alpha: NcAlphaBits) {
crate::nccell_set_bg_alpha(self, alpha);
}
/// Indicates to use the "default color" for the background [`NcChannel`].
///
/// *C style function: [nccell_set_bg_default()][crate::nccell_set_bg_default].*
pub fn set_bg_default(&mut self) {
crate::nccell_set_bg_default(self);
}
/// Sets the background [`NcPaletteIndex`].
///
/// Also sets [NCALPHA_BG_PALETTE][crate::NCALPHA_BG_PALETTE] and
/// [NCALPHA_OPAQUE][crate::NCALPHA_OPAQUE], and clears out
/// [NCALPHA_BGDEFAULT_MASK][crate::NCALPHA_BGDEFAULT_MASK].
///
/// *C style function: [nccell_set_bg_palindex()][crate::nccell_set_bg_palindex].*
pub fn set_bg_palindex(&mut self, index: NcPaletteIndex) {
crate::nccell_set_bg_palindex(self, index);
}
/// Sets the background [`NcRgb`] and marks it as not using the default color.
///
/// *C style function: [nccell_set_bg_rgb()][crate::nccell_set_bg_rgb].*
pub fn set_bg_rgb(&mut self, rgb: NcRgb) {
crate::nccell_set_bg_rgb(self, rgb);
}
/// Sets the background RGB [`NcComponent`]s, and marks it as not using
/// the "default color".
///
/// *C style function: [nccell_set_bg_rgb8()][crate::nccell_set_bg_rgb8].*
pub fn set_bg_rgb8(&mut self, red: NcComponent, green: NcComponent, blue: NcComponent) {
crate::nccell_set_bg_rgb8(self, red, green, blue);
}
/// Sets the foreground [`NcAlphaBits`].
///
/// *C style function: [nccell_set_fg_alpha()][crate::nccell_set_fg_alpha].*
pub fn set_fg_alpha(&mut self, alpha: NcAlphaBits) {
crate::nccell_set_fg_alpha(self, alpha);
}
/// Indicates to use the "default color" for the foreground [`NcChannel`].
///
/// *C style function: [nccell_set_fg_default()][crate::nccell_set_fg_default].*
pub fn set_fg_default(&mut self) {
crate::nccell_set_fg_default(self);
}
/// Sets the foreground [`NcPaletteIndex`].
///
/// Also sets [NCALPHA_FG_PALETTE][crate::NCALPHA_FG_PALETTE] and
/// [NCALPHA_OPAQUE][crate::NCALPHA_OPAQUE], and clears out
/// [NCALPHA_BGDEFAULT_MASK][crate::NCALPHA_BGDEFAULT_MASK].
///
/// *C style function: [nccell_set_fg_palindex()][crate::nccell_set_fg_palindex].*
pub fn set_fg_palindex(&mut self, index: NcPaletteIndex) {
crate::nccell_set_fg_palindex(self, index);
}
/// Sets the foreground [`NcRgb`] and marks it as not using the default color.
///
/// *C style function: [nccell_set_fg_rgb()][crate::nccell_set_fg_rgb].*
pub fn set_fg_rgb(&mut self, rgb: NcRgb) {
crate::nccell_set_fg_rgb(self, rgb);
}
/// Sets the foreground RGB [`NcComponent`]s, and marks it as not using
/// the "default color".
///
/// *C style function: [nccell_set_fg_rgb8()][crate::nccell_set_fg_rgb8].*
pub fn set_fg_rgb8(&mut self, red: NcComponent, green: NcComponent, blue: NcComponent) {
crate::nccell_set_fg_rgb8(self, red, green, blue);
}
}
/// # `NcCell` methods: other components
impl NcCell {
/// Returns true if the two cells have distinct `EGC`s, attributes,
/// or [`NcChannel`]s.
///
/// The actual egcpool index needn't be the same--indeed, the planes
/// needn't even be the same. Only the expanded `EGC` must be bit-equal.
///
/// *C style function: [nccellcmp()][crate::nccellcmp].*
pub fn compare(plane1: &NcPlane, cell1: &NcCell, plane2: &NcPlane, cell2: &NcCell) -> bool {
crate::nccellcmp(plane1, cell1, plane2, cell2)
}
/// Saves the [`NcStyle`] and the [`NcChannels`], and returns the `EGC`.
/// (These are the three elements of an `NcCell`).
///
/// *C style function: [nccell_fg_alpha()][crate::nccell_fg_alpha].*
pub fn extract(
&mut self,
plane: &mut NcPlane,
styles: &mut NcStyle,
channels: &mut NcChannels,
) -> String {
crate::nccell_extract(plane, self, styles, channels)
}
/// Returns the `EGC` of the `NcCell`.
///
/// See also: [extended_gcluster][NcCell#method.extended_gcluster] method.
///
/// *(No equivalent C style function)*
pub fn egc(&mut self, plane: &mut NcPlane) -> String {
let (mut _styles, mut _channels) = (0, 0);
crate::nccell_extract(plane, self, &mut _styles, &mut _channels)
}
/// Returns the [`NcStyle`] bits.
///
/// *C style function: [nccell_styles()][crate::nccell_styles].*
pub fn styles(&mut self) -> NcStyle {
crate::nccell_styles(self)
}
/// Removes the specified [`NcStyle`] bits.
///
/// *C style function: [nccell_off_styles()][crate::nccell_off_styles].*
pub fn styles_off(&mut self, stylebits: NcStyle) {
crate::nccell_off_styles(self, stylebits)
}
/// Adds the specified [`NcStyle`] bits.
///
/// *C style function: [nccell_on_styles()][crate::nccell_on_styles].*
pub fn styles_on(&mut self, stylebits: NcStyle) {
crate::nccell_on_styles(self, stylebits)
}
/// Sets just the specified [`NcStyle`] bits.
///
/// *C style function: [nccell_set_styles()][crate::nccell_set_styles].*
pub fn styles_set(&mut self, stylebits: NcStyle) {
crate::nccell_set_styles(self, stylebits)
}
}
/// # `NcCell` methods: text
impl NcCell {
// /// Returns a pointer to the `EGC` of this NcCell in the [NcPlane] `plane`.
// ///
// /// This pointer can be invalidated by any further operation on the referred
// /// plane, so… watch out!
// ///
// /// *C style function: [nccell_extended_gcluster()][crate::nccell_wide_left_p].*
// pub fn extended_gcluster(&self, plane: &NcPlane) -> u32 {
// let egcpointer = unsafe { crate::nccell_extended_gcluster(plane, self) };
// egcpointer
// }
/// Copies the UTF8-encoded `EGC` out of this NcCell,
/// whether simple or complex.
///
/// The result is not tied to the [NcPlane],
/// and persists across erases and destruction.
///
/// *C style function: [nccell_strdup()][crate::nccell_strdup].*
pub fn strdup(&self, plane: &NcPlane) -> String {
crate::nccell_strdup(plane, self)
}
/// Does this NcCell contain a wide codepoint?
///
/// *C style function: [nccell_double_wide_p()][crate::nccell_double_wide_p].*
pub fn double_wide_p(&self) -> bool {
crate::nccell_double_wide_p(self)
}
/// Is this the left half of a wide character?
///
/// *C style function: [nccell_wide_left_p()][crate::nccell_wide_left_p].*
pub fn wide_left_p(&self) -> bool {
crate::nccell_wide_right_p(self)
}
/// Is this the right side of a wide character?
///
/// *C style function: [nccell_wide_right_p()][crate::nccell_wide_right_p].*
pub fn wide_right_p(&self) -> bool {
crate::nccell_wide_right_p(self)
}
}
/// # `NcCell` methods: boxes
impl NcCell {
/// Loads up six cells with the `EGC`s necessary to draw a box.
///
/// On error, any [`NcCell`]s this function might have loaded before the error
/// are [release][NcCell#method.release]d.
/// There must be at least six `EGC`s in `gcluster`.
///
/// *C style function: [nccells_load_box()][crate::nccells_load_box].*
pub fn load_box(
plane: &mut NcPlane,
style: NcStyle,
channels: NcChannels,
ul: &mut NcCell,
ur: &mut NcCell,
ll: &mut NcCell,
lr: &mut NcCell,
hl: &mut NcCell,
vl: &mut NcCell,
gcluster: &str,
) -> NcResult<()> {
error![crate::nccells_load_box(
plane, style, channels, ul, ur, ll, lr, hl, vl, gcluster
)]
}
/// NcCell.[load_box()][NcCell#method.box] with the double box-drawing characters.
///
/// *C style function: [nccells_double_box()][crate::nccells_double_box].*
pub fn double_box(
plane: &mut NcPlane,
style: NcStyle,
channels: NcChannels,
ul: &mut NcCell,
ur: &mut NcCell,
ll: &mut NcCell,
lr: &mut NcCell,
hl: &mut NcCell,
vl: &mut NcCell,
) -> NcResult<()> {
error![unsafe {
crate::nccells_double_box(plane, style as u32, channels, ul, ur, ll, lr, hl, vl)
}]
}
/// NcCell.[load_box()][NcCell#method.box] with the rounded box-drawing characters.
///
/// *C style function: [nccells_rounded_box()][crate::nccells_double_box].*
pub fn rounded_box(
plane: &mut NcPlane,
style: NcStyle,
channels: NcChannels,
ul: &mut NcCell,
ur: &mut NcCell,
ll: &mut NcCell,
lr: &mut NcCell,
hl: &mut NcCell,
vl: &mut NcCell,
) -> NcResult<()> {
error![unsafe {
crate::nccells_rounded_box(plane, style as u32, channels, ul, ur, ll, lr, hl, vl)
}]
}
}

@ -1,362 +0,0 @@
//! `NcCell`
// functions already exported by bindgen : 7
// -----------------------------------------
// (W) wrap: 4
// (#) test: 0
// ------------------------------------------
//… nccell_extended_gcluster
//… nccell_load
//W nccells_double_box
//W nccells_rounded_box
//W nccell_duplicate
//W nccell_release
//
// functions manually reimplemented: 46
// ------------------------------------------
// (X) wont: 2
// (+) done: 38
// (W) wrap: 40
// (#) test: 26
// ------------------------------------------
//W# nccell_bg_alpha
//W# nccell_bg_default_p
//W# nccell_bg_palindex
//W# nccell_bg_palindex_p
//W# nccell_bg_rgb
//W# nccell_bg_rgb8
// + nccell_cols
//W+ nccell_double_wide_p
//W+ nccell_extract
//W# nccell_fchannel
//W# nccell_fg_alpha
//W# nccell_fg_default_p
//W# nccell_fg_palindex
//W# nccell_fg_palindex_p
//W# nccell_fg_rgb
//W# nccell_fg_rgb8
//W+ nccell_init
//…… nccell_load_char
// nccell_load_egc32
//W+ nccell_off_styles
//W+ nccell_on_styles
//W+ nccell_prime
//W# nccell_set_bchannel
//W# nccell_set_bg_alpha
//W# nccell_set_bg_default
//W# nccell_set_bg_palindex
//W# nccell_set_bg_rgb
//W# nccell_set_bg_rgb8
// X nccell_set_bg_rgb8_clipped // unneeded
//W# nccell_set_fchannel
//W# nccell_set_fg_alpha
//W# nccell_set_fg_default
//W# nccell_set_fg_palindex
//W# nccell_set_fg_rgb
//W# nccell_set_fg_rgb8
// X nccell_set_fg_rgb8_clipped // unneeded
//W+ nccell_set_styles
//W+ nccell_strdup
//W+ nccell_styles
//W+ nccell_wide_left_p
//W+ nccell_wide_right_p
//W+ nccellcmp
// nccells_ascii_box
// nccells_heavy_box
// nccells_light_box
//W+ nccells_load_box
#[cfg(test)]
mod test;
mod methods;
mod reimplemented;
pub use reimplemented::*;
#[allow(unused_imports)] // TEMP
use crate::{NcChannel, NcPlane};
// NcCell
/// A coordinate on an [`NcPlane`][crate::NcPlane] storing 128 bits of data.
///
/// # Methods & Associated Functions
///
/// - [Constructors & Destructors](#nccell-constructors-and-destructors)
///
/// - [bg|fg `NcChannel`s manipulation](#nccell-methods-bgfg-ncchannels-manipulation)
/// - [Other components](#nccell-methods-other-components)
/// - [Text](#nccell-methods-text)
///
/// # Description
///
/// An `NcCell` corresponds to a single character cell on some `NcPlane`,
/// which can be occupied by a single `EGC` grapheme cluster (some root
/// spacing glyph, along with possible combining characters, which might span
/// multiple columns).
///
/// An NcCell is bounded to an `NcPlane`, but the cell doesn't store anything
/// about the plane.
///
/// At any `NcCell`, we can have a theoretically arbitrarily long UTF-8 string,
/// a foreground color, a background color, and an [`NcStyle`] attribute set.
///
/// Valid grapheme cluster contents include:
///
/// - A NUL terminator,
/// - A single [control character](https://en.wikipedia.org/wiki/Control_character),
/// followed by a NUL terminator,
/// - At most one [spacing
/// character](https://en.wikipedia.org/wiki/Graphic_character#Spacing_character),
/// followed by zero or more nonspacing characters, followed by a NUL terminator.
///
/// ## Diagram
///
/// ```txt
/// NcCell: 128 bits structure comprised of the following 5 elements:
///
/// GCLUSTER|GCLUSTER|GCLUSTER|GCLUSTER 1. `EGC`
/// 00000000║WWWWWWWW║11111111|11111111 2. NcEgcBackstop + 3. width + 4. NcStyle
/// ~~AA~~~~|RRRRRRRR|GGGGGGGG|BBBBBBBB 5. NcChannels
/// ~~AA~~~~|RRRRRRRR|GGGGGGGG|BBBBBBBB "
///
/// 1. (32b) Extended Grapheme Cluster, presented either as:
///
/// 1.1. An EGC of up to 4 bytes:
/// UUUUUUUU|UUUUUUUU|UUUUUUUU|UUUUUUUU
///
/// 1.2. A `0x01` in the first byte, plus 3 bytes with a 24b address to an egcpool:
/// 00000001|IIIIIIII|IIIIIIII|IIIIIIII
///
/// 2. (8b) Backstop (zero)
/// 00000000
///
/// 3. (8b) column width
/// WWWWWWWW
///
/// 4. (16b) NcStyle
/// 11111111 11111111
///
/// 5. (64b) NcChannels
/// ~~AA~~~~|RRRRRRRR|GGGGGGGG|BBBBBBBB║~~AA~~~~|RRRRRRRR|GGGGGGGG|BBBBBBBB
/// ```
///
/// `type in C: cell (struct)`
///
/// # More NcCell Information
///
/// ## Size
///
/// Multi-column characters can only have a single style/color throughout.
/// [`wcwidth()`](https://www.man7.org/linux/man-pages/man3/wcwidth.3.html)
/// is not reliable. It's just quoting whether or not the `EGC`
/// contains a "Wide Asian" double-width character.
/// This is set for some things, like most emoji, and not set for
/// other things, like cuneiform.
///
/// Each cell occupies 16 static bytes (128 bits). The surface is thus ~1.6MB
/// for a (pretty large) 500x200 terminal. At 80x43, it's less than 64KB.
/// Dynamic requirements (the egcpool) can add up to 16MB to an ncplane, but
/// such large pools are unlikely in common use.
///
/// ## Alpha Compositing
///
/// We implement some small alpha compositing. Foreground and background both
/// have two bits of inverted alpha. The actual grapheme written to a cell is
/// the topmost non-zero grapheme.
///
/// - If its alpha is 00 ([`NCALPHA_OPAQUE`][crate::NCALPHA_OPAQUE])
/// its foreground color is used unchanged.
///
/// - If its alpha is 10 ([`NCALPHA_TRANSPARENT`][crate::NCALPHA_TRANSPARENT])
/// its foreground color is derived
/// entirely from cells underneath it.
///
/// - If its alpha is 01 ([`NCALPHA_BLEND`][crate::NCALPHA_BLEND])
/// the result will be a composite.
///
/// Likewise for the background. If the bottom of a coordinate's zbuffer is
/// reached with a cumulative alpha of zero, the default is used. In this way,
/// a terminal configured with transparent background can be supported through
/// multiple occluding ncplanes.
///
/// A foreground alpha of 11
/// ([`NCALPHA_HIGHCONTRAST`][crate::NCALPHA_HIGHCONTRAST])
/// requests high-contrast text (relative to the computed background).
/// A background alpha of 11 is currently forbidden.
///
/// ## Precedence
///
/// - Default color takes precedence over palette or RGB, and cannot be used with
/// transparency.
/// - Indexed palette takes precedence over RGB. It cannot meaningfully set
/// transparency, but it can be mixed into a cascading color.
/// - RGB is used if neither default terminal colors nor palette indexing are in
/// play, and fully supports all transparency options.
///
/// ## Column width *(WIP)*
///
/// See [USAGE.md](https://github.com/dankamongmen/notcurses/blob/master/USAGE.md)
///
/// We store the column width in this field. for a multicolumn EGC of N
/// columns, there will be N nccells, and each has a width of N...for now.
/// eventually, such an EGC will set more than one subsequent cell to
/// WIDE_RIGHT, and this won't be necessary. it can then be used as a
/// bytecount. see #1203. FIXME iff width >= 2, the cell is part of a
/// multicolumn glyph. whether a cell is the left or right side of the glyph
/// can be determined by checking whether ->gcluster is zero.
///
pub type NcCell = crate::bindings::ffi::nccell;
// RETHINK:
//
// NcEgc
//
// /// Extended Grapheme Cluster. A unicode string of length 1.
// ///
// /// This 32 bit char, together with the associated plane's associated egcpool,
// /// completely define this cell's `NcEgc`. Unless the `NcEgc` requires more than
// /// four bytes to encode as UTF-8, it will be inlined here:
// ///
// /// ## Diagram 1
// ///
// /// ```txt
// /// UUUUUUUU UUUUUUUU UUUUUUUU UUUUUUUU
// /// extended grapheme cluster <= 4bytes
// /// ```
// ///
// /// `type in C: uint32_t`
// ///
// /// If more than four bytes are required, it will be spilled into the egcpool.
// /// In either case, there's a NUL-terminated string available without copying,
// /// because (1) the egcpool is all NUL-terminated sequences and (2) the fifth
// /// byte of this struct (the GClusterBackStop field, see below) is
// /// guaranteed to be zero, as are any unused bytes in gcluster.
// ///
// /// A spilled `NcEgc` is indicated by the value `0x01iiiiii`. This cannot alias a
// /// true supra-ASCII NcEgc, because UTF-8 only encodes bytes <= 0x80 when they
// /// are single-byte ASCII-derived values. The `iiiiii` is interpreted as a 24-bit
// /// index into the egcpool (which may thus be up to 16MB):
// ///
// /// ## Diagram 2
// ///
// /// ```txt
// /// 00000001 iiiiiiii iiiiiiii iiiiiiii
// /// sign 24bit index to egcpool
// /// ```
// /// `type in C: uint32_t`
// ///
// /// The cost of this scheme is that the character 0x01 (`SOH`) cannot be encoded
// /// in a cell, and therefore it must not be allowed through the API.
// ///
// /// -----
// /// Note that even if the `NcEgc` is <= 4 bytes and inlined, is still interpreted as
// /// a NUL-terminated char * (technically, &cell->gcluster is treated as a char*).
// /// If it is more than 4 bytes, cell->gcluster has a first byte of 0x01,
// /// and the remaining 24 bits are an index into the plane's egcpool,
// /// which is carved into NUL-terminated chunks of arbitrary length.
// ///
// /// ## Links
// ///
// /// - [Grapheme Cluster
// /// Boundaries](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries)
// ///
// ///
// FIXME: should be an utf-8 string len 1 of type &str.
// pub type NcEgc = String;
// pub type NcEgc<'a> = &'a str;
// NcEgcBackStop
/// An `u8` always at zero, part of the [`NcCell`] struct
///
/// ## Diagram
///
/// ```txt
/// 00000000
/// ```
///
/// `type in C: uint_8t`
///
pub type NcEgcBackstop = u8;
// NcStyle
///
/// An `u16` of `NCSTYLE_*` boolean styling attribute flags
///
/// ## Attributes
///
/// - [`NCSTYLE_MASK`]
/// - [`NCSTYLE_ITALIC`]
/// - [`NCSTYLE_UNDERLINE`]
/// - [`NCSTYLE_UNDERCURL`]
/// - [`NCSTYLE_STRUCK`]
/// - [`NCSTYLE_BOLD`]
/// - [`NCSTYLE_NONE`]
///
/// ## Diagram
///
/// ```txt
/// 11111111 11111111
/// ```
///
/// `type in C: uint16_t`
///
pub type NcStyle = u16;
///
pub const NCSTYLE_MASK: u16 = crate::bindings::ffi::NCSTYLE_MASK as u16;
///
pub const NCSTYLE_ITALIC: u16 = crate::bindings::ffi::NCSTYLE_ITALIC as u16;
///
pub const NCSTYLE_UNDERLINE: u16 = crate::bindings::ffi::NCSTYLE_UNDERLINE as u16;
///
pub const NCSTYLE_UNDERCURL: u16 = crate::bindings::ffi::NCSTYLE_UNDERCURL as u16;
///
pub const NCSTYLE_STRUCK: u16 = crate::bindings::ffi::NCSTYLE_STRUCK as u16;
///
pub const NCSTYLE_BOLD: u16 = crate::bindings::ffi::NCSTYLE_BOLD as u16;
///
pub const NCSTYLE_NONE: u16 = crate::bindings::ffi::NCSTYLE_NONE as u16;
/// Enables the [`NcStyle`] methods.
pub trait NcStyleMethods {
fn add(&mut self, other_style: NcStyle);
fn has(&self, other: NcStyle) -> bool;
fn to_vec(&self) -> Vec<NcStyle>;
}
impl NcStyleMethods for NcStyle {
/// Returns a `Vec` with all the styles contained in the current style.
fn to_vec(&self) -> Vec<NcStyle> {
let mut v = vec![];
let styles = [
NCSTYLE_ITALIC,
NCSTYLE_UNDERLINE,
NCSTYLE_UNDERCURL,
NCSTYLE_STRUCK,
NCSTYLE_BOLD,
NCSTYLE_NONE,
];
for s in &styles {
if self.has(*s) {
v.push(*s)
}
}
v
}
/// Returns true if the current style has included the `other_style`.
fn has(&self, other_style: NcStyle) -> bool {
(self & other_style) == other_style
}
/// Adds the `other_style` to the current style.
fn add(&mut self, other_style: NcStyle) {
*self |= other_style
}
}

@ -1,532 +0,0 @@
//! `cell*_*` reimplemented functions.
use libc::strcmp;
use crate::{
cstring, nccell_release, rstring, NcAlphaBits, NcCell, NcChannel, NcChannels, NcComponent,
NcIntResult, NcPaletteIndex, NcPlane, NcRgb, NcStyle, NCALPHA_BGDEFAULT_MASK,
NCALPHA_BG_PALETTE, NCALPHA_FGDEFAULT_MASK, NCALPHA_FG_PALETTE, NCALPHA_OPAQUE, NCRESULT_ERR,
NCRESULT_OK, NCSTYLE_MASK,
};
// Alpha -----------------------------------------------------------------------
/// Extracts the foreground [`NcAlphaBits`] from an [`NcCell`] (shifted to LSBs).
///
/// *Method: NcCell.[fg_alpha()][NcCell#method.fg_alpha].*
#[inline]
pub fn nccell_fg_alpha(cell: &NcCell) -> NcAlphaBits {
crate::ncchannels_fg_alpha(cell.channels)
}
/// Extracts the background [`NcAlphaBits`] from an [`NcCell`] (shifted to LSBs).
///
/// *Method: NcCell.[bg_alpha()][NcCell#method.bg_alpha].*
#[inline]
pub fn nccell_bg_alpha(cell: &NcCell) -> NcAlphaBits {
crate::ncchannels_bg_alpha(cell.channels)
}
/// Sets the foreground [`NcAlphaBits`] of an [`NcCell`].
///
/// *Method: NcCell.[set_fg_alpha()][NcCell#method.set_fg_alpha].*
#[inline]
pub fn nccell_set_fg_alpha(cell: &mut NcCell, alpha: NcAlphaBits) {
crate::ncchannels_set_fg_alpha(&mut cell.channels, alpha);
}
/// Sets the background [`NcAlphaBits`] of an [`NcCell`].
///
/// *Method: NcCell.[set_bg_alpha()][NcCell#method.set_bg_alpha].*
#[inline]
pub fn nccell_set_bg_alpha(cell: &mut NcCell, alpha: NcAlphaBits) {
crate::ncchannels_set_bg_alpha(&mut cell.channels, alpha);
}
// NcComponent ---------------------------------------------------------------------
/// Gets the foreground [`NcComponent`]s of an [`NcCell`],
/// and returns the [`NcChannel`] (which can have some extra bits set).
///
/// *Method: NcCell.[fg_rgb8()][NcCell#method.fg_rgb8].*
#[inline]
pub fn nccell_fg_rgb8(
cell: &NcCell,
red: &mut NcComponent,
green: &mut NcComponent,
blue: &mut NcComponent,
) -> NcChannel {
crate::ncchannels_fg_rgb8(cell.channels, red, green, blue)
}
/// Gets the background [`NcComponent`]s of an [`NcCell`],
/// and returns the [`NcChannel`] (which can have some extra bits set).
///
/// *Method: NcCell.[bg_rgb8()][NcCell#method.bg_rgb8].*
#[inline]
pub fn nccell_bg_rgb8(
cell: &NcCell,
red: &mut NcComponent,
green: &mut NcComponent,
blue: &mut NcComponent,
) -> NcChannel {
crate::ncchannels_bg_rgb8(cell.channels, red, green, blue)
}
/// Sets the foreground [`NcComponent`]s of the [`NcCell`],
/// and marks it as not using the "default color".
///
/// *Method: NcCell.[set_fg_rgb8()][NcCell#method.set_fg_rgb8].*
#[inline]
pub fn nccell_set_fg_rgb8(
cell: &mut NcCell,
red: NcComponent,
green: NcComponent,
blue: NcComponent,
) {
crate::ncchannels_set_fg_rgb8(&mut cell.channels, red, green, blue);
}
/// Sets the background [`NcComponent`]s of the [`NcCell`],
/// and marks it as not using the "default color".
///
/// *Method: NcCell.[set_bg_rgb8()][NcCell#method.set_bg_rgb8].*
#[inline]
pub fn nccell_set_bg_rgb8(
cell: &mut NcCell,
red: NcComponent,
green: NcComponent,
blue: NcComponent,
) {
crate::ncchannels_set_bg_rgb8(&mut cell.channels, red, green, blue);
}
// NcRgb -----------------------------------------------------------------------
/// Gets the foreground [`NcRgb`] from an [`NcCell`] (shifted to LSBs).
///
/// *Method: NcCell.[fg_rgb()][NcCell#method.fg_rgb].*
#[inline]
pub fn nccell_fg_rgb(cell: &NcCell) -> NcRgb {
crate::ncchannels_fg_rgb(cell.channels)
}
/// Gets the background [`NcRgb`] from an [`NcCell`] (shifted to LSBs).
///
/// *Method: NcCell.[bg_rgb()][NcCell#method.bg_rgb].*
#[inline]
pub fn nccell_bg_rgb(cell: &NcCell) -> NcRgb {
crate::ncchannels_bg_rgb(cell.channels)
}
/// Sets the foreground [`NcRgb`] of an [`NcCell`],
/// and marks it as not using the default color.
///
/// *Method: NcCell.[set_fg_rgb()][NcCell#method.set_fg_rgb].*
#[inline]
pub fn nccell_set_fg_rgb(cell: &mut NcCell, rgb: NcRgb) {
crate::ncchannels_set_fg_rgb(&mut cell.channels, rgb);
}
/// Sets the background [`NcRgb`] of an [`NcCell`],
/// and marks it as not using the default color.
///
/// *Method: NcCell.[set_bg_rgb()][NcCell#method.set_bg_rgb].*
#[inline]
pub fn nccell_set_bg_rgb(cell: &mut NcCell, rgb: NcRgb) {
crate::ncchannels_set_bg_rgb(&mut cell.channels, rgb);
}
// Default ---------------------------------------------------------------------
/// Indicates to use the "default color" for the foreground [`NcChannel`]
/// of an [`NcCell`].
///
/// *Method: NcCell.[set_fg_default()][NcCell#method.set_fg_default].*
#[inline]
pub fn nccell_set_fg_default(cell: &mut NcCell) {
crate::ncchannels_set_fg_default(&mut cell.channels);
}
/// Indicates to use the "default color" for the background [`NcChannel`]
/// of an [`NcCell`].
///
/// *Method: NcCell.[set_bg_default()][NcCell#method.set_bg_default].*
#[inline]
pub fn nccell_set_bg_default(cell: &mut NcCell) {
crate::ncchannels_set_bg_default(&mut cell.channels);
}
/// Is the foreground [`NcChannel`] of this [`NcCell`] using the
/// "default foreground color"?
///
/// *Method: NcCell.[fg_default_p()][NcCell#method.fg_default_p].*
#[inline]
pub fn nccell_fg_default_p(cell: &NcCell) -> bool {
crate::ncchannels_fg_default_p(cell.channels)
}
/// Is the background [`NcChannel`] of this [`NcCell`] using the
/// "default background color"?
///
/// The "default background color" must generally be used to take advantage of
/// terminal-effected transparency.
///
/// *Method: NcCell.[bg_default_p()][NcCell#method.bg_default_p].*
#[inline]
pub fn nccell_bg_default_p(cell: &NcCell) -> bool {
crate::ncchannels_bg_default_p(cell.channels)
}
// Palette ---------------------------------------------------------------------
/// Is the foreground [`NcChannel`] of this [`NcCell`] using an
/// [`NcPaletteIndex`] indexed [`NcPalette`][crate::NcPalette] color?
///
/// *Method: NcCell.[fg_palindex_p()][NcCell#method.fg_palindex_p].*
#[inline]
pub fn nccell_fg_palindex_p(cell: &NcCell) -> bool {
crate::ncchannels_fg_palindex_p(cell.channels)
}
/// Is the background [`NcChannel`] of this [`NcCell`] using an
/// [`NcPaletteIndex`] indexed [`NcPalette`][crate::NcPalette] color?
///
/// *Method: NcCell.[bg_palindex_p()][NcCell#method.bg_palindex_p].*
#[inline]
pub fn nccell_bg_palindex_p(cell: &NcCell) -> bool {
crate::ncchannels_bg_palindex_p(cell.channels)
}
/// Gets the [`NcPaletteIndex`] of the foreground [`NcChannel`] of the [`NcCell`].
///
/// *Method: NcCell.[fg_palindex()][NcCell#method.fg_palindex].*
#[inline]
#[allow(clippy::unnecessary_cast)]
pub const fn nccell_fg_palindex(cell: &NcCell) -> NcPaletteIndex {
((cell.channels & 0xff00000000 as NcChannels) >> 32) as NcPaletteIndex
}
/// Gets the [`NcPaletteIndex`] of the background [`NcChannel`] of the [`NcCell`].
///
/// *Method: NcCell.[bg_palindex()][NcCell#method.bg_palindex].*
#[inline]
#[allow(clippy::unnecessary_cast)]
pub const fn nccell_bg_palindex(cell: &NcCell) -> NcPaletteIndex {
(cell.channels & 0xff) as NcPaletteIndex
}
/// Sets an [`NcCell`]'s foreground [`NcPaletteIndex`].
///
/// Also sets [NCALPHA_FG_PALETTE] and [NCALPHA_OPAQUE],
/// and clears out [NCALPHA_FGDEFAULT_MASK].
///
/// *Method: NcCell.[set_fg_palindex()][NcCell#method.set_fg_palindex].*
//
// NOTE: unlike the original C function, this one can't fail
#[inline]
#[allow(clippy::unnecessary_cast)]
pub fn nccell_set_fg_palindex(cell: &mut NcCell, index: NcPaletteIndex) {
cell.channels |= NCALPHA_FGDEFAULT_MASK;
cell.channels |= NCALPHA_FG_PALETTE;
nccell_set_fg_alpha(cell, NCALPHA_OPAQUE);
cell.channels &= 0xff000000ffffffff as NcChannels;
cell.channels |= (index as NcChannels) << 32;
}
/// Sets an [`NcCell`]'s background [`NcPaletteIndex`].
///
/// Also sets [`NCALPHA_BG_PALETTE`] and [`NCALPHA_OPAQUE`],
/// and clears out [`NCALPHA_BGDEFAULT_MASK`].
///
/// *Method: NcCell.[set_bg_palindex()][NcCell#method.set_bg_palindex].*
//
// NOTE: unlike the original C function, this one can't fail
#[inline]
pub fn nccell_set_bg_palindex(cell: &mut NcCell, index: NcPaletteIndex) {
cell.channels |= NCALPHA_BGDEFAULT_MASK as NcChannels;
cell.channels |= NCALPHA_BG_PALETTE as NcChannels;
nccell_set_bg_alpha(cell, NCALPHA_OPAQUE);
cell.channels &= 0xffffffffff000000;
cell.channels |= index as NcChannels;
}
// Styles ----------------------------------------------------------------------
/// Extracts the [`NcStyle`] bits from an [`NcCell`].
///
/// *Method: NcCell.[cell_styles()][NcCell#method.cell_styles].*
#[inline]
pub const fn nccell_styles(cell: &NcCell) -> NcStyle {
cell.stylemask
}
/// Adds the specified [`NcStyle`] bits to an [`NcCell`]'s existing spec.,
/// whether they're actively supported or not.
///
/// *Method: NcCell.[styles_on()][NcCell#method.styles_on].*
#[inline]
pub fn nccell_on_styles(cell: &mut NcCell, stylebits: NcStyle) {
cell.stylemask |= stylebits & NCSTYLE_MASK as u16;
}
/// Removes the specified [`NcStyle`] bits from an [`NcCell`]'s existing spec.
///
/// *Method: NcCell.[styles_off()][NcCell#method.styles_off].*
#[inline]
pub fn nccell_off_styles(cell: &mut NcCell, stylebits: NcStyle) {
cell.stylemask &= !(stylebits & NCSTYLE_MASK as u16);
}
/// Sets *just* the specified [`NcStyle`] bits for an [`NcCell`],
/// whether they're actively supported or not.
///
/// *Method: NcCell.[styles_set()][NcCell#method.styles_set].*
#[inline]
pub fn nccell_set_styles(cell: &mut NcCell, stylebits: NcStyle) {
cell.stylemask = stylebits & NCSTYLE_MASK as u16;
}
// Chars -----------------------------------------------------------------------
/// Returns the number of columns occupied by 'c'. see ncstrwidth() for an
/// equivalent for multiple EGCs.
#[inline]
pub const fn nccell_cols(cell: &NcCell) -> u8 {
if cell.width != 0 {
cell.width
} else {
1
}
}
#[deprecated]
pub fn nccell_width(plane: &NcPlane, cell: &NcCell) -> NcIntResult {
unsafe { crate::ffi::nccell_width(plane, cell) }
}
/// Does the [`NcCell`] contain an East Asian Wide codepoint?
///
/// *Method: NcCell.[double_wide_p()][NcCell#method.double_wide_p].*
#[inline]
pub const fn nccell_double_wide_p(cell: &NcCell) -> bool {
cell.width > 0
}
/// Is this the right half of a wide character?
///
/// *Method: NcCell.[wide_right_p()][NcCell#method.wide_right_p].*
#[inline]
pub const fn nccell_wide_right_p(cell: &NcCell) -> bool {
nccell_double_wide_p(cell) && cell.gcluster == 0
}
/// Is this the left half of a wide character?
///
/// *Method: NcCell.[wide_left_p()][NcCell#method.wide_left_p].*
#[inline]
pub const fn nccell_wide_left_p(cell: &NcCell) -> bool {
nccell_double_wide_p(cell) && cell.gcluster != 0
}
// /// Loads a 7-bit `EGC` character into the [`NcCell`].
// ///
// /// *Method: NcCell.[load_char()][NcCell#method.load_char].*
// //
// // TODO:CHECK is this necessary at all?
// #[inline]
// pub fn nccell_load_char(plane: &mut NcPlane, cell: &mut NcCell, ch: char) /* -> i32 */
// {
// let _ = unsafe { crate::nccell_load(plane, cell, ch) };
// }
// nccell_load_char(struct ncplane* n, nccell* c, char ch){
// char gcluster[2];
// gcluster[0] = ch;
// gcluster[1] = '\0';
// let _ = nccell_load(n, c, gcluster);
// }
// /// Loads a UTF-8 grapheme cluster of up to 4 bytes into the cell `c`.
// ///
// /// *Method: NcCell.[load_egc32()][NcCell#method.load_egc32].*
// //
// // TODO
// #[inline]
// pub fn nccell_load_egc32(plane: &mut NcPlane, cell: &mut NcCell, egc: &str) -> NcIntResult {
// char gcluster[sizeof(egc) + 1];
// egc = egc.to_le();
// memcpy(gcluster, &egc, sizeof(egc));
// gcluster[4] = '\0';
// return nccell_load(n, c, gcluster);
// }
// // Load a UTF-8 encoded EGC of up to 4 bytes into the nccell 'c'. Returns the
// // number of bytes used, or -1 on error.
// static inline int
// nccell_load_egc32(struct ncplane* n, nccell* c, uint32_t egc){
// char gcluster[sizeof(egc) + 1];
// egc = htole(egc);
// memcpy(gcluster, &egc, sizeof(egc));
// gcluster[4] = '\0';
// return nccell_load(n, c, gcluster);
// }
/// Copies the UTF8-encoded `EGC` out of the [`NcCell`], whether simple or complex.
///
/// The result is not tied to the [NcPlane],
/// and persists across erases and destruction.
///
/// *Method: NcCell.[strdup()][NcCell#method.strdup].*
#[inline]
pub fn nccell_strdup(plane: &NcPlane, cell: &NcCell) -> String {
rstring![libc::strdup(crate::nccell_extended_gcluster(plane, cell))].into()
}
// Misc. -----------------------------------------------------------------------
/// Saves the [`NcStyle`] and the [`NcChannels`],
/// and returns the `EGC`, of an [`NcCell`].
///
/// *Method: NcCell.[extract()][NcCell#method.extract].*
#[inline]
pub fn nccell_extract(
plane: &NcPlane,
cell: &NcCell,
stylemask: &mut NcStyle,
channels: &mut NcChannels,
) -> String {
if *stylemask != 0 {
*stylemask = cell.stylemask;
}
if *channels != 0 {
*channels = cell.channels;
}
nccell_strdup(plane, cell)
}
/// Returns true if the two cells are distinct `EGC`s, attributes, or channels.
///
/// The actual egcpool index needn't be the same--indeed, the planes needn't even
/// be the same. Only the expanded EGC must be equal. The EGC must be bit-equal;
///
/// *Method: NcCell.[compare()][NcCell#method.compare].*
//
// NOTE: FIXME: it would probably be better to test whether they're Unicode-equal
#[inline]
pub fn nccellcmp(plane1: &NcPlane, cell1: &NcCell, plane2: &NcPlane, cell2: &NcCell) -> bool {
if cell1.stylemask != cell2.stylemask {
return true;
}
if cell1.channels != cell2.channels {
return true;
}
unsafe {
strcmp(
crate::nccell_extended_gcluster(plane1, cell1),
crate::nccell_extended_gcluster(plane2, cell2),
) != 0
}
}
/// Initializes (zeroes out) an [`NcCell`].
///
/// *Method: NcCell.[init()][NcCell#method.init].*
#[inline]
pub fn nccell_init(cell: &mut NcCell) {
*cell = unsafe { core::mem::zeroed() }
}
/// Same as [`nccell_load`][crate::nccell_load], plus blasts the styling with
/// `style` and `channels`.
///
/// - Breaks the UTF-8 string in `gcluster` down, setting up the cell `cell`.
/// - Returns the number of bytes copied out of `gcluster`, or -1 on failure.
/// - The styling of the cell is left untouched, but any resources are released.
/// - Blasts the styling with `style` and `channels`.
///
/// *Method: NcCell.[prime()][NcCell#method.prime].*
pub fn nccell_prime(
plane: &mut NcPlane,
cell: &mut NcCell,
gcluster: &str,
style: NcStyle,
channels: NcChannels,
) -> NcIntResult {
cell.stylemask = style;
cell.channels = channels;
unsafe { crate::nccell_load(plane, cell, cstring![gcluster]) }
}
/// Loads up six cells with the `EGC`s necessary to draw a box.
///
/// Returns [`NCRESULT_OK`] on success or [`NCRESULT_ERR`] on error.
///
/// On error, any [`NcCell`]s this function might have loaded before the error
/// are [nccell_release]d. There must be at least six `EGC`s in `gcluster`.
///
/// *Method: NcCell.[load_box()][NcCell#method.load_box].*
pub fn nccells_load_box(
plane: &mut NcPlane,
style: NcStyle,
channels: NcChannels,
ul: &mut NcCell,
ur: &mut NcCell,
ll: &mut NcCell,
lr: &mut NcCell,
hl: &mut NcCell,
vl: &mut NcCell,
gcluster: &str,
) -> NcIntResult {
assert![gcluster.len() >= 6]; // DEBUG
// TODO: CHECK: mutable copy for pointer arithmetics:
let mut gclu = cstring![gcluster];
let mut ulen: NcIntResult;
ulen = nccell_prime(plane, ul, gcluster, style, channels);
if ulen > 0 {
gclu = unsafe { gclu.offset(ulen as isize) };
ulen = nccell_prime(plane, ur, gcluster, style, channels);
if ulen > 0 {
gclu = unsafe { gclu.offset(ulen as isize) };
ulen = nccell_prime(plane, ll, gcluster, style, channels);
if ulen > 0 {
gclu = unsafe { gclu.offset(ulen as isize) };
ulen = nccell_prime(plane, lr, gcluster, style, channels);
if ulen > 0 {
gclu = unsafe { gclu.offset(ulen as isize) };
ulen = nccell_prime(plane, hl, gcluster, style, channels);
if ulen > 0 {
let _gclu = unsafe { gclu.offset(ulen as isize) };
ulen = nccell_prime(plane, vl, gcluster, style, channels);
if ulen > 0 {
return NCRESULT_OK;
}
unsafe {
nccell_release(plane, hl);
}
}
unsafe {
nccell_release(plane, lr);
}
}
unsafe {
nccell_release(plane, ll);
}
}
unsafe {
nccell_release(plane, ur);
}
}
unsafe {
nccell_release(plane, ul);
}
}
NCRESULT_ERR
}

@ -1,18 +0,0 @@
//! Test `NcCell` methods and associated functions.
use crate::{Nc, NcCell, NcPlane};
use serial_test::serial;
#[test]
#[serial]
fn constructors() -> crate::NcResult<()> {
let _c1 = NcCell::new();
let _c2 = NcCell::from_char7b('C');
let nc = Nc::new()?;
let plane = NcPlane::new(nc, 0, 0, 10, 10)?;
let _c3 = NcCell::from_char('௵', plane);
nc.stop()?;
Ok(())
}

@ -1,7 +0,0 @@
//! `NcCell` tests
#[cfg(test)]
mod methods;
#[cfg(test)]
mod reimplemented;

@ -1,103 +0,0 @@
//! Test `cell*_*` reimplemented functions
use serial_test::serial;
use crate::NcCell;
#[test]
#[serial]
fn rgb() {
// rgb
let mut c1 = NcCell::new();
assert_eq![0, crate::nccell_fg_rgb(&c1)];
assert_eq![0, crate::nccell_bg_rgb(&c1)];
crate::nccell_set_fg_rgb(&mut c1, 0x99112233);
assert_eq![0x112233, crate::nccell_fg_rgb(&c1)];
crate::nccell_set_bg_rgb(&mut c1, 0x99445566);
assert_eq![0x445566, crate::nccell_bg_rgb(&c1)];
// rgb8
let mut c2 = NcCell::new();
let (mut r, mut g, mut b) = (0, 0, 0);
crate::nccell_set_fg_rgb8(&mut c2, 0x11, 0x22, 0x33);
let fchannel = crate::nccell_fg_rgb8(&c2, &mut r, &mut g, &mut b);
assert_eq!((0x11, 0x22, 0x33), (r, g, b));
assert_eq![0x112233, fchannel & !crate::NCALPHA_BGDEFAULT_MASK];
crate::nccell_set_bg_rgb8(&mut c2, 0x44, 0x55, 0x66);
let bchannel = crate::nccell_bg_rgb8(&c2, &mut r, &mut g, &mut b);
assert_eq!((0x44, 0x55, 0x66), (r, g, b));
assert_eq![0x445566, bchannel & !crate::NCALPHA_BGDEFAULT_MASK];
}
#[test]
#[serial]
fn alpha() {
let mut c1 = NcCell::new();
assert_eq![0, crate::nccell_fg_alpha(&c1)];
assert_eq![0, crate::nccell_bg_alpha(&c1)];
crate::nccell_set_fg_alpha(&mut c1, crate::NCALPHA_TRANSPARENT);
assert_eq![crate::NCALPHA_TRANSPARENT, crate::nccell_fg_alpha(&c1)];
crate::nccell_set_bg_alpha(&mut c1, crate::NCALPHA_BLEND);
assert_eq![crate::NCALPHA_BLEND, crate::nccell_bg_alpha(&c1)];
}
#[test]
#[serial]
fn default() {
let mut c1 = NcCell::new();
assert_eq![true, crate::nccell_fg_default_p(&c1)];
assert_eq![true, crate::nccell_bg_default_p(&c1)];
// rgb
crate::nccell_set_fg_rgb(&mut c1, 0x112233);
crate::nccell_set_bg_rgb(&mut c1, 0x445566);
assert_eq![false, crate::nccell_fg_default_p(&c1)];
assert_eq![false, crate::nccell_bg_default_p(&c1)];
// reset
crate::nccell_set_fg_default(&mut c1);
crate::nccell_set_bg_default(&mut c1);
assert_eq![true, crate::nccell_fg_default_p(&c1)];
assert_eq![true, crate::nccell_bg_default_p(&c1)];
// rgb8
crate::nccell_set_fg_rgb8(&mut c1, 0x11, 0x22, 0x33);
crate::nccell_set_bg_rgb8(&mut c1, 0x44, 0x55, 0x66);
assert_eq![false, crate::nccell_fg_default_p(&c1)];
assert_eq![false, crate::nccell_bg_default_p(&c1)];
// reset
crate::nccell_set_fg_default(&mut c1);
crate::nccell_set_bg_default(&mut c1);
// palette
crate::nccell_set_fg_palindex(&mut c1, 5);
crate::nccell_set_bg_palindex(&mut c1, 6);
assert_eq![false, crate::nccell_fg_default_p(&c1)];
assert_eq![false, crate::nccell_bg_default_p(&c1)];
}
#[test]
#[serial]
fn palette() {
let mut c1 = NcCell::new();
assert_eq![false, crate::nccell_fg_palindex_p(&c1)];
assert_eq![false, crate::nccell_bg_palindex_p(&c1)];
assert_eq![0, crate::nccell_fg_palindex(&c1)];
assert_eq![0, crate::nccell_bg_palindex(&c1)];
crate::nccell_set_fg_palindex(&mut c1, 5);
crate::nccell_set_bg_palindex(&mut c1, 6);
assert_eq![true, crate::nccell_fg_palindex_p(&c1)];
assert_eq![true, crate::nccell_bg_palindex_p(&c1)];
assert_eq![5, crate::nccell_fg_palindex(&c1)];
assert_eq![6, crate::nccell_bg_palindex(&c1)];
}

@ -1,776 +0,0 @@
//! `NcChannel*` methods and associated functions.
#![allow(clippy::unnecessary_cast)]
use crate::{NcAlphaBits, NcChannel, NcChannels, NcComponent, NcPaletteIndex, NcRgb};
/// Enables the [`NcChannel`] methods.
pub trait NcChannelMethods {
// constructors
fn new() -> Self;
fn default() -> Self;
fn from_rgb(rgb: NcRgb) -> Self;
fn from_rgb_alpha(rgb: NcRgb, alpha: NcAlphaBits) -> Self;
fn from_rgb8(r: NcComponent, g: NcComponent, b: NcComponent) -> Self;
fn from_rgb8_alpha(r: NcComponent, g: NcComponent, b: NcComponent, alpha: NcAlphaBits) -> Self;
// methods
fn fcombine(&self, bchannel: NcChannel) -> NcChannels;
fn bcombine(&self, fchannel: NcChannel) -> NcChannels;
fn alpha(&self) -> NcAlphaBits;
fn set_alpha(&mut self, alpha: NcAlphaBits) -> Self;
fn rgb(&self) -> NcRgb;
fn set(&mut self, rgb: NcRgb) -> Self;
fn rgb8(&self) -> (NcComponent, NcComponent, NcComponent);
fn set_rgb8(&mut self, r: NcComponent, g: NcComponent, b: NcComponent) -> Self;
fn r(&self) -> NcComponent;
fn g(&self) -> NcComponent;
fn b(&self) -> NcComponent;
fn set_r(&mut self, r: NcComponent) -> Self;
fn set_g(&mut self, g: NcComponent) -> Self;
fn set_b(&mut self, b: NcComponent) -> Self;
fn default_p(&self) -> bool;
fn set_default(&mut self) -> Self;
fn set_not_default(&mut self) -> Self;
fn palindex_p(&self) -> bool;
}
/// Enables the [`NcChannels`] methods.
pub trait NcChannelsMethods {
// constructors
fn new() -> Self;
fn with_default() -> Self;
fn from_rgb(fg_rgb: NcRgb, bg_rgb: NcRgb) -> Self;
fn from_rgb_both(rgb: NcRgb) -> Self;
fn from_rgb_alpha(
fg_rgb: NcRgb,
fg_alpha: NcAlphaBits,
bg_rgb: NcRgb,
bg_alpha: NcAlphaBits,
) -> Self;
fn from_rgb_alpha_both(rgb: NcRgb, alpha: NcAlphaBits) -> Self;
fn from_rgb8(
fg_r: NcComponent,
fg_g: NcComponent,
fg_b: NcComponent,
bg_r: NcComponent,
bg_g: NcComponent,
bg_b: NcComponent,
) -> Self;
fn from_rgb8_both(r: NcComponent, g: NcComponent, b: NcComponent) -> Self;
fn from_rgb8_alpha(
fg_r: NcComponent,
fg_g: NcComponent,
fg_b: NcComponent,
fg_alpha: NcAlphaBits,
bg_r: NcComponent,
bg_g: NcComponent,
bg_b: NcComponent,
bg_alpha: NcAlphaBits,
) -> Self;
fn from_rgb8_alpha_both(
r: NcComponent,
g: NcComponent,
b: NcComponent,
alpha: NcAlphaBits,
) -> Self;
// methods
fn combine(fchannel: NcChannel, bchannel: NcChannel) -> Self;
fn fchannel(&self) -> NcChannel;
fn bchannel(&self) -> NcChannel;
fn set_fchannel(&mut self, fchannel: NcChannel) -> Self;
fn set_bchannel(&mut self, bchannel: NcChannel) -> Self;
fn fg_alpha(&self) -> NcAlphaBits;
fn bg_alpha(&self) -> NcAlphaBits;
fn set_fg_alpha(&mut self, alpha: NcAlphaBits);
fn set_bg_alpha(&mut self, alpha: NcAlphaBits);
fn fg_rgb(&self) -> NcRgb;
fn bg_rgb(&self) -> NcRgb;
fn set_fg_rgb(&mut self, alpha: NcAlphaBits) -> Self;
fn set_bg_rgb(&mut self, alpha: NcAlphaBits) -> Self;
fn fg_rgb8(&self) -> (NcComponent, NcComponent, NcComponent);
fn bg_rgb8(&self) -> (NcComponent, NcComponent, NcComponent);
fn set_fg_rgb8(&mut self, r: NcComponent, g: NcComponent, b: NcComponent) -> Self;
fn set_bg_rgb8(&mut self, r: NcComponent, g: NcComponent, b: NcComponent) -> Self;
fn fg_r(&self) -> NcComponent;
fn fg_g(&self) -> NcComponent;
fn fg_b(&self) -> NcComponent;
fn bg_r(&self) -> NcComponent;
fn bg_g(&self) -> NcComponent;
fn bg_b(&self) -> NcComponent;
fn fg_set_r(&mut self, r: NcComponent) -> Self;
fn fg_set_g(&mut self, g: NcComponent) -> Self;
fn fg_set_b(&mut self, b: NcComponent) -> Self;
fn bg_set_r(&mut self, r: NcComponent) -> Self;
fn bg_set_g(&mut self, g: NcComponent) -> Self;
fn bg_set_b(&mut self, b: NcComponent) -> Self;
fn fg_default_p(&self) -> bool;
fn bg_default_p(&self) -> bool;
fn set_fg_default(&mut self) -> Self;
fn set_fg_not_default(&mut self) -> Self;
fn set_bg_default(&mut self) -> Self;
fn set_bg_not_default(&mut self) -> Self;
fn set_default(&mut self) -> Self;
fn set_not_default(&mut self) -> Self;
fn fg_palindex_p(&self) -> bool;
fn bg_palindex_p(&self) -> bool;
fn set_fg_palindex(&mut self, index: NcPaletteIndex) -> Self;
fn set_bg_palindex(&mut self, index: NcPaletteIndex) -> Self;
}
// NcChannel -------------------------------------------------------------------
/// # NcChannel Methods
impl NcChannelMethods for NcChannel {
// Constructors
/// New `NcChannel`, set to black and NOT using the "default color".
fn new() -> Self {
0 as NcChannel | crate::NCALPHA_BGDEFAULT_MASK
}
/// New `NcChannel`, set to black and using the "default color".
fn default() -> Self {
0 as NcChannel
}
/// New `NcChannel`, expects [`NcRgb`].
fn from_rgb(rgb: NcRgb) -> Self {
Self::new().set(rgb)
}
/// New `NcChannel`, expects [`NcRgb`] & [`NcAlphaBits`].
fn from_rgb_alpha(rgb: NcRgb, alpha: NcAlphaBits) -> Self {
Self::new().set(rgb).set_alpha(alpha)
}
/// New `NcChannel`, expects three RGB [`NcComponent`] components.
fn from_rgb8(r: NcComponent, g: NcComponent, b: NcComponent) -> Self {
Self::new().set_rgb8(r, g, b)
}
/// New `NcChannel`, expects three RGB [`NcComponent`] components & [`NcAlphaBits`].
fn from_rgb8_alpha(r: NcComponent, g: NcComponent, b: NcComponent, alpha: NcAlphaBits) -> Self {
Self::new().set_rgb8(r, g, b).set_alpha(alpha)
}
// Combine
/// Combines this [`NcChannel`] as foreground, with another as background
/// into an [`NcChannels`].
///
/// *C style function: [channels_combine()][crate::ncchannels_combine].*
//
// Not in the C API
fn fcombine(&self, bchannel: NcChannel) -> NcChannels {
crate::ncchannels_combine(*self, bchannel)
}
/// Combines this [`NcChannel`] as background, with another as foreground
/// into an [`NcChannels`].
///
/// *C style function: [channels_combine()][crate::ncchannels_combine].*
//
// Not in the C API
fn bcombine(&self, fchannel: NcChannel) -> NcChannels {
crate::ncchannels_combine(fchannel, *self)
}
// Alpha
/// Gets the [`NcAlphaBits`].
///
/// *C style function: [channel_alpha()][crate::ncchannel_alpha].*
fn alpha(&self) -> NcAlphaBits {
crate::ncchannel_alpha(*self)
}
/// Sets the [`NcAlphaBits`].
///
/// *C style function: [channel_set_alpha()][crate::ncchannel_set_alpha].*
fn set_alpha(&mut self, alpha: NcAlphaBits) -> Self {
crate::ncchannel_set_alpha(self, alpha);
*self
}
// NcRgb
/// Gets the [`NcRgb`].
///
/// *C style function: [channel_rgb()][crate::ncchannel_rgb].*
//
// Not in the C API
fn rgb(&self) -> NcRgb {
crate::ncchannel_rgb(*self)
}
/// Sets the [`NcRgb`], and marks the NcChannel as NOT using the
/// "default color", retaining the other bits unchanged.
///
/// *C style function: [channel_set()][crate::ncchannel_set].*
fn set(&mut self, rgb: NcRgb) -> Self {
crate::ncchannel_set(self, rgb);
*self
}
// NcComponent
/// Gets the three [`NcComponent`]s.
///
/// *C style function: [channel_rgb8()][crate::ncchannel_rgb8].*
fn rgb8(&self) -> (NcComponent, NcComponent, NcComponent) {
let (mut r, mut g, mut b) = (0, 0, 0);
crate::ncchannel_rgb8(*self, &mut r, &mut g, &mut b);
(r, g, b)
}
/// Sets the three [`NcComponent`]s, and
/// marks the NcChannel as NOT using the "default color".
///
/// *C style function: [channel_set_rgb8()][crate::ncchannel_set_rgb8].*
fn set_rgb8(&mut self, r: NcComponent, g: NcComponent, b: NcComponent) -> Self {
crate::ncchannel_set_rgb8(self, r, g, b);
*self
}
/// Gets the red [`NcComponent`].
///
/// *C style function: [channel_r()][crate::ncchannel_r].*
fn r(&self) -> NcComponent {
crate::ncchannel_r(*self)
}
/// Gets the green [`NcComponent`].
///
/// *C style function: [channel_g()][crate::ncchannel_g].*
fn g(&self) -> NcComponent {
crate::ncchannel_g(*self)
}
/// Gets the blue [`NcComponent`].
///
/// *C style function: [channel_b()][crate::ncchannel_b].*
fn b(&self) -> NcComponent {
crate::ncchannel_b(*self)
}
/// Sets the red [`NcComponent`], and returns the new `NcChannel`.
///
/// *C style function: [channel_set_r()][crate::ncchannel_set_r].*
//
// Not in the C API
fn set_r(&mut self, r: NcComponent) -> Self {
crate::ncchannel_set_r(self, r)
}
/// Sets the green [`NcComponent`], and returns the new `NcChannel`.
///
/// *C style function: [channel_set_g()][crate::ncchannel_set_g].*
//
// Not in the C API
fn set_g(&mut self, g: NcComponent) -> Self {
crate::ncchannel_set_g(self, g)
}
/// Sets the blue [`NcComponent`], and returns the new `NcChannel`.
///
/// *C style function: [channel_set_b()][crate::ncchannel_set_b].*
//
// Not in the C API
fn set_b(&mut self, b: NcComponent) -> Self {
crate::ncchannel_set_b(self, b)
}
// default color
/// Is this `NcChannel` using the "default color" rather than RGB/palette-indexed?
///
/// *C style function: [channel_default_p()][crate::ncchannel_default_p].*
fn default_p(&self) -> bool {
crate::ncchannel_default_p(*self)
}
/// Marks this `NcChannel` as using its "default color",
/// which also marks it opaque.
///
/// *C style function: [channel_set_default()][crate::ncchannel_set_default].*
fn set_default(&mut self) -> Self {
crate::ncchannel_set_default(self)
}
/// Marks this `NcChannel` as *not* using its "default color".
///
/// The following methods also marks the channel as NOT using the "default color":
/// - [new()][NcChannel#method.new]
/// - [set()][NcChannel#method.set]
/// - [set_rgb8()][NcChannel#method.set_rgb8]
///
/// *C style function: [channel_set_not_default()][crate::ncchannel_set_not_default].*
//
// Not in the C API
fn set_not_default(&mut self) -> Self {
crate::ncchannel_set_not_default(self)
}
// NcPaletteIndex
/// Is this NcChannel using palette-indexed color rather than RGB?
///
/// *C style function: [channel_set_default()][crate::ncchannel_set_default].*
fn palindex_p(&self) -> bool {
crate::ncchannel_palindex_p(*self)
}
}
// NcChannels ---------------------------------------------------------------
/// # NcChannels Methods
impl NcChannelsMethods for NcChannels {
// Constructors
/// New `NcChannels`, set to black and NOT using the "default color".
fn new() -> Self {
Self::combine(
0 as NcChannel | crate::NCALPHA_BGDEFAULT_MASK,
0 as NcChannel | crate::NCALPHA_BGDEFAULT_MASK,
)
}
/// New `NcChannels`, set to black and using the "default color".
fn with_default() -> Self {
Self::combine(0 as NcChannel, 0 as NcChannel)
}
/// New `NcChannels`, expects two separate [`NcRgb`]s for the foreground
/// and background channels.
fn from_rgb(fg_rgb: NcRgb, bg_rgb: NcRgb) -> Self {
Self::combine(NcChannel::from_rgb(fg_rgb), NcChannel::from_rgb(bg_rgb))
}
/// New `NcChannels`, expects a single [`NcRgb`] for both foreground
/// and background channels.
fn from_rgb_both(rgb: NcRgb) -> Self {
let channel = NcChannel::new().set(rgb);
Self::combine(channel, channel)
}
/// New `NcChannels`, expects two separate [`NcRgb`] & [`NcAlphaBits`] for the
/// foreground and background channels.
fn from_rgb_alpha(
fg_rgb: NcRgb,
fg_alpha: NcAlphaBits,
bg_rgb: NcRgb,
bg_alpha: NcAlphaBits,
) -> Self {
Self::combine(
NcChannel::from_rgb(fg_rgb).set_alpha(fg_alpha),
NcChannel::from_rgb(bg_rgb).set_alpha(bg_alpha),
)
}
/// New `NcChannels`, expects [`NcRgb`] & [`NcAlphaBits`] for both
/// channels.
fn from_rgb_alpha_both(rgb: NcRgb, alpha: NcAlphaBits) -> Self {
let channel = NcChannel::new().set(rgb).set_alpha(alpha);
Self::combine(channel, channel)
}
/// New `NcChannels`, expects three RGB [`NcComponent`] components
/// for each channel.
fn from_rgb8(
fg_r: NcComponent,
fg_g: NcComponent,
fg_b: NcComponent,
bg_r: NcComponent,
bg_g: NcComponent,
bg_b: NcComponent,
) -> Self {
Self::combine(
NcChannel::from_rgb8(fg_r, fg_g, fg_b),
NcChannel::from_rgb8(bg_r, bg_g, bg_b),
)
}
/// New `NcChannels`, expects three RGB [`NcComponent`] components for
/// both the foreground and background channels.
fn from_rgb8_both(r: NcComponent, g: NcComponent, b: NcComponent) -> Self {
let channel = NcChannel::new().set_rgb8(r, g, b);
Self::combine(channel, channel)
}
/// New `NcChannels`, expects three RGB [`NcComponent`]s and
/// [`NcAlphaBits`], for both the foreground and background channels.
fn from_rgb8_alpha(
fg_r: NcComponent,
fg_g: NcComponent,
fg_b: NcComponent,
fg_alpha: NcAlphaBits,
bg_r: NcComponent,
bg_g: NcComponent,
bg_b: NcComponent,
bg_alpha: NcAlphaBits,
) -> Self {
Self::combine(
NcChannel::from_rgb8_alpha(fg_r, fg_g, fg_b, fg_alpha),
NcChannel::from_rgb8_alpha(bg_r, bg_g, bg_b, bg_alpha),
)
}
/// New `NcChannel`, expects three RGB [`NcComponent`]s.
fn from_rgb8_alpha_both(
r: NcComponent,
g: NcComponent,
b: NcComponent,
alpha: NcAlphaBits,
) -> Self {
let channel = NcChannel::new().set_rgb8(r, g, b).set_alpha(alpha);
Self::combine(channel, channel)
}
// Combine
/// Combines two [`NcChannel`]s into an [`NcChannels`].
///
/// *C style function: [channels_combine()][crate::ncchannels_combine].*
fn combine(fchannel: NcChannel, bchannel: NcChannel) -> Self {
crate::ncchannels_combine(fchannel, bchannel)
}
// NcChannel
/// Extracts the foreground [`NcChannel`].
///
/// *C style function: [channels_fchannel()][crate::ncchannels_fchannel].*
fn fchannel(&self) -> NcChannel {
crate::ncchannels_fchannel(*self)
}
/// Extracts the background [`NcChannel`].
///
/// *C style function: [channels_bchannel()][crate::ncchannels_bchannel].*
fn bchannel(&self) -> NcChannel {
crate::ncchannels_bchannel(*self)
}
/// Sets the foreground [`NcChannel`].
///
/// *C style function: [channels_set_fchannel()][crate::ncchannels_set_fchannel].*
fn set_fchannel(&mut self, fchannel: NcChannel) -> Self {
crate::ncchannels_set_fchannel(self, fchannel)
}
/// Sets the background [`NcChannel`].
///
/// *C style function: [channels_set_bchannel()][crate::ncchannels_set_bchannel].*
fn set_bchannel(&mut self, bchannel: NcChannel) -> Self {
crate::ncchannels_set_bchannel(self, bchannel)
}
// Alpha
/// Gets the foreground [`NcAlphaBits`].
///
/// *C style function: [channels_fg_alpha()][crate::ncchannels_fg_alpha].*
fn fg_alpha(&self) -> NcAlphaBits {
crate::ncchannels_fg_alpha(*self)
}
/// Gets the background [`NcAlphaBits`].
///
/// *C style function: [channels_bg_alpha()][crate::ncchannels_bg_alpha].*
fn bg_alpha(&self) -> NcAlphaBits {
crate::ncchannels_bg_alpha(*self)
}
/// Sets the foreground [`NcAlphaBits`].
///
/// *C style function: [channels_set_fg_alpha()][crate::ncchannels_set_fg_alpha].*
fn set_fg_alpha(&mut self, alpha: NcAlphaBits) {
crate::ncchannels_set_fg_alpha(self, alpha)
}
/// Sets the background [`NcAlphaBits`].
///
/// *C style function: [channels_set_bg_alpha()][crate::ncchannels_set_bg_alpha].*
fn set_bg_alpha(&mut self, alpha: NcAlphaBits) {
crate::ncchannels_set_bg_alpha(self, alpha)
}
// NcRgb
/// Gets the foreground [`NcRgb`].
///
/// *C style function: [channels_fg_rgb()][crate::ncchannels_fg_rgb].*
fn fg_rgb(&self) -> NcRgb {
crate::ncchannels_fg_rgb(*self)
}
/// Gets the background [`NcRgb`].
///
/// *C style function: [channels_bg_rgb()][crate::ncchannels_bg_rgb].*
fn bg_rgb(&self) -> NcRgb {
crate::ncchannels_bg_rgb(*self)
}
/// Sets the foreground [`NcRgb`].
///
/// *C style function: [channels_set_fg_rgb()][crate::ncchannels_set_fg_rgb].*
fn set_fg_rgb(&mut self, rgb: NcRgb) -> Self {
crate::ncchannels_set_fg_rgb(self, rgb);
*self
}
/// Sets the background [`NcRgb`].
///
/// *C style function: [channels_set_bg_rgb()][crate::ncchannels_set_bg_rgb].*
fn set_bg_rgb(&mut self, rgb: NcRgb) -> Self {
crate::ncchannels_set_bg_rgb(self, rgb);
*self
}
// NcComponent
/// Gets the three foreground RGB [`NcComponent`]s (r, g, b).
///
/// *C style function: [channels_fg_rgb8()][crate::ncchannels_fg_rgb8].*
fn fg_rgb8(&self) -> (NcComponent, NcComponent, NcComponent) {
let (mut r, mut g, mut b) = (0, 0, 0);
crate::ncchannels_fg_rgb8(*self, &mut r, &mut g, &mut b);
(r, g, b)
}
/// Gets the three background RGB [`NcComponent`]s (r, g, b).
///
/// *C style function: [channels_bg_rgb8()][crate::ncchannels_bg_rgb8].*
fn bg_rgb8(&self) -> (NcComponent, NcComponent, NcComponent) {
let (mut r, mut g, mut b) = (0, 0, 0);
crate::ncchannels_bg_rgb8(*self, &mut r, &mut g, &mut b);
(r, g, b)
}
/// Sets the three foreground RGB [`NcComponent`]s (r, g, b), and
/// marks the foreground [`NcChannel`] as not using the "default color".
///
/// *C style function: [channels_set_fg_rgb8()][crate::ncchannels_set_fg_rgb8].*
fn set_fg_rgb8(&mut self, r: NcComponent, g: NcComponent, b: NcComponent) -> Self {
crate::ncchannels_set_fg_rgb8(self, r, g, b)
}
/// Sets the three background RGB [`NcComponent`]s (r, g, b), and
/// marks the background [`NcChannel`] as not using the "default color".
///
/// *C style function: [channels_set_bg_rgb8()][crate::ncchannels_set_bg_rgb8].*
fn set_bg_rgb8(&mut self, r: NcComponent, g: NcComponent, b: NcComponent) -> Self {
crate::ncchannels_set_bg_rgb8(self, r, g, b)
}
/// Gets the foreground red [`NcComponent`].
///
/// *(No equivalent C style function)*
fn fg_r(&self) -> NcComponent {
crate::ncchannel_r(crate::ncchannels_fchannel(*self))
}
/// Gets the foreground green [`NcComponent`].
///
/// *(No equivalent C style function)*
fn fg_g(&self) -> NcComponent {
crate::ncchannel_g(crate::ncchannels_fchannel(*self))
}
/// Gets the foreground blue [`NcComponent`].
///
/// *(No equivalent C style function)*
fn fg_b(&self) -> NcComponent {
crate::ncchannel_b(crate::ncchannels_fchannel(*self))
}
/// Gets the background red [`NcComponent`].
///
/// *(No equivalent C style function)*
fn bg_r(&self) -> NcComponent {
crate::ncchannel_r(crate::ncchannels_bchannel(*self))
}
/// Gets the background green [`NcComponent`].
///
/// *(No equivalent C style function)*
fn bg_g(&self) -> NcComponent {
crate::ncchannel_g(crate::ncchannels_bchannel(*self))
}
/// Gets the background blue [`NcComponent`].
///
/// *(No equivalent C style function)*
fn bg_b(&self) -> NcComponent {
crate::ncchannel_b(crate::ncchannels_bchannel(*self))
}
/// Sets the foreground red [`NcComponent`], and returns the new `NcChannels`.
///
/// *(No equivalent C style function)*
fn fg_set_r(&mut self, r: NcComponent) -> Self {
let (_, g, b) = self.bg_rgb8();
crate::ncchannels_set_fg_rgb8(self, r, g, b)
}
/// Sets the foreground green [`NcComponent`], and returns the new `NcChannels`.
///
/// *(No equivalent C style function)*
fn fg_set_g(&mut self, g: NcComponent) -> Self {
let (r, _, b) = self.bg_rgb8();
crate::ncchannels_set_fg_rgb8(self, r, g, b)
}
/// Sets the foreground blue [`NcComponent`], and returns the new `NcChannels`.
///
/// *(No equivalent C style function)*
fn fg_set_b(&mut self, b: NcComponent) -> Self {
let (r, g, _) = self.bg_rgb8();
crate::ncchannels_set_fg_rgb8(self, r, g, b)
}
/// Sets the background red [`NcComponent`], and returns the new `NcChannels`.
///
/// *(No equivalent C style function)*
fn bg_set_r(&mut self, r: NcComponent) -> Self {
let (_, g, b) = self.bg_rgb8();
crate::ncchannels_set_bg_rgb8(self, r, g, b)
}
/// Sets the background green [`NcComponent`], and returns the new `NcChannels`.
///
/// *(No equivalent C style function)*
fn bg_set_g(&mut self, g: NcComponent) -> Self {
let (r, _, b) = self.bg_rgb8();
crate::ncchannels_set_bg_rgb8(self, r, g, b)
}
/// Sets the background blue [`NcComponent`], and returns the new `NcChannels`.
///
/// *(No equivalent C style function)*
fn bg_set_b(&mut self, b: NcComponent) -> Self {
let (r, g, _) = self.bg_rgb8();
crate::ncchannels_set_bg_rgb8(self, r, g, b)
}
// default color
/// Is the background using the "default background color"?
///
/// *C style function: [channels_fg_default_p()][crate::ncchannels_fg_default_p].*
fn fg_default_p(&self) -> bool {
crate::ncchannels_fg_default_p(*self)
}
/// Is the background using the "default background color"?
///
/// The "default background color" must generally be used to take advantage
/// of terminal-effected transparency.
///
/// *C style function: [channels_bg_default_p()][crate::ncchannels_bg_default_p].*
fn bg_default_p(&self) -> bool {
crate::ncchannels_bg_default_p(*self)
}
/// Marks the foreground as using its "default color", and
/// returns the new [`NcChannels`].
///
/// *C style function: [channels_set_fg_default()][crate::ncchannels_set_fg_default].*
fn set_fg_default(&mut self) -> Self {
crate::ncchannels_set_fg_default(self)
}
/// Marks the background as using its "default color", and
/// returns the new [`NcChannels`].
///
/// *C style function: [channels_set_bg_default()][crate::ncchannels_set_bg_default].*
fn set_bg_default(&mut self) -> Self {
crate::ncchannels_set_bg_default(self)
}
/// Marks the foreground as NOT using its "default color", and
/// returns the new [`NcChannels`].
///
/// *C style function: [channels_set_fg_default()][crate::ncchannels_set_fg_default].*
//
// Not in the C API
fn set_fg_not_default(&mut self) -> Self {
crate::ncchannels_set_fg_not_default(self)
}
/// Marks the background as NOT using its "default color", and
/// returns the new [`NcChannels`].
///
/// *C style function: [channels_set_bg_not_default()][crate::ncchannels_set_bg_not_default].*
//
// Not in the C API
fn set_bg_not_default(&mut self) -> Self {
crate::ncchannels_set_bg_not_default(self)
}
/// Marks both the foreground and background as using its "default color", and
/// returns the new [`NcChannels`].
///
//
// Not in the C API
fn set_default(&mut self) -> Self {
crate::ncchannels_set_fg_default(&mut crate::ncchannels_set_bg_default(self))
}
/// Marks both the foreground and background as NOT using its "default color",
/// and returns the new [`NcChannels`].
///
//
// Not in the C API
fn set_not_default(&mut self) -> Self {
crate::ncchannels_set_fg_not_default(&mut crate::ncchannels_set_bg_not_default(self))
}
// NcPaletteIndex
/// Is the foreground of using an [indexed][NcPaletteIndex]
/// [NcPalette][crate::NcPalette] color?
///
/// *C style function: [channels_fg_palindex_p()][crate::ncchannels_fg_palindex_p].*
fn fg_palindex_p(&self) -> bool {
crate::ncchannels_fg_palindex_p(*self)
}
/// Is the background of using an [indexed][NcPaletteIndex]
/// [NcPalette][crate::NcPalette] color?
///
/// *C style function: [channels_bg_palindex_p()][crate::ncchannels_bg_palindex_p].*
fn bg_palindex_p(&self) -> bool {
crate::ncchannels_bg_palindex_p(*self)
}
/// Sets the foreground of an [`NcChannels`] as using an
/// [indexed][NcPaletteIndex] [NcPalette][crate::NcPalette] color.
///
/// *C style function: [channels_set_fg_palindex()][crate::ncchannels_set_fg_palindex].*
fn set_fg_palindex(&mut self, index: NcPaletteIndex) -> Self {
crate::ncchannels_set_fg_palindex(self, index);
*self
}
/// Sets the background of an [`NcChannels`] as using an
/// [indexed][NcPaletteIndex] [NcPalette][crate::NcPalette] color.
///
/// *C style function: [channels_set_bg_palindex()][crate::ncchannels_set_bg_palindex].*
fn set_bg_palindex(&mut self, index: NcPaletteIndex) -> Self {
crate::ncchannels_set_bg_palindex(self, index);
*self
}
}

@ -1,314 +0,0 @@
//! `NcChannel*`
// -----------------------------------------------------------------------------
// - The channel components are u8 instead of u32.
// Because of type enforcing, some runtime checks are now unnecessary.
//
// - None of the functions can't fail now. The original checks for dirty bits
// have been substitued by mask cleaning (bitwise and)
//
// - These functions were deemed unnecessary to implement:
// - `channel_set_rgb_clipped()`
// - `channels_set_fg_rgb8_clipped()`
// - `channels_set_bg_rgb8_clipped()`
// -----------------------------------------------------------------------------
//
// functions manually reimplemented: 44
// ------------------------------------------
// (X) wont: 3
// (+) done: 36 / 0
// (#) test: 21
// (W) wrap: 41
// ------------------------------------------
//W# channel_alpha
//W# channel_b
//W# channel_default_p
//W# channel_g
//W# channel_palindex_p
//W# channel_r
//W# channel_rgb8
//W# channel_set
//W# channel_set_alpha
//W# channel_set_default
//W# channel_set_not_default // not in the original C API
//W# channel_set_rgb8
// X channel_set_rgb_clipped // not needed
//W# channels_bchannel
//W+ channels_bg_alpha
//W+ channels_bg_default_p
//W# channels_bg_palindex_p
//W+ channels_bg_rgb
//W+ channels_bg_rgb8
//W# channels_combine
//W# channels_fchannel
//W+ channels_fg_alpha
//W+ channels_fg_default_p
//W# channels_fg_palindex_p
//W+ channels_fg_rgb
//W+ channels_fg_rgb8
//W# channels_set_bchannel
//W+ channels_set_bg_alpha
//W+ channels_set_bg_default
//W channels_set_bg_not_default // not in the original C API
//W# channels_set_bg_palindex
//W+ channels_set_bg_rgb
//W+ channels_set_bg_rgb8
// X channels_set_bg_rgb8_clipped // not needed
//W channels_set_default // not in the original C API
//W# channels_set_fchannel
//W+ channels_set_fg_alpha
//W+ channels_set_fg_default
//W channels_set_fg_not_default // not in the original C API
//W# channels_set_fg_palindex
//W+ channels_set_fg_rgb
//W+ channels_set_fg_rgb8
// X channels_set_fg_rgb8_clipped // not needed
//W channels_set_not_default // not in the original C API
#[allow(unused_imports)] // for the doc comments
use crate::{NcCell, NcRgba};
#[cfg(test)]
mod test;
mod methods;
mod reimplemented;
pub use methods::{NcChannelMethods, NcChannelsMethods};
pub use reimplemented::*;
// NcChannel
//
/// 32 bits of context-dependent info
/// containing RGB + 2 bits of alpha + extra
///
/// It is:
/// - a 24-bit [`NcRgb`] value
/// - plus 8 bits divided in:
/// - 2 bits of [`NcAlphaBits`]
/// - 6 bits of context-dependent info
///
/// The context details are documented in [`NcChannels`]
///
/// ## Diagram
///
/// ```txt
/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB
/// ```
/// `type in C: channel (uint32_t)`
///
/// See also: [NcRgb] and [NcRgba] types.
pub type NcChannel = u32;
/// Extract these bits to get a channel's alpha value
pub const NCCHANNEL_ALPHA_MASK: u32 = crate::bindings::ffi::NC_BG_ALPHA_MASK;
// NcAlphaBits
//
/// 2 bits of alpha (surrounded by context dependent bits).
/// It is part of an [`NcChannel`].
///
/// ## Diagram
///
/// ```txt
/// ~~AA~~~~ -------- -------- --------
/// ```
/// `type in C: no data type`
///
pub type NcAlphaBits = u32;
/// [`NcAlphaBits`] bits indicating
/// [`NcCell`]'s foreground or background color will be a composite between
/// its color and the `NcCell`s' corresponding colors underneath it
pub const NCALPHA_BLEND: u32 = crate::bindings::ffi::NCALPHA_BLEND;
/// [`NcAlphaBits`] bits indicating
/// [`NcCell`]'s foreground color will be high-contrast (relative to the
/// computed background). Background cannot be highcontrast
pub const NCALPHA_HIGHCONTRAST: u32 = crate::bindings::ffi::NCALPHA_HIGHCONTRAST;
/// [`NcAlphaBits`] bits indicating
/// [`NcCell`]'s foreground or background color is used unchanged
pub const NCALPHA_OPAQUE: u32 = crate::bindings::ffi::NCALPHA_OPAQUE;
/// [`NcAlphaBits`] bits indicating
/// [`NcCell`]'s foreground or background color is derived entirely from the
/// `NcCell`s underneath it
pub const NCALPHA_TRANSPARENT: u32 = crate::bindings::ffi::NCALPHA_TRANSPARENT;
/// If this bit is set, we are *not* using the default background color
///
/// See the detailed diagram at [`NcChannels`][crate::NcChannels]
///
/// Note: This can also be used against a single [`NcChannel`]
pub const NCALPHA_BGDEFAULT_MASK: u32 = crate::bindings::ffi::NC_BGDEFAULT_MASK;
/// Extract these bits to get the background alpha mask
/// ([`NcAlphaBits`])
///
/// See the detailed diagram at [`NcChannels`][crate::NcChannels]
///
/// Note: This can also be used against a single [`NcChannel`]
pub const NCALPHA_BG_ALPHA_MASK: u32 = crate::bindings::ffi::NC_BG_ALPHA_MASK;
/// If this bit *and* [`NCALPHA_BGDEFAULT_MASK`] are set, we're using a
/// palette-indexed background color
///
/// See the detailed diagram at [`NcChannels`][crate::NcChannels]
///
/// Note: This can also be used against a single [`NcChannel`]
pub const NCALPHA_BG_PALETTE: u32 = crate::bindings::ffi::NC_BG_PALETTE;
/// Extract these bits to get the background [`NcRgb`][crate::NcRgb] value
///
/// See the detailed diagram at [`NcChannels`][crate::NcChannels]
///
/// Note: This can also be used against a single [`NcChannel`]
pub const NCALPHA_BG_RGB_MASK: u32 = crate::bindings::ffi::NC_BG_RGB_MASK;
/// If this bit is set, we are *not* using the default foreground color
///
/// See the detailed diagram at [`NcChannels`][crate::NcChannels]
///
/// Note: When working with a single [`NcChannel`] use [`NCALPHA_BGDEFAULT_MASK`];
pub const NCALPHA_FGDEFAULT_MASK: u64 = crate::bindings::ffi::NC_FGDEFAULT_MASK;
/// Extract these bits to get the foreground alpha mask
/// ([`NcAlphaBits`])
///
/// See the detailed diagram at [`NcChannels`][crate::NcChannels]
///
/// Note: When working with a single [`NcChannel`] use [`NCALPHA_BG_ALPHA_MASK`];
pub const NCALPHA_FG_ALPHA_MASK: u64 = crate::bindings::ffi::NC_FG_ALPHA_MASK;
/// If this bit *and* [`NCALPHA_FGDEFAULT_MASK`] are set, we're using a
/// palette-indexed background color
///
/// See the detailed diagram at [`NcChannels`][crate::NcChannels]
///
/// Note: When working with a single [`NcChannel`] use [`NCALPHA_BG_PALETTE`];
pub const NCALPHA_FG_PALETTE: u64 = crate::bindings::ffi::NC_FG_PALETTE;
/// Extract these bits to get the foreground [`NcRgb`][crate::NcRgb] value
///
/// See the detailed diagram at [`NcChannels`][crate::NcChannels]
///
/// Note: When working with a single [`NcChannel`] use [`NCALPHA_BG_RGB_MASK`];
pub const NCALPHA_FG_RGB_MASK: u64 = crate::bindings::ffi::NC_FG_RGB_MASK;
// NcChannels
//
/// 64 bits containing a foreground and background [`NcChannel`]
///
/// At render time, both 24-bit [`NcRgb`] values are quantized down to terminal
/// capabilities, if necessary. There's a clear path to 10-bit support should
/// we one day need it.
///
/// ## Default Color
///
/// The "default color" is best explained by
/// [color(3NCURSES)](https://manpages.debian.org/stretch/ncurses-doc/color.3ncurses.en.html) and
/// [default_colors(3NCURSES)](https://manpages.debian.org/stretch/ncurses-doc/default_colors.3ncurses.en.html).
/// Ours is the same concept.
///
/// **Until the "not default color" bit is set, any color you load will be ignored.**
///
/// ## Diagram
///
/// ```txt
/// ~~AA~~~~|RRRRRRRR|GGGGGGGG|BBBBBBBB║~~AA~~~~|RRRRRRRR|GGGGGGGG|BBBBBBBB
/// ↑↑↑↑↑↑↑↑↑↑↑↑ foreground ↑↑↑↑↑↑↑↑↑↑↑║↑↑↑↑↑↑↑↑↑↑↑↑ background ↑↑↑↑↑↑↑↑↑↑↑
/// ```
///
/// Detailed info (specially on the context-dependent bits on each
/// [`NcChannel`]'s 4th byte):
///
/// ```txt
/// ~foreground channel~
/// NCALPHA_WIDEASIAN_MASK: part of a wide glyph ↓bits view↓ ↓hex mask↓
/// 1·······|········|········|········║········|········|········|········ = 8·······|········
///
/// NCALPHA_FGDEFAULT_MASK: foreground is NOT "default color"
/// ·1······|········|········|········║········|········|········|········ = 4·······|········
///
/// NCALPHA_FG_ALPHA_MASK: foreground alpha (2bits)
/// ··11····|········|········|········║········|········|········|········ = 3·······|········
///
/// NCALPHA_FG_PALETTE: foreground uses palette index
/// ····1···|········|········|········║········|········|········|········ = ·8······|········
///
/// NCALPHA_NOBACKGROUND_MASK: glyph is entirely foreground
/// ·····1··|········|········|········║········|········|········|········ = ·4······|········
///
/// reserved, must be 0
/// ······00|········|········|········║········|········|········|········ = ·3······|········
///
/// NCALPHA_FG_RGB_MASK: foreground in 3x8 RGB (rrggbb)
/// ········|11111111|11111111|11111111║········|········|········|········ = ··FFFFFF|········
/// ```
/// ```txt
/// ~background channel~
/// reserved, must be 0 ↓bits view↓ ↓hex mask↓
/// ········|········|········|········║0·······|········|········|········ = ········|8·······
///
/// NCALPHA_BGDEFAULT_MASK: background is NOT "default color"
/// ········|········|········|········║·1······|········|········|········ = ········|4·······
///
/// NCALPHA_BG_ALPHA_MASK: background alpha (2 bits)
/// ········|········|········|········║··11····|········|········|········ = ········|3·······
///
/// NCALPHA_BG_PALETTE: background uses palette index
/// ········|········|········|········║····1···|········|········|········ = ········|·8······
///
/// reserved, must be 0
/// ········|········|········|········║·····000|········|········|········ = ········|·7······
///
/// NCALPHA_BG_RGB_MASK: background in 3x8 RGB (rrggbb)
/// ········|········|········|········║········|11111111|11111111|11111111 = ········|··FFFFFF
/// ```
/// `type in C: channels (uint64_t)`
///
/// ## `NcCell` Mask Flags
///
/// - [`NCALPHA_BGDEFAULT_MASK`][crate::NCALPHA_BGDEFAULT_MASK]
/// - [`NCALPHA_BG_ALPHA_MASK`][crate::NCALPHA_BG_ALPHA_MASK]
/// - [`NCALPHA_BG_PALETTE`][crate::NCALPHA_BG_PALETTE]
/// - [`NCALPHA_BG_RGB_MASK`][crate::NCALPHA_BG_RGB_MASK]
/// - [`NCALPHA_FGDEFAULT_MASK`][crate::NCALPHA_FGDEFAULT_MASK]
/// - [`NCALPHA_FG_ALPHA_MASK`][crate::NCALPHA_FG_ALPHA_MASK]
/// - [`NCALPHA_FG_PALETTE`][crate::NCALPHA_FG_PALETTE]
/// - [`NCALPHA_FG_RGB_MASK`][crate::NCALPHA_FG_RGB_MASK]
///
pub type NcChannels = u64;
#[deprecated = "use NcChannels instead"]
#[doc(hidden)]
pub type NcChannelPair = NcChannels;
// NcRgb
//
/// 24 bits broken into 3x 8bpp channels.
///
/// Unlike with [`NcChannel`], operations involving `NcRgb` ignores the last 4th byte
///
/// ## Diagram
///
/// ```txt
/// -------- RRRRRRRR GGGGGGGG BBBBBBBB
/// ```
/// `type in C: no data type`
///
/// See also: [NcRgba] and [NcChannel] types.
pub type NcRgb = u32;
// NcComponent
//
/// 8 bits representing an R/G/B color component or an alpha channel component.
///
/// ## Diagram
///
/// ```txt
/// CCCCCCCC (1 Byte)
/// ```
/// `type in C: no data type`
pub type NcComponent = u8;

@ -1,510 +0,0 @@
//! `channel*_*` reimplemented functions.
use crate::{
NcAlphaBits, NcChannel, NcChannels, NcComponent, NcPaletteIndex, NcRgb, NCALPHA_BGDEFAULT_MASK,
NCALPHA_BG_PALETTE, NCALPHA_BG_RGB_MASK, NCALPHA_FGDEFAULT_MASK, NCALPHA_FG_PALETTE,
NCALPHA_HIGHCONTRAST, NCALPHA_OPAQUE, NCCHANNEL_ALPHA_MASK,
};
// Alpha -----------------------------------------------------------------------
/// Gets the [`NcAlphaBits`] from an [`NcChannel`].
///
/// *Method: NcChannel.[alpha()][NcChannel#method.alpha]*
#[inline]
pub const fn ncchannel_alpha(channel: NcChannel) -> NcAlphaBits {
channel & NCCHANNEL_ALPHA_MASK
}
/// Sets the [`NcAlphaBits`] of an [`NcChannel`].
///
/// *Method: NcChannel.[set_alpha()][NcChannel#method.set_alpha]*
#[inline]
pub fn ncchannel_set_alpha(channel: &mut NcChannel, alpha: NcAlphaBits) {
let alpha_clean = alpha & NCCHANNEL_ALPHA_MASK;
*channel = alpha_clean | (*channel & !NCCHANNEL_ALPHA_MASK);
if alpha != NCALPHA_OPAQUE {
// indicate that we are *not* using the default background color
*channel |= NCALPHA_BGDEFAULT_MASK;
}
}
/// Gets the foreground [`NcAlphaBits`] from an [`NcChannels`], shifted to LSBs.
///
/// *Method: NcChannels.[fg_alpha()][NcChannels#method.fg_alpha]*
#[inline]
pub const fn ncchannels_fg_alpha(channels: NcChannels) -> NcAlphaBits {
ncchannel_alpha(ncchannels_fchannel(channels))
}
/// Gets the background [`NcAlphaBits`] from an [`NcChannels`], shifted to LSBs.
///
/// *Method: NcChannels.[bg_alpha()][NcChannels#method.bg_alpha]*
#[inline]
pub const fn ncchannels_bg_alpha(channels: NcChannels) -> NcAlphaBits {
ncchannel_alpha(ncchannels_bchannel(channels))
}
/// Sets the [`NcAlphaBits`] of the foreground [`NcChannel`] of an [`NcChannels`].
///
/// *Method: NcChannels.[set_fg_alpha()][NcChannels#method.set_fg_alpha]*
#[inline]
pub fn ncchannels_set_fg_alpha(channels: &mut NcChannels, alpha: NcAlphaBits) {
let mut channel = ncchannels_fchannel(*channels);
ncchannel_set_alpha(&mut channel, alpha);
*channels = (channel as NcChannels) << 32 | *channels & 0xffffffff_u64;
}
/// Sets the [`NcAlphaBits`] of the background [`NcChannel`] of an [`NcChannels`].
///
/// *Method: NcChannels.[set_bg_alpha()][NcChannels#method.set_bg_alpha]*
#[inline]
pub fn ncchannels_set_bg_alpha(channels: &mut NcChannels, alpha: NcAlphaBits) {
let mut alpha_clean = alpha;
if alpha == NCALPHA_HIGHCONTRAST {
// forbidden for background alpha, so makes it opaque
alpha_clean = NCALPHA_OPAQUE;
}
let mut channel = ncchannels_bchannel(*channels);
ncchannel_set_alpha(&mut channel, alpha_clean);
ncchannels_set_bchannel(channels, channel);
}
// Channels --------------------------------------------------------------------
/// Extracts the background [`NcChannel`] from a [`NcChannels`].
///
/// *Method: NcChannels.[bchannel()][NcChannels#method.bchannel]*
#[inline]
pub const fn ncchannels_bchannel(channels: NcChannels) -> NcChannel {
(channels & 0xffffffff_u64) as NcChannel
}
/// Extracts the foreground [`NcChannel`] from an [`NcChannels`].
///
/// *Method: NcChannels.[fchannel()][NcChannels#method.fchannel]*
#[inline]
pub const fn ncchannels_fchannel(channels: NcChannels) -> NcChannel {
ncchannels_bchannel(channels >> 32)
}
/// Sets the background [`NcChannel`] of an [`NcChannels`].
///
/// *Method: NcChannels.[set_bchannel()][NcChannels#method.set_bchannel]*
#[inline]
pub fn ncchannels_set_bchannel(channels: &mut NcChannels, bchannel: NcChannel) -> NcChannels {
*channels = (*channels & 0xffffffff00000000_u64) | bchannel as u64;
*channels
}
/// Sets the foreground [`NcChannel`] of an [`NcChannels`].
///
/// *Method: NcChannels.[set_fchannel()][NcChannels#method.set_fchannel]*
#[inline]
pub fn ncchannels_set_fchannel(channels: &mut NcChannels, fchannel: NcChannel) -> NcChannels {
*channels = (*channels & 0xffffffff_u64) | (fchannel as u64) << 32;
*channels
}
/// Combines two [`NcChannel`]s into an [`NcChannels`].
///
/// *Method: NcChannels.[combine()][NcChannels#method.combine]*
#[inline]
pub fn ncchannels_combine(fchannel: NcChannel, bchannel: NcChannel) -> NcChannels {
let mut channels: NcChannels = 0;
ncchannels_set_fchannel(&mut channels, fchannel);
ncchannels_set_bchannel(&mut channels, bchannel);
channels
}
// NcComponent ---------------------------------------------------------------------
/// Gets the red [`NcComponent`] from an [`NcChannel`].
///
/// *Method: NcChannel.[r()][NcChannel#method.r]*
#[inline]
pub const fn ncchannel_r(channel: NcChannel) -> NcComponent {
((channel & 0xff0000) >> 16) as NcComponent
}
/// Gets the green [`NcComponent`] from an [`NcChannel`].
///
/// *Method: NcChannel.[g()][NcChannel#method.g]*
#[inline]
pub const fn ncchannel_g(channel: NcChannel) -> NcComponent {
((channel & 0x00ff00) >> 8) as NcComponent
}
/// Gets the blue [`NcComponent`] from an [`NcChannel`].
///
/// *Method: NcChannel.[b()][NcChannel#method.b]*
#[inline]
pub const fn ncchannel_b(channel: NcChannel) -> NcComponent {
(channel & 0x0000ff) as NcComponent
}
/// Sets the red [`NcComponent`] of an [`NcChannel`], and returns it.
///
/// *Method: NcChannel.[set_r()][NcChannel#method.set_r]*
//
// Not in the C API.
#[inline]
pub fn ncchannel_set_r(channel: &mut NcChannel, r: NcComponent) -> NcChannel {
*channel = (r as NcChannel) << 16 | (*channel & 0xff00) | (*channel & 0xff);
*channel
}
/// Sets the green [`NcComponent`] of an [`NcChannel`], and returns it.
///
/// *Method: NcChannel.[set_g()][NcChannel#method.set_g]*
//
// Not in the C API.
#[inline]
pub fn ncchannel_set_g(channel: &mut NcChannel, g: NcComponent) -> NcChannel {
*channel = (*channel & 0xff0000) | (g as NcChannel) << 8 | (*channel & 0xff);
*channel
}
/// Sets the blue [`NcComponent`] of an [`NcChannel`], and returns it.
///
/// *Method: NcChannel.[set_b()][NcChannel#method.set_b]*
//
// Not in the C API.
#[inline]
pub fn ncchannel_set_b(channel: &mut NcChannel, b: NcComponent) -> NcChannel {
*channel = (*channel & 0xff0000) | (*channel & 0xff00) | (b as NcChannel);
*channel
}
/// Gets the three RGB [`NcComponent`]s from an [`NcChannel`], and returns it.
///
/// *Method: NcChannel.[rgb8()][NcChannel#method.rgb8]*
#[inline]
pub fn ncchannel_rgb8(
channel: NcChannel,
r: &mut NcComponent,
g: &mut NcComponent,
b: &mut NcComponent,
) -> NcChannel {
*r = ncchannel_r(channel);
*g = ncchannel_g(channel);
*b = ncchannel_b(channel);
channel
}
/// Sets the three RGB [`NcComponent`]s an [`NcChannel`], and marks it as NOT using the
/// "default color", retaining the other bits unchanged.
///
/// *Method: NcChannel.[set_rgb8()][NcChannel#method.set_rgb8]*
#[inline]
pub fn ncchannel_set_rgb8(channel: &mut NcChannel, r: NcComponent, g: NcComponent, b: NcComponent) {
let rgb: NcRgb = (r as NcChannel) << 16 | (g as NcChannel) << 8 | (b as NcChannel);
*channel = (*channel & !NCALPHA_BG_RGB_MASK) | NCALPHA_BGDEFAULT_MASK | rgb;
}
/// Gets the three foreground RGB [`NcComponent`]s from an [`NcChannels`], and
/// returns the foreground [`NcChannel`] (which can have some extra bits set).
///
/// *Method: NcChannels.[fg_rgb8()][NcChannels#method.fg_rgb8]*
#[inline]
pub fn ncchannels_fg_rgb8(
channels: NcChannels,
r: &mut NcComponent,
g: &mut NcComponent,
b: &mut NcComponent,
) -> NcChannel {
ncchannel_rgb8(ncchannels_fchannel(channels), r, g, b)
}
/// Gets the three background RGB [`NcComponent`]s from an [`NcChannels`], and
/// returns the background [`NcChannel`] (which can have some extra bits set).
///
/// *Method: NcChannels.[bg_rgb8()][NcChannels#method.bg_rgb8]*
#[inline]
pub fn ncchannels_bg_rgb8(
channels: NcChannels,
r: &mut NcComponent,
g: &mut NcComponent,
b: &mut NcComponent,
) -> NcChannel {
ncchannel_rgb8(ncchannels_bchannel(channels), r, g, b)
}
/// Sets the three foreground RGB [`NcComponent`]s of an [`NcChannels`], and
/// marks it as NOT using the "default color", retaining the other bits unchanged.
///
/// Unlike the original C API, it also returns the new NcChannels.
///
/// *Method: NcChannels.[set_fg_rgb8()][NcChannels#method.set_fg_rgb8]*
#[inline]
pub fn ncchannels_set_fg_rgb8(
channels: &mut NcChannels,
r: NcComponent,
g: NcComponent,
b: NcComponent,
) -> NcChannels {
let mut channel = ncchannels_fchannel(*channels);
ncchannel_set_rgb8(&mut channel, r, g, b);
*channels = (channel as u64) << 32 | *channels & 0xffffffff_u64;
*channels
}
/// Sets the three background RGB [`NcComponent`]s of an [`NcChannels`], and
/// marks it as NOT using the "default color", retaining the other bits unchanged.
///
/// Unlike the original C API, it also returns the new NcChannels.
///
/// *Method: NcChannels.[set_bg_rgb8()][NcChannels#method.set_bg_rgb8]*
#[inline]
pub fn ncchannels_set_bg_rgb8(
channels: &mut NcChannels,
r: NcComponent,
g: NcComponent,
b: NcComponent,
) -> NcChannels {
let mut channel = ncchannels_bchannel(*channels);
ncchannel_set_rgb8(&mut channel, r, g, b);
ncchannels_set_bchannel(channels, channel);
*channels
}
// NcRgb -----------------------------------------------------------------------
/// Gets the foreground [`NcRgb`] from an [`NcChannels`], shifted to LSBs.
///
/// *Method: NcChannels.[fg_rgb()][NcChannels#method.fg_rgb]*
#[inline]
pub fn ncchannels_fg_rgb(channels: NcChannels) -> NcRgb {
ncchannels_fchannel(channels) & NCALPHA_BG_RGB_MASK
}
/// Gets the background [`NcRgb`] from an [`NcChannels`], shifted to LSBs.
///
/// *Method: NcChannels.[bg_rgb()][NcChannels#method.bg_rgb]*
#[inline]
pub fn ncchannels_bg_rgb(channels: NcChannels) -> NcRgb {
ncchannels_bchannel(channels) & NCALPHA_BG_RGB_MASK
}
/// Gets the [`NcRgb`] of an [`NcChannel`].
///
/// This function basically removes the 4th byte of the NcChannel.
///
/// *Method: NcChannel.[rgb()][NcChannel#method.rgb]*
//
// Not in the C API
#[inline]
pub const fn ncchannel_rgb(channel: NcChannel) -> NcRgb {
channel & NCALPHA_BG_RGB_MASK
}
/// Sets the [`NcRgb`] of an [`NcChannel`], and marks it as NOT using the
/// "default color", retaining the other bits unchanged.
///
/// *Method: NcChannel.[set()][NcChannel#method.set]*
#[inline]
pub fn ncchannel_set(channel: &mut NcChannel, rgb: NcRgb) {
*channel = (*channel & !NCALPHA_BG_RGB_MASK) | NCALPHA_BGDEFAULT_MASK | (rgb & 0x00ffffff);
}
/// Sets the foreground [`NcRgb`] of an [`NcChannels`], and marks it as NOT using
/// the "default color", retaining the other bits unchanged.
///
/// *Method: NcChannels.[set_fg_rgb()][NcChannels#method.set_fg_rgb]*
#[inline]
pub fn ncchannels_set_fg_rgb(channels: &mut NcChannels, rgb: NcRgb) {
let mut channel = ncchannels_fchannel(*channels);
ncchannel_set(&mut channel, rgb);
*channels = (channel as u64) << 32 | *channels & 0xffffffff_u64;
}
/// Sets the foreground [`NcRgb`] of an [`NcChannels`], and marks it as NOT using
/// the "default color", retaining the other bits unchanged.
///
/// *Method: NcChannels.[set_bg_rgb()][NcChannels#method.set_bg_rgb]*
#[inline]
pub fn ncchannels_set_bg_rgb(channels: &mut NcChannels, rgb: NcRgb) {
let mut channel = ncchannels_bchannel(*channels);
ncchannel_set(&mut channel, rgb);
ncchannels_set_bchannel(channels, channel);
}
// Default ---------------------------------------------------------------------
/// Is this [`NcChannel`] using the "default color" rather than RGB/palette-indexed?
///
/// *Method: NcChannel.[default_p()][NcChannel#method.default_p]*
#[inline]
pub const fn ncchannel_default_p(channel: NcChannel) -> bool {
(channel & NCALPHA_BGDEFAULT_MASK) == 0
}
/// Marks an [`NcChannel`] as using its "default color", which also marks it opaque.
///
/// *Method: NcChannel.[set_default()][NcChannel#method.set_default]*
#[inline]
pub fn ncchannel_set_default(channel: &mut NcChannel) -> NcChannel {
*channel &= !(NCALPHA_BGDEFAULT_MASK | NCALPHA_HIGHCONTRAST);
*channel
}
/// Marks an [`NcChannel`] as NOT using its "default color",
/// retaining the other bits unchanged.
///
/// *Method: NcChannel.[set_not_default()][NcChannel#method.set_not_default]*
//
// Not in the C API
#[inline]
pub fn ncchannel_set_not_default(channel: &mut NcChannel) -> NcChannel {
*channel |= NCALPHA_BGDEFAULT_MASK;
*channel
}
/// Is the foreground of an [`NcChannels`] using the "default foreground color"?
///
/// *Method: NcChannels.[fg_default_p()][NcChannels#method.fg_default_p]*
#[inline]
pub fn ncchannels_fg_default_p(channels: NcChannels) -> bool {
ncchannel_default_p(ncchannels_fchannel(channels))
}
/// Is the background using the "default background color"?
///
/// The "default background color" must generally be used to take advantage of
/// terminal-effected transparency.
///
/// *Method: NcChannels.[bg_default_p()][NcChannels#method.bg_default_p]*
#[inline]
pub fn ncchannels_bg_default_p(channels: NcChannels) -> bool {
ncchannel_default_p(ncchannels_bchannel(channels))
}
/// Marks the foreground of an [`NcChannels`] as using its "default color",
/// which also marks it opaque, and returns the new [`NcChannels`].
///
/// *Method: NcChannels.[set_fg_default()][NcChannels#method.set_fg_default]*
#[inline]
pub fn ncchannels_set_fg_default(channels: &mut NcChannels) -> NcChannels {
let mut channel = ncchannels_fchannel(*channels);
ncchannel_set_default(&mut channel);
*channels = (channel as u64) << 32 | *channels & 0xffffffff_u64;
*channels
}
/// Marks the foreground of an [`NcChannels`] as NOT using its "default color",
/// retaining the other bits unchanged, and returns the new [`NcChannels`].
///
/// *Method: NcChannels.[set_fg_not_default()][NcChannels#method.set_fg_not_default]*
//
// Not in the C API
#[inline]
pub fn ncchannels_set_fg_not_default(channels: &mut NcChannels) -> NcChannels {
let mut channel = ncchannels_fchannel(*channels);
ncchannel_set_not_default(&mut channel);
*channels = (channel as u64) << 32 | *channels & 0xffffffff_u64;
*channels
}
/// Marks the background of an [`NcChannels`] as using its "default color",
/// which also marks it opaque, and returns the new [`NcChannels`].
///
/// *Method: NcChannels.[set_bg_default()][NcChannels#method.set_bg_default]*
#[inline]
pub fn ncchannels_set_bg_default(channels: &mut NcChannels) -> NcChannels {
let mut channel = ncchannels_bchannel(*channels);
ncchannel_set_default(&mut channel);
ncchannels_set_bchannel(channels, channel);
*channels
}
/// Marks the background of an [`NcChannels`] as NOT using its "default color",
/// retaining the other bits unchanged, and returns the new [`NcChannels`].
///
/// *Method: NcChannels.[set_bg_not_default()][NcChannels#method.set_bg_not_default]*
//
// Not in the C API
#[inline]
pub fn ncchannels_set_bg_not_default(channels: &mut NcChannels) -> NcChannels {
let mut channel = ncchannels_bchannel(*channels);
ncchannel_set_not_default(&mut channel);
ncchannels_set_bchannel(channels, channel);
*channels
}
/// Marks both the foreground and background of an [`NcChannels`] as using their
/// "default color", which also marks them opaque, and returns the new [`NcChannels`].
///
/// *Method: NcChannels.[set_default()][NcChannels#method.set_default]*
//
// Not in the C API
#[inline]
pub fn ncchannels_set_default(channels: &mut NcChannels) -> NcChannels {
ncchannels_set_bg_default(&mut ncchannels_set_fg_default(channels))
}
/// Marks both the foreground and background of an [`NcChannels`] as NOT using their
/// "default color", retaining the other bits unchanged, and returns the new [`NcChannels`].
///
/// *Method: NcChannels.[set_not_default()][NcChannels#method.set_not_default]*
//
// Not in the C API
#[inline]
pub fn ncchannels_set_not_default(channels: &mut NcChannels) -> NcChannels {
ncchannels_set_bg_not_default(&mut ncchannels_set_fg_not_default(channels))
}
// Palette ---------------------------------------------------------------------
/// Is this [`NcChannel`] using palette-indexed color rather than RGB?
///
/// *Method: NcChannel.[palindex_p()][NcChannel#method.palindex_p]*
#[inline]
pub fn ncchannel_palindex_p(channel: NcChannel) -> bool {
!(ncchannel_default_p(channel) && (channel & NCALPHA_BG_PALETTE) == 0)
}
/// Is the foreground of an [`NcChannels`] using an [indexed][`NcPaletteIndex`]
/// [`NcPalette`][crate::NcPalette] color?
///
/// *Method: NcChannels.[fg_palindex_p()][NcChannels#method.fg_palindex_p]*
#[inline]
pub fn ncchannels_fg_palindex_p(channels: NcChannels) -> bool {
ncchannel_palindex_p(ncchannels_fchannel(channels))
}
/// Is the background of an [`NcChannels`] using an [indexed][`NcPaletteIndex`]
/// [`NcPalette`][crate::NcPalette] color?
///
/// *Method: NcChannels.[bg_palindex_p()][NcChannels#method.bg_palindex_p]*
#[inline]
pub fn ncchannels_bg_palindex_p(channels: NcChannels) -> bool {
ncchannel_palindex_p(ncchannels_bchannel(channels))
}
/// Sets the foreground of an [`NcChannels`] as using an
/// [indexed][`NcPaletteIndex`] [`NcPalette`][crate::NcPalette] color.
///
/// *Method: NcChannels.[set_fg_palindex()][NcChannels#method.set_fg_palindex]*
#[inline]
#[allow(clippy::unnecessary_cast)]
pub fn ncchannels_set_fg_palindex(channels: &mut NcChannels, index: NcPaletteIndex) {
*channels |= NCALPHA_FGDEFAULT_MASK;
*channels |= NCALPHA_FG_PALETTE as NcChannels;
ncchannels_set_fg_alpha(channels, NCALPHA_OPAQUE);
*channels &= 0xff000000ffffffff as NcChannels;
*channels |= (index as NcChannels) << 32;
}
/// Sets the background of an [`NcChannels`] as using an
/// [indexed][`NcPaletteIndex`] [`NcPalette`][crate::NcPalette] color.
///
/// *Method: NcChannels.[set_bg_palindex()][NcChannels#method.set_bg_palindex]*
#[inline]
pub fn ncchannels_set_bg_palindex(channels: &mut NcChannels, index: NcPaletteIndex) {
*channels |= NCALPHA_BGDEFAULT_MASK as NcChannels;
*channels |= NCALPHA_BG_PALETTE as NcChannels;
ncchannels_set_bg_alpha(channels, NCALPHA_OPAQUE);
*channels &= 0xffffffffff000000;
*channels |= index as NcChannels;
}

@ -1,10 +0,0 @@
//! Test `NcChannel*` methods and associated functions.
// use crate::{NcChannel, NcChannels};
//
// use serial_test::serial;
//
// #[test]
// #[serial]
// fn () {
// }

@ -1,7 +0,0 @@
//! `NcChannel*` tests.
#[cfg(test)]
mod methods;
#[cfg(test)]
mod reimplemented;

@ -1,226 +0,0 @@
//! Test `channel*_*` reimplemented functions.
use serial_test::serial;
use crate::{
NcChannel, NcChannels, NCALPHA_BLEND, NCALPHA_HIGHCONTRAST, NCALPHA_OPAQUE, NCALPHA_TRANSPARENT,
};
// NcChannel tests -------------------------------------------------------------
/// retrieves the red NcComponent component
#[test]
#[serial]
fn channel_r() {
let c: NcChannel = 0x112233;
assert_eq!(crate::ncchannel_r(c), 0x11);
}
/// retrieves the green NcComponent component
#[test]
#[serial]
fn channel_g() {
let c: NcChannel = 0x112233;
assert_eq!(crate::ncchannel_g(c), 0x22);
}
/// retrieves the blue NcComponent component
#[test]
#[serial]
fn channel_b() {
let c: NcChannel = 0x112233;
assert_eq!(crate::ncchannel_b(c), 0x33);
}
/// writes out the three RGB NcComponent components
#[test]
#[serial]
fn channel_rgb8() {
let c: NcChannel = 0x112233;
let mut r = 0;
let mut g = 0;
let mut b = 0;
crate::ncchannel_rgb8(c, &mut r, &mut g, &mut b);
assert_eq!(r, 0x11);
assert_eq!(g, 0x22);
assert_eq!(b, 0x33);
}
/// sets the three RGB NcComponent components
#[test]
#[serial]
fn channel_set_rgb8() {
let mut c = 0x000000;
// by default it uses the default color
assert_eq!(true, crate::ncchannel_default_p(c));
crate::ncchannel_set_rgb8(&mut c, 0x11, 0x22, 0x33);
assert_eq!(crate::ncchannel_r(c), 0x11);
assert_eq!(crate::ncchannel_g(c), 0x22);
assert_eq!(crate::ncchannel_b(c), 0x33);
// now it shoud be marked as NOT using the default color
assert_eq!(false, crate::ncchannel_default_p(c));
}
/// sets the NcRGB color components
#[test]
#[serial]
fn channel_set() {
let mut c = 0x000000;
// by default it uses the default color
assert_eq!(true, crate::ncchannel_default_p(c));
crate::ncchannel_set(&mut c, 0x112233);
println!("\n {:08x}", c); // DEBUG
assert_eq!(crate::ncchannel_r(c), 0x11);
assert_eq!(crate::ncchannel_g(c), 0x22);
assert_eq!(crate::ncchannel_b(c), 0x33);
// now it shoud be marked as NOT using the default color
assert_eq!(false, crate::ncchannel_default_p(c));
}
/// gets the alpha component
#[test]
#[serial]
fn channel_alpha() {
let c: NcChannel = 0x112233;
assert_ne!(crate::ncchannel_alpha(c), NCALPHA_TRANSPARENT);
let c: NcChannel = 0x112233 | NCALPHA_TRANSPARENT;
assert_eq!(crate::ncchannel_alpha(c), NCALPHA_TRANSPARENT);
}
/// sets the alpha component
#[test]
#[serial]
fn channel_set_alpha() {
let mut c: NcChannel = 0x112233;
crate::ncchannel_set_alpha(&mut c, NCALPHA_HIGHCONTRAST);
assert_eq!(NCALPHA_HIGHCONTRAST, crate::ncchannel_alpha(c));
crate::ncchannel_set_alpha(&mut c, NCALPHA_TRANSPARENT);
assert_eq!(NCALPHA_TRANSPARENT, crate::ncchannel_alpha(c));
crate::ncchannel_set_alpha(&mut c, NCALPHA_BLEND);
assert_eq!(NCALPHA_BLEND, crate::ncchannel_alpha(c));
crate::ncchannel_set_alpha(&mut c, NCALPHA_OPAQUE);
assert_eq!(NCALPHA_OPAQUE, crate::ncchannel_alpha(c));
// TODO: CHECK for NCALPHA_BGDEFAULT_MASK
}
/// sets the channel as using the default color
#[test]
#[serial]
fn channel_set_default() {
let channel = 0x_00_112233;
// By default a channel uses the default color, if the proper bit isn't set
assert_eq!(true, crate::ncchannel_default_p(channel));
// If we change it from being opaque...
let mut channel_transp = channel | NCALPHA_TRANSPARENT;
assert_eq!(0x_20_112233, channel_transp); // the transparent bit is now set
crate::ncchannel_set_not_default(&mut channel_transp);
// both the "not default" & transparent bits are now set
assert_eq!(0x_60_112233, channel_transp);
// and calling set_default() should make it both default & opaque again
assert_eq!(
0x_00_112233,
crate::ncchannel_set_default(&mut channel_transp)
);
}
/// sets the channel as *not* using the default color
//
// more functions that marks as NOT using the default color:
// - channel_set()
// - channel_set_rgb8()
#[test]
#[serial]
fn channel_set_not_default() {
let mut channel = 0x_00_112233;
// By default a channel uses the default color, if the proper bit isn't set
assert_eq!(true, crate::ncchannel_default_p(channel));
// marking it as NOT using the default color
crate::ncchannel_set_not_default(&mut channel);
assert_eq!(0x_40_112233, channel); // check the "not default" bit is set
assert_eq!(false, crate::ncchannel_default_p(channel));
}
/// checks whether the channel is using the default color
#[test]
#[serial]
fn channel_default_p() {
let mut c: NcChannel = 0x112233;
assert_eq!(true, crate::ncchannel_default_p(c));
let _ = crate::ncchannel_set_alpha(&mut c, NCALPHA_OPAQUE);
assert_eq!(true, crate::ncchannel_default_p(c));
crate::ncchannel_set(&mut c, 0x112233);
assert_eq!(false, crate::ncchannel_default_p(c));
}
// NcChannels tests ---------------------------------------------------------
///
#[test]
#[serial]
#[allow(non_snake_case)]
fn channels_set_fchannel__channels_fchannel() {
let fc: NcChannel = 0x112233;
let mut cp: NcChannels = 0;
crate::ncchannels_set_fchannel(&mut cp, fc);
assert_eq!(crate::ncchannels_fchannel(cp), fc);
}
///
#[test]
#[serial]
#[allow(non_snake_case)]
fn channels_set_bchannel__channels_bchannel() {
let bc: NcChannel = 0x112233;
let mut cp: NcChannels = 0;
crate::ncchannels_set_bchannel(&mut cp, bc);
assert_eq!(crate::ncchannels_bchannel(cp), bc);
}
///
#[test]
#[serial]
fn channels_combine() {
let bc: NcChannel = 0x112233;
let fc: NcChannel = 0x445566;
let mut cp1: NcChannels = 0;
let mut _cp2: NcChannels = 0;
crate::ncchannels_set_bchannel(&mut cp1, bc);
crate::ncchannels_set_fchannel(&mut cp1, fc);
_cp2 = crate::ncchannels_combine(fc, bc);
assert_eq!(cp1, _cp2);
}
///
#[test]
#[serial]
fn channels_palette() {
let bc: NcChannel = 0x112233;
let fc: NcChannel = 0x445566;
assert_eq!(false, crate::ncchannel_palindex_p(bc));
assert_eq!(false, crate::ncchannel_palindex_p(fc));
let mut channels = crate::ncchannels_combine(fc, bc);
assert_eq!(false, crate::ncchannels_fg_palindex_p(channels));
assert_eq!(false, crate::ncchannels_bg_palindex_p(channels));
crate::ncchannels_set_fg_palindex(&mut channels, 5);
crate::ncchannels_set_bg_palindex(&mut channels, 6);
assert_eq!(true, crate::ncchannels_fg_palindex_p(channels));
assert_eq!(true, crate::ncchannels_bg_palindex_p(channels));
}

@ -1,7 +0,0 @@
//! `NcDim`, `NcOffset`
/// Represents a dimension in rows or columns. Can't be negative.
pub type NcDim = u32;
/// Represents an offset in rows or columns. Can be negative.
pub type NcOffset = i32;

@ -1,767 +0,0 @@
//! `NcDirect` methods and associated functions.
use core::ptr::{null, null_mut};
use crate::{
cstring, error, error_ref_mut, rstring, NcAlign, NcBlitter, NcCapabilities, NcChannels,
NcComponent, NcDim, NcDirect, NcDirectFlags, NcError, NcInput, NcOffset, NcPaletteIndex,
NcPlane, NcResult, NcRgb, NcScale, NcStyle, NcTime, NCRESULT_ERR,
};
/// # `NcDirect` constructors and destructors
impl NcDirect {
/// New NcDirect with the default options.
///
/// Initializes a direct-mode notcurses context on the tty.
///
/// Direct mode supports a limited subset of notcurses routines,
/// and neither supports nor requires
/// [notcurses_render()][crate::notcurses_render]. This can be used to add
/// color and styling to text in the standard output paradigm.
///
/// *C style function: [ncdirect_init()][crate::ncdirect_init].*
pub fn new<'a>() -> NcResult<&'a mut NcDirect> {
Self::with_flags(0)
}
/// New NcDirect with optional flags.
///
/// `flags` is a bitmask over:
/// - [NCDIRECT_OPTION_INHIBIT_CBREAK][crate::NCDIRECT_OPTION_INHIBIT_CBREAK]
/// - [NCDIRECT_OPTION_INHIBIT_SETLOCALE][crate::NCDIRECT_OPTION_INHIBIT_SETLOCALE]
/// - [NCDIRECT_OPTION_NO_QUIT_SIGHANDLERS][crate::NCDIRECT_OPTION_NO_QUIT_SIGHANDLERS]
/// - [NCDIRECT_OPTION_VERBOSE][crate::NCDIRECT_OPTION_VERBOSE]
/// - [NCDIRECT_OPTION_VERY_VERBOSE][crate::NCDIRECT_OPTION_VERY_VERBOSE]
///
/// *C style function: [ncdirect_init()][crate::ncdirect_init].*
pub fn with_flags<'a>(flags: NcDirectFlags) -> NcResult<&'a mut NcDirect> {
let res = unsafe { crate::ncdirect_init(null(), null_mut(), flags) };
error_ref_mut![res, "Initializing NcDirect"]
}
/// Releases this NcDirect and any associated resources.
///
/// *C style function: [ncdirect_stop()][crate::ncdirect_stop].*
pub fn stop(&mut self) -> NcResult<()> {
error![unsafe { crate::ncdirect_stop(self) }, "NcDirect.stop()"]
}
}
/// ## NcDirect methods: clear, flush, render
impl NcDirect {
/// Clears the screen.
///
/// *C style function: [ncdirect_clear()][crate::ncdirect_clear].*
pub fn clear(&mut self) -> NcResult<()> {
error![unsafe { crate::ncdirect_clear(self) }, "NcDirect.clear()"]
}
/// Forces a flush.
///
/// *C style function: [ncdirect_flush()][crate::ncdirect_flush].*
pub fn flush(&self) -> NcResult<()> {
error![unsafe { crate::ncdirect_flush(self) }, "NcDirect.clear()"]
}
/// Takes the result of [`render_frame`][NcDirect#method.render_frame]
/// and writes it to the output.
///
/// *C style function: [ncdirect_raster_frame()][crate::ncdirect_raster_frame].*
pub fn raster_frame(&mut self, frame: &mut NcPlane, align: NcAlign) -> NcResult<()> {
error![
unsafe { crate::ncdirect_raster_frame(self, frame, align) },
"NcDirect.raster_frame()"
]
}
/// Renders an image using the specified blitter and scaling,
/// but doesn't write the result.
///
/// The image may be arbitrarily many rows -- the output will scroll --
/// but will only occupy the column of the cursor, and those to the right.
///
/// To actually write (and free) this, invoke ncdirect_raster_frame().
///
/// `max_y' and 'max_x` (cell geometry, *not* pixel), if greater than 0,
/// are used for scaling; the terminal's geometry is otherwise used.
///
/// *C style function: [ncdirect_render_frame()][crate::ncdirect_render_frame].*
pub fn render_frame<'a>(
&mut self,
filename: &str,
blitter: NcBlitter,
scale: NcScale,
max_y: NcDim,
max_x: NcDim,
) -> NcResult<&'a mut NcPlane> {
let res = unsafe {
crate::ncdirect_render_frame(
self,
cstring![filename],
blitter,
scale,
max_y as i32,
max_x as i32,
)
};
error_ref_mut![
res,
&format!(
"NcDirect.render_frame({:?}, {:?}, {:?})",
filename, blitter, scale
)
]
}
/// Displays an image using the specified blitter and scaling.
///
/// The image may be arbitrarily many rows -- the output will scroll -- but
/// will only occupy the column of the cursor, and those to the right.
///
/// The render/raster process can be split by using
/// [render_frame()][#method.render_frame] and
/// [raster_frame()][#method.raster_frame].
///
/// *C style function: [ncdirect_render_image()][crate::ncdirect_render_image].*
pub fn render_image(
&mut self,
filename: &str,
align: NcAlign,
blitter: NcBlitter,
scale: NcScale,
) -> NcResult<()> {
error![
unsafe {
crate::ncdirect_render_image(self, cstring![filename], align, blitter, scale)
},
&format!(
"NcDirect.render_image({:?}, {:?}, {:?}, {:?})",
filename, align, blitter, scale
)
]
}
}
/// ## NcDirect methods: `NcPaletteIndex`, `NcRgb`, `NcStyle` & default color
impl NcDirect {
/// Sets the foreground [NcPaletteIndex].
///
/// *C style function: [ncdirect_set_fg_palindex()][crate::ncdirect_set_fg_palindex].*
pub fn set_fg_palindex(&mut self, index: NcPaletteIndex) -> NcResult<()> {
error![
unsafe { crate::ncdirect_set_fg_palindex(self, index as i32) },
&format!("NcDirect.set_fg_palindex({})", index)
]
}
/// Sets the background [NcPaletteIndex].
///
/// *C style function: [ncdirect_set_bg_palindex()][crate::ncdirect_set_bg_palindex].*
pub fn set_bg_palindex(&mut self, index: NcPaletteIndex) -> NcResult<()> {
error![
unsafe { crate::ncdirect_set_bg_palindex(self, index as i32) },
&format!("NcDirect.set_fg_palindex({})", index)
]
}
/// Returns the number of simultaneous colors claimed to be supported,
/// if there is color support.
///
/// Note that several terminal emulators advertise more colors than they
/// actually support, downsampling internally.
///
/// *C style function: [ncdirect_palette_size()][crate::ncdirect_palette_size].*
pub fn palette_size(&self) -> NcResult<u32> {
let res = unsafe { crate::ncdirect_palette_size(self) };
if res == 1 {
return Err(NcError::with_msg(
1,
"No color support ← NcDirect.palette_size()",
));
}
Ok(res)
}
/// Sets the foreground [NcRgb].
///
/// *C style function: [ncdirect_set_fg_rgb()][crate::ncdirect_set_fg_rgb].*
pub fn set_fg_rgb(&mut self, rgb: NcRgb) -> NcResult<()> {
error![
unsafe { crate::ncdirect_set_fg_rgb(self, rgb) },
&format!("NcDirect.set_fg_rgb({})", rgb)
]
}
/// Sets the background [NcRgb].
///
/// *C style function: [ncdirect_set_bg_rgb()][crate::ncdirect_set_bg_rgb].*
pub fn set_bg_rgb(&mut self, rgb: NcRgb) -> NcResult<()> {
error![
unsafe { crate::ncdirect_set_bg_rgb(self, rgb) },
&format!("NcDirect.set_bg_rgb({})", rgb)
]
}
/// Sets the foreground [NcComponent] components.
///
/// *C style function: [ncdirect_set_fg_rgb8()][crate::ncdirect_set_fg_rgb8].*
pub fn set_fg_rgb8(
&mut self,
red: NcComponent,
green: NcComponent,
blue: NcComponent,
) -> NcResult<()> {
error![
crate::ncdirect_set_fg_rgb8(self, red, green, blue),
&format!("NcDirect.set_fg_rgb8({}, {}, {})", red, green, blue)
]
}
/// Sets the background [NcComponent] components.
///
/// *C style function: [ncdirect_set_bg_rgb()][crate::ncdirect_set_bg_rgb].*
pub fn set_bg_rgb8(
&mut self,
red: NcComponent,
green: NcComponent,
blue: NcComponent,
) -> NcResult<()> {
error![
crate::ncdirect_set_bg_rgb8(self, red, green, blue),
&format!("NcDirect.set_bg_rgb8({}, {}, {})", red, green, blue)
]
}
/// Removes the specified styles.
///
/// *C style function: [ncdirect_off_styles()][crate::ncdirect_off_styles].*
pub fn styles_off(&mut self, stylebits: NcStyle) -> NcResult<()> {
error![
unsafe { crate::ncdirect_off_styles(self, stylebits.into()) },
&format!("NcDirect.styles_off({:0X})", stylebits)
]
}
/// Adds the specified styles.
///
/// *C style function: [ncdirect_on_styles()][crate::ncdirect_on_styles].*
pub fn styles_on(&mut self, stylebits: NcStyle) -> NcResult<()> {
error![
unsafe { crate::ncdirect_on_styles(self, stylebits.into()) },
&format!("NcDirect.styles_on({:0X})", stylebits)
]
}
/// Sets just the specified styles.
///
/// *C style function: [ncdirect_set_styles()][crate::ncdirect_set_styles].*
pub fn styles_set(&mut self, stylebits: NcStyle) -> NcResult<()> {
error![
unsafe { crate::ncdirect_set_styles(self, stylebits.into()) },
&format!("NcDirect.styles_set({:0X})", stylebits)
]
}
/// Indicates to use the "default color" for the foreground.
///
/// *C style function: [ncdirect_set_fg_default()][crate::ncdirect_set_fg_default].*
pub fn set_fg_default(&mut self) -> NcResult<()> {
error![
unsafe { crate::ncdirect_set_fg_default(self) },
"NcDirect.set_fg_default()"
]
}
/// Indicates to use the "default color" for the background.
///
/// *C style function: [ncdirect_set_bg_default()][crate::ncdirect_set_bg_default].*
pub fn set_bg_default(&mut self) -> NcResult<()> {
error![
unsafe { crate::ncdirect_set_bg_default(self) },
"NcDirect.set_bg_default()"
]
}
}
/// ## NcDirect methods: capabilities, cursor, dimensions
impl NcDirect {
/// Is there support for acquiring the cursor's current position?
///
/// Requires the u7 terminfo capability, and that we are connected to an
/// actual terminal.
pub fn canget_cursor(&self) -> bool {
unsafe { crate::ncdirect_canget_cursor(self) }
}
/// Can we reliably use Unicode braille?
///
/// *C style function: [ncdirect_canbraille()][crate::ncdirect_canbraille].*
pub fn canbraille(&self) -> bool {
crate::ncdirect_canbraille(self)
}
/// Can we set the "hardware" palette?
///
/// Requires the "ccc" terminfo capability.
///
/// *C style function: [ncdirect_canchangecolor()][crate::ncdirect_canchangecolor].*
pub fn canchangecolor(&self) -> bool {
crate::ncdirect_canchangecolor(self)
}
/// Can we fade?
///
/// Requires either the "rgb" or "ccc" terminfo capability.
///
/// *C style function: [ncdirect_canfade()][crate::ncdirect_canfade].*
pub fn canfade(&self) -> bool {
crate::ncdirect_canfade(self)
}
/// Can we reliably use Unicode halfblocks?
///
/// *C style function: [ncdirect_canhalfblock()][crate::ncdirect_canhalfblock].*
pub fn canhalfblock(&self) -> bool {
crate::ncdirect_canhalfblock(self)
}
/// Can we load images?
///
/// Requires being built against FFmpeg/OIIO.
///
/// *C style function: [ncdirect_canopen_images()][crate::ncdirect_canopen_images].*
pub fn canopen_images(&self) -> bool {
unsafe { crate::ncdirect_canopen_images(self) }
}
/// Can we load videos?
///
/// Requires being built against FFmpeg/OIIO.
///
/// *C style function: [ncdirect_canopen_videos()][crate::ncdirect_canopen_videos].*
pub fn canopen_videos(&self) -> bool {
crate::ncdirect_canopen_videos(self)
}
/// Can we reliably use Unicode quadrants?
///
/// *C style function: [ncdirect_canquadrant()][crate::ncdirect_canquadrant].*
pub fn canquadrant(&self) -> bool {
crate::ncdirect_canquadrant(self)
}
/// Can we reliably use Unicode sextants?
///
/// *C style function: [ncdirect_cansextant()][crate::ncdirect_cansextant].*
pub fn cansextant(&self) -> bool {
crate::ncdirect_cansextant(self)
}
/// Can we directly specify RGB values per cell, or only use palettes?
///
/// *C style function: [ncdirect_cantruecolor()][crate::ncdirect_cantruecolor].*
pub fn cantruecolor(&self) -> bool {
crate::ncdirect_cantruecolor(self)
}
/// Is our encoding UTF-8?
///
/// Requires LANG being set to a UTF8 locale.
///
/// *C style function: [ncdirect_canutf8()][crate::ncdirect_canutf8].*
pub fn canutf8(&self) -> bool {
unsafe { crate::ncdirect_canutf8(self) }
}
/// Returns the [`NcCapabilities`].
///
/// *C style function: [ncdirect_capabilities()][crate::ncdirect_capabilities].*
pub fn capabilities(&self) -> NcCapabilities {
crate::ncdirect_capabilities(self)
}
/// Checks for pixel support.
///
/// Returns `false` for no support, or `true` if pixel output is supported.
///
/// This function must successfully return before NCBLIT_PIXEL is available.
///
/// Must not be called concurrently with either input or rasterization.
///
/// *C style function: [ncdirect_check_pixel_support()][crate::ncdirect_check-pixel_support].*
#[allow(clippy::wildcard_in_or_patterns)]
pub fn check_pixel_support(&self) -> NcResult<bool> {
let res = unsafe { crate::ncdirect_check_pixel_support(self) };
match res {
0 => Ok(false),
1 => Ok(true),
NCRESULT_ERR | _ => Err(NcError::with_msg(res, "NcDirect.check_pixel_support()")),
}
}
/// Disables the terminal's cursor, if supported.
///
/// *C style function: [ncdirect_cursor_disable()][crate::ncdirect_cursor_disable].*
pub fn cursor_disable(&mut self) -> NcResult<()> {
error![
unsafe { crate::ncdirect_cursor_disable(self) },
"NcDirect.cursor_disable()"
]
}
/// Enables the terminal's cursor, if supported.
///
/// *C style function: [ncdirect_cursor_enable()][crate::ncdirect_cursor_enable].*
pub fn cursor_enable(&mut self) -> NcResult<()> {
error![
unsafe { crate::ncdirect_cursor_enable(self) },
"NcDirect.cursor_enable()"
]
}
/// Moves the cursor down any number of rows.
///
/// *C style function: [ncdirect_cursor_down()][crate::ncdirect_cursor_down].*
pub fn cursor_down(&mut self, rows: NcOffset) -> NcResult<()> {
error![
unsafe { crate::ncdirect_cursor_down(self, rows as i32) },
&format!("NcDirect.cursor_down({})", rows)
]
}
/// Moves the cursor left any number of columns.
///
/// *C style function: [ncdirect_cursor_left()][crate::ncdirect_cursor_left].*
pub fn cursor_left(&mut self, cols: NcOffset) -> NcResult<()> {
error![
unsafe { crate::ncdirect_cursor_left(self, cols as i32) },
&format!("NcDirect.cursor_left({})", cols)
]
}
/// Moves the cursor right any number of columns.
///
/// *C style function: [ncdirect_cursor_right()][crate::ncdirect_cursor_right].*
pub fn cursor_right(&mut self, cols: NcOffset) -> NcResult<()> {
error![
unsafe { crate::ncdirect_cursor_right(self, cols as i32) },
&format!("NcDirect.cursor_right({})", cols)
]
}
/// Moves the cursor up any number of rows.
///
/// *C style function: [ncdirect_cursor_up()][crate::ncdirect_cursor_up].*
pub fn cursor_up(&mut self, rows: NcOffset) -> NcResult<()> {
error![
unsafe { crate::ncdirect_cursor_up(self, rows as i32) },
&format!("NcDirect.cursor_up({})", rows)
]
}
/// Sets the cursor to the specified row `y`, column `x`.
///
/// *C style function: [ncdirect_cursor_move_yx()][crate::ncdirect_cursor_move_yx].*
pub fn cursor_set_yx(&mut self, y: NcDim, x: NcDim) -> NcResult<()> {
error![unsafe { crate::ncdirect_cursor_move_yx(self, y as i32, x as i32) }]
}
/// Sets the cursor to the specified row `y`.
///
/// *(No equivalent C style function)*
pub fn cursor_set_y(&mut self, y: NcDim) -> NcResult<()> {
error![unsafe { crate::ncdirect_cursor_move_yx(self, y as i32, -1) }]
}
/// Sets the cursor to the specified column `x`.
///
/// *(No equivalent C style function)*
pub fn cursor_set_x(&mut self, x: NcDim) -> NcResult<()> {
error![unsafe { crate::ncdirect_cursor_move_yx(self, -1, x as i32) }]
}
/// Gets the cursor (y, x) position, when supported.
///
/// This requires writing to the terminal, and then reading from it.
/// If the terminal doesn't reply, or doesn't reply in a way we understand,
/// the results might be detrimental.
///
/// *C style function: [ncdirect_cursor_yx()][crate::ncdirect_cursor_yx].*
pub fn cursor_yx(&mut self) -> NcResult<(NcDim, NcDim)> {
let (mut y, mut x) = (0, 0);
error![
unsafe { crate::ncdirect_cursor_yx(self, &mut y, &mut x) },
"",
(y as NcDim, x as NcDim)
]
}
/// Pushes the cursor location to the terminal's stack.
///
/// The depth of this stack, and indeed its existence, is terminal-dependent.
///
/// *C style function: [ncdirect_cursor_push()][crate::ncdirect_cursor_push].*
pub fn cursor_push(&mut self) -> NcResult<()> {
error![unsafe { crate::ncdirect_cursor_push(self) }]
}
/// Pops the cursor location from the terminal's stack.
///
/// The depth of this stack, and indeed its existence, is terminal-dependent.
///
/// *C style function: [ncdirect_cursor_pop()][crate::ncdirect_cursor_pop].*
pub fn cursor_pop(&mut self) -> NcResult<()> {
error![unsafe { crate::ncdirect_cursor_pop(self) }]
}
/// Gets the current number of rows.
///
/// *C style function: [ncdirect_dim_y()][crate::ncdirect_dim_y].*
pub fn dim_y(&mut self) -> NcDim {
unsafe { crate::ncdirect_dim_y(self) as NcDim }
}
/// Gets the current number of columns.
///
/// *C style function: [ncdirect_dim_x()][crate::ncdirect_dim_x].*
pub fn dim_x(&mut self) -> NcDim {
unsafe { crate::ncdirect_dim_x(self) as NcDim }
}
/// Gets the current number of rows and columns.
///
/// *C style function: [ncdirect_dim_y()][crate::ncdirect_dim_y].*
pub fn dim_yx(&mut self) -> (NcDim, NcDim) {
let y = unsafe { crate::ncdirect_dim_y(self) as NcDim };
let x = unsafe { crate::ncdirect_dim_x(self) as NcDim };
(y, x)
}
/// Returns the name of the detected terminal.
///
/// *C style function: [ncdirect_detected_terminal()][crate::ncdirect_detected_terminal].*
pub fn detected_terminal(&self) -> String {
rstring![crate::ncdirect_detected_terminal(self)].to_string()
}
}
/// ## NcDirect methods: I/O
impl NcDirect {
/// Returns a [char] representing a single unicode point.
///
/// If an event is processed, the return value is the `id` field from that
/// event.
///
/// Provide a None `time` to block at length, a `time` of 0 for non-blocking
/// operation, and otherwise a timespec to bound blocking.
///
/// *C style function: [ncdirect_getc()][crate::ncdirect_getc].*
//
// CHECK returns 0 on a timeout.
pub fn getc(&mut self, time: Option<NcTime>, input: Option<&mut NcInput>) -> NcResult<char> {
let ntime;
if let Some(time) = time {
ntime = &time as *const _;
} else {
ntime = null();
}
let ninput;
if let Some(input) = input {
ninput = input as *mut _;
} else {
ninput = null_mut();
}
let c = unsafe { core::char::from_u32_unchecked(crate::ncdirect_get(self, ntime, ninput)) };
if c as u32 as i32 == NCRESULT_ERR {
return Err(NcError::new());
}
Ok(c)
}
///
/// *C style function: [ncdirect_getc_nblock()][crate::ncdirect_getc_nblock].*
pub fn getc_nblock(&mut self, input: &mut NcInput) -> char {
crate::ncdirect_getc_nblock(self, input)
}
///
/// *C style function: [ncdirect_getc_blocking()][crate::ncdirect_getc_blocking].*
pub fn getc_blocking(&mut self, input: &mut NcInput) -> char {
crate::ncdirect_getc_blocking(self, input)
}
/// Get a file descriptor suitable for input event poll()ing.
///
/// When this descriptor becomes available, you can call
/// [getc_nblock()][NcDirect#method.getc_nblock], and input ought be ready.
///
/// This file descriptor is not necessarily the file descriptor associated
/// with stdin (but it might be!).
///
/// *C style function: [ncdirect_inputready_fd()][crate::ncdirect_inputready_fd].*
pub fn inputready_fd(&mut self) -> NcResult<()> {
error![unsafe { crate::ncdirect_inputready_fd(self) }]
}
/// Outputs the `string` according to the `channels`, and
/// returns the total number of characters written on success.
///
/// Note that it does not explicitly flush output buffers, so it will not
/// necessarily be immediately visible.
///
/// It will fail if the NcDirect context and the foreground channel
/// are both marked as using the default color.
///
/// *C style function: [ncdirect_putstr()][crate::ncdirect_putstr].*
pub fn putstr(&mut self, channels: NcChannels, string: &str) -> NcResult<()> {
error![
unsafe { crate::ncdirect_putstr(self, channels, cstring![string]) },
&format!("NcDirect.putstr({:0X}, {:?})", channels, string)
]
}
/// Reads a (heap-allocated) line of text using the Readline library.
///
/// Initializes Readline the first time it's called.
///
/// For input to be echoed to the terminal, it is necessary that the flag
/// [NCDIRECT_OPTION_INHIBIT_CBREAK][crate::NCDIRECT_OPTION_INHIBIT_CBREAK]
/// be provided to the constructor.
///
/// *C style function: [ncdirect_readline()][crate::ncdirect_readline].*
pub fn readline(&mut self, prompt: &str) -> NcResult<&str> {
let res = unsafe { crate::ncdirect_readline(self, cstring![prompt]) };
if !res.is_null() {
return Ok(rstring![res]);
} else {
Err(NcError::with_msg(
NCRESULT_ERR,
&format!["NcDirect.readline({})", prompt],
))
}
}
/// Draws a box with its upper-left corner at the current cursor position,
/// having dimensions `ylen` * `xlen`.
///
/// See NcPlane.[box()][NcPlane#method.box] for more information.
///
/// The minimum box size is 2x2, and it cannot be drawn off-screen.
///
/// `wchars` is an array of 6 characters: UL, UR, LL, LR, HL, VL.
///
/// *C style function: [ncdirect_box()][crate::ncdirect_box].*
// TODO: CHECK, specially wchars.
pub fn r#box(
&mut self,
ul: NcChannels,
ur: NcChannels,
ll: NcChannels,
lr: NcChannels,
wchars: &[char; 6],
y_len: NcDim,
x_len: NcDim,
ctlword: u32,
) -> NcResult<()> {
error![
unsafe {
let wchars = core::mem::transmute(wchars);
crate::ncdirect_box(
self,
ul,
ur,
ll,
lr,
wchars,
y_len as i32,
x_len as i32,
ctlword,
)
},
&format!(
"NcDirect.box({:0X}, {:0X}, {:0X}, {:0X}, {:?}, {}, {}, {})",
ul, ur, ll, lr, wchars, y_len, x_len, ctlword
)
]
}
/// NcDirect.[box()][NcDirect#method.box] with the double box-drawing characters.
///
/// *C style function: [ncdirect_double_box()][crate::ncdirect_double_box].*
pub fn double_box(
&mut self,
ul: NcChannels,
ur: NcChannels,
ll: NcChannels,
lr: NcChannels,
y_len: NcDim,
x_len: NcDim,
ctlword: u32,
) -> NcResult<()> {
error![unsafe {
crate::ncdirect_double_box(self, ul, ur, ll, lr, y_len as i32, x_len as i32, ctlword)
}]
}
/// NcDirect.[box()][NcDirect#method.box] with the rounded box-drawing characters.
///
/// *C style function: [ncdirect_rounded_box()][crate::ncdirect_rounded_box].*
pub fn rounded_box(
&mut self,
ul: NcChannels,
ur: NcChannels,
ll: NcChannels,
lr: NcChannels,
y_len: NcDim,
x_len: NcDim,
ctlword: u32,
) -> NcResult<()> {
error![unsafe {
crate::ncdirect_rounded_box(self, ul, ur, ll, lr, y_len as i32, x_len as i32, ctlword)
}]
}
/// Draws horizontal lines using the specified [NcChannels]s, interpolating
/// between them as we go.
///
/// All lines start at the current cursor position.
///
/// The string at `egc` may not use more than one column.
///
/// For a horizontal line, `len` cannot exceed the screen width minus the
/// cursor's offset.
///
/// *C style function: [ncdirect_hline_interp()][crate::ncdirect_hline_interp].*
#[inline]
pub fn hline_interp(
&mut self,
egc: &str,
len: NcDim,
h1: NcChannels,
h2: NcChannels,
) -> NcResult<()> {
error![crate::ncdirect_hline_interp(self, egc, len, h1, h2)]
}
/// Draws horizontal lines using the specified [NcChannels]s, interpolating
/// between them as we go.
///
/// All lines start at the current cursor position.
///
/// The string at `egc` may not use more than one column.
///
/// For a vertical line, `len` may be as long as you'd like; the screen
/// will scroll as necessary.
///
/// *C style function: [ncdirect_vline_interp()][crate::ncdirect_vline_interp].*
#[inline]
pub fn vline_interp(
&mut self,
egc: &str,
len: NcDim,
h1: NcChannels,
h2: NcChannels,
) -> NcResult<()> {
error![crate::ncdirect_vline_interp(self, egc, len, h1, h2)]
}
}

@ -1,125 +0,0 @@
//! `NcDirect`
// total: 62
// ---------------------------------------------------
// (X) 1 : wont do
// (~) 3 : TODO / WIP
//
// (f) 46 : unsafe ffi function exported by bindgen
// (w) 1 : safely wrapped ffi function
// (r) 11 : static function manually reimplemented
//
// (m) 55 : method implemented
//
// (t) 0 : unit test done for the function
// (T) 0 : unit test done also for the method
// ---------------------------------------------------
// fm ncdirect_bg_default
// fm ncdirect_bg_palindex
// fm ncdirect_bg_rgb
// fm ncdirect_box
// rm ncdirect_canbraille
// rm ncdirect_canchangecolor
// fm ncdirect_canget_cursor
// rm ncdirect_canfade
// rm ncdirect_canhalfblock
// fm ncdirect_canopen_images
// rm ncdirect_canopen_videos
// rm ncdirect_canquadrant
// rm ncdirect_cantruecolor
// fm ncdirect_canutf8
// wm ncdirect_capabilities
// fm ncdirect_check_pixel_support
// fm ncdirect_clear
//~f ncdirect_core_init
// fm ncdirect_cursor_disable
// fm ncdirect_cursor_down
// fm ncdirect_cursor_enable
// fm ncdirect_cursor_left
// fm ncdirect_cursor_move_yx
// fm ncdirect_cursor_pop
// fm ncdirect_cursor_push
// fm ncdirect_cursor_right
// fm ncdirect_cursor_up
// fm ncdirect_cursor_yx
// fm ncdirect_detected_terminal
// fm ncdirect_dim_x
// fm ncdirect_dim_y
// fm ncdirect_double_box
// fm ncdirect_fg_default
// fm ncdirect_fg_palindex
// fm ncdirect_fg_rgb
// fm ncdirect_flush
// fm ncdirect_getc
//~r ncdirect_heavy_box,
// fm ncdirect_hline_interp
// fm ncdirect_init
// fm ncdirect_inputready_fd
//~r ncdirect_light_box,
// fm ncplane_on_styles
// fm ncplane_off_styles
// fm ncdirect_palette_size
//X ncdirect_printf_aligned
// fm ncdirect_putstr
// fm ncdirect_raster_frame
// fm ncdirect_readline
// fm ncdirect_render_frame
// fm ncdirect_render_image
// fm ncdirect_rounded_box
// fm ncplane_set_styles
// fm ncdirect_stop
// f ncdirect_stream
// f ncdirect_styles
// f ncdirect_supported_styles
// fm ncdirect_vline_interp
// rm ncdirect_bg_rgb8
// rm ncdirect_fg_rgb8
// rm ncdirect_getc_nblock
// rm ncdirect_getc_nblocking
#[cfg(test)]
mod test;
mod methods;
mod reimplemented;
pub use reimplemented::*;
/// Minimal notcurses instance for styling text.
pub type NcDirect = crate::bindings::ffi::ncdirect;
/// Flags (options) for [`NcDirect`]
pub type NcDirectFlags = u64;
/// Flag that avoids placing the terminal into cbreak mode
/// (disabling echo and line buffering)
///
pub const NCDIRECT_OPTION_INHIBIT_CBREAK: NcDirectFlags =
crate::bindings::ffi::NCDIRECT_OPTION_INHIBIT_CBREAK as NcDirectFlags;
/// Flag that avoids calling setlocale(LC_ALL, NULL)
///
/// If the result is either "C" or "POSIX", it will print a
/// diagnostic to stderr, and then call setlocale(LC_ALL, "").
///
/// This will attempt to set the locale based off the LANG
/// environment variable. Your program should call setlocale(3)
/// itself, usually as one of the first lines.
///
pub const NCDIRECT_OPTION_INHIBIT_SETLOCALE: NcDirectFlags =
crate::bindings::ffi::NCDIRECT_OPTION_INHIBIT_SETLOCALE as NcDirectFlags;
/// Flag that inhibits registration of the SIGINT, SIGSEGV, SIGABRT & SIGQUIT
/// signal handlers.
pub const NCDIRECT_OPTION_NO_QUIT_SIGHANDLERS: NcDirectFlags =
crate::bindings::ffi::NCDIRECT_OPTION_NO_QUIT_SIGHANDLERS as NcDirectFlags;
/// Flag that enables showing detailed information.
pub const NCDIRECT_OPTION_VERBOSE: NcDirectFlags =
crate::bindings::ffi::NCDIRECT_OPTION_VERBOSE as NcDirectFlags;
/// Flag that enables showing all diagnostics (equivalent to
/// [`NCLOGLEVEL_TRACE`][crate::NCLOGLEVEL_TRACE]).
/// Implies [`NCDIRECT_OPTION_VERBOSE`].
pub const NCDIRECT_OPTION_VERY_VERBOSE: NcDirectFlags =
crate::bindings::ffi::NCDIRECT_OPTION_VERY_VERBOSE as NcDirectFlags;

@ -1,169 +0,0 @@
//! `ncdirect_*` reimplemented functions.
use core::ptr::null;
use crate::{
cstring, NcCapabilities, NcChannels, NcComponent, NcDim, NcDirect, NcInput, NcIntResult, NcRgb,
NcTime,
};
/// Can we directly specify RGB values per cell, or only use palettes?
#[inline]
pub fn ncdirect_cantruecolor(ncd: &NcDirect) -> bool {
ncdirect_capabilities(ncd).rgb
}
/// Can we set the "hardware" palette? Requires the "ccc" terminfo capability.
#[inline]
pub fn ncdirect_canchangecolor(ncd: &NcDirect) -> bool {
crate::nccapability_canchangecolor(&ncdirect_capabilities(ncd))
}
/// Can we fade? Fading requires either the "rgb" or "ccc" terminfo capability.
#[inline]
pub fn ncdirect_canfade(ncd: &NcDirect) -> bool {
ncdirect_canchangecolor(ncd) || ncdirect_cantruecolor(ncd)
}
/// Can we load videos? This requires being built against FFmpeg.
#[inline]
pub fn ncdirect_canopen_videos(_ncd: &NcDirect) -> bool {
unsafe { crate::notcurses_canopen_videos(null()) }
}
/// Can we reliably use Unicode halfblocks?
#[inline]
pub fn ncdirect_canhalfblock(ncd: &NcDirect) -> bool {
unsafe { crate::ncdirect_canutf8(ncd) }
}
/// Can we reliably use Unicode quadrants?
#[inline]
pub fn ncdirect_canquadrant(ncd: &NcDirect) -> bool {
(unsafe { crate::ncdirect_canutf8(ncd) }) && ncdirect_capabilities(ncd).quadrants
}
/// Can we reliably use Unicode 13 sextants?
#[inline]
pub fn ncdirect_cansextant(ncd: &NcDirect) -> bool {
(unsafe { crate::ncdirect_canutf8(ncd) }) && ncdirect_capabilities(ncd).sextants
}
/// Can we reliably use Unicode Braille?
#[inline]
pub fn ncdirect_canbraille(_ncd: &NcDirect) -> bool {
unsafe { crate::notcurses_canbraille(null()) }
}
/// Returns the detected [`NcCapabilities`].
#[inline]
pub fn ncdirect_capabilities(ncd: &NcDirect) -> NcCapabilities {
unsafe { *crate::bindings::ffi::ncdirect_capabilities(ncd) }
}
/// 'input' may be NULL if the caller is uninterested in event details.
/// Blocks until an event is processed or a signal is received.
///
/// *Method: NcDirect.[getc_blocking()][NcDirect#method.getc_blocking].*
// TODO: use from_u32 & return Option.
#[inline]
pub fn ncdirect_getc_blocking(ncd: &mut NcDirect, input: &mut NcInput) -> char {
unsafe { core::char::from_u32_unchecked(crate::ncdirect_get(ncd, null(), input)) }
}
///
/// If no event is ready, returns 0.
///
/// *Method: NcDirect.[getc_nblock()][NcDirect#method.getc_nblock].*
//
// `input` may be NULL if the caller is uninterested in event details.
#[inline]
pub fn ncdirect_getc_nblock(ncd: &mut NcDirect, input: &mut NcInput) -> char {
unsafe {
let ts = NcTime::new();
core::char::from_u32_unchecked(crate::ncdirect_get(ncd, &ts, input))
}
}
/// Sets the foreground [NcComponent] components.
///
/// *Method: NcDirect.[set_fg_rgb8()][NcDirect#method.set_fg_rgb8].*
#[inline]
pub fn ncdirect_set_fg_rgb8(
ncd: &mut NcDirect,
red: NcComponent,
green: NcComponent,
blue: NcComponent,
) -> NcIntResult {
let rgb = (red as NcRgb) << 16 | (green as NcRgb) << 8 | blue as NcRgb;
unsafe { crate::ncdirect_set_fg_rgb(ncd, rgb) }
}
/// Sets the background [NcComponent] components.
///
/// *Method: NcDirect.[set_bg_rgb8()][NcDirect#method.set_bg_rgb8].*
#[inline]
pub fn ncdirect_set_bg_rgb8(
ncd: &mut NcDirect,
red: NcComponent,
green: NcComponent,
blue: NcComponent,
) -> NcIntResult {
let rgb = (red as NcRgb) << 16 | (green as NcRgb) << 8 | blue as NcRgb;
unsafe { crate::ncdirect_set_bg_rgb(ncd, rgb) }
}
/// Draws horizontal lines using the specified [NcChannels]s, interpolating
/// between them as we go.
///
/// The string at `egc` may not use more than one column.
///
/// All lines start at the current cursor position.
///
/// For a horizontal line, `len` cannot exceed the screen width minus the
/// cursor's offset.
// TODO:MAYBE saturate the `len` value
///
/// *Method: NcDirect.[hline_interp()][NcDirect#method.hline_interp].*
#[inline]
pub fn ncdirect_hline_interp(
ncd: &mut NcDirect,
egc: &str,
len: NcDim,
h1: NcChannels,
h2: NcChannels,
) -> NcIntResult {
#[cfg(any(target_arch = "armv7l", target_arch = "i686"))]
let egc_ptr = cstring![egc] as *const i8;
#[cfg(not(any(target_arch = "armv7l", target_arch = "i686")))]
let egc_ptr = cstring![egc];
unsafe { crate::bindings::ffi::ncdirect_hline_interp(ncd, egc_ptr, len as i32, h1, h2) }
}
/// Draws horizontal lines using the specified [NcChannels]s, interpolating
/// between them as we go.
///
/// The string at `egc` may not use more than one column.
///
/// All lines start at the current cursor position.
///
/// For a vertical line, `len` may be as long as you'd like; the screen
/// will scroll as necessary.
///
/// *Method: NcDirect.[vline_interp()][NcDirect#method.vline_interp].*
#[inline]
pub fn ncdirect_vline_interp(
ncd: &mut NcDirect,
egc: &str,
len: NcDim,
h1: NcChannels,
h2: NcChannels,
) -> NcIntResult {
#[cfg(any(target_arch = "armv7l", target_arch = "i686"))]
let egc_ptr = cstring![egc] as *const i8;
#[cfg(not(any(target_arch = "armv7l", target_arch = "i686")))]
let egc_ptr = cstring![egc];
unsafe { crate::bindings::ffi::ncdirect_vline_interp(ncd, egc_ptr, len as i32, h1, h2) }
}

@ -1,80 +0,0 @@
//! Error handling with `Error`, `NcResult` & `NcIntResult` for error handling
use std::{self, error, fmt};
/// The [`i32`] value used to return errors by the underlying C API.
///
/// A value < 0 means error, (usually -1).
///
/// # Defined constants:
///
/// - [`NCRESULT_OK`]
/// - [`NCRESULT_ERR`]
/// - [`NCRESULT_MAX`]
pub type NcIntResult = i32;
/// OK value, for the functions that return [`NcIntResult`].
pub const NCRESULT_OK: i32 = 0;
/// ERROR value, for the functions that return an [`NcIntResult`].
pub const NCRESULT_ERR: i32 = -1;
/// MAX value, for the functions that return [`NcIntResult`].
pub const NCRESULT_MAX: i32 = i32::MAX;
/// The error type for the Rust methods API.
#[derive(Debug, Clone, Default)]
pub struct NcError {
/// [NcIntResult].
pub int: i32,
pub msg: String,
}
impl fmt::Display for NcError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "NcError {}: {}", self.int, self.msg)
}
}
impl error::Error for NcError {
fn description(&self) -> &str {
&self.msg
}
}
impl NcError {
/// New NcError with default [NCRESULT_ERR] error number, and without message.
pub fn new() -> Self {
Self {
int: NCRESULT_ERR,
..Default::default()
}
}
/// New NcError with custom error number, and without message.
pub fn new_err(int: NcIntResult) -> Self {
Self {
int,
..Default::default()
}
}
/// New NcError with default [NCRESULT_ERR] error number and a custom message.
pub fn new_msg(msg: &str) -> Self {
Self {
int: NCRESULT_ERR,
msg: msg.to_string(),
}
}
/// New NcError with both a custom error number and a custom message.
pub fn with_msg(int: NcIntResult, msg: &str) -> Self {
Self {
int,
msg: msg.to_string(),
}
}
}
/// The result type for the Rust methods API.
pub type NcResult<T> = Result<T, NcError>;

@ -1,49 +0,0 @@
//! `NcFadeCb` & `NcFadeCtx`
// functions already exported by bindgen : 3
// -------------------------------------------
// (#) test: 0
// (W) wrap: 3 / 0
// -------------------------------------------
//W ncfadectx_free
//W ncfadectx_iterations
//W ncfadectx_setup
use std::ffi::c_void;
use crate::{Nc, NcIntResult, NcPlane, NcTime};
/// Called for each fade iteration on the NcPlane.
///
/// If anything but 0 is returned, the fading operation ceases immediately,
/// and that value is propagated out.
///
/// The recommended absolute display time target is passed in 'tspec'.
pub type NcFadeCb =
Option<unsafe extern "C" fn(*mut Nc, *mut NcPlane, *const NcTime, *mut c_void) -> NcIntResult>;
/// Context for a palette fade operation
pub type NcFadeCtx = crate::bindings::ffi::ncfadectx;
impl NcFadeCtx {
/// NcFadeCtx constructor.
///
/// Rather than the simple ncplane_fade{in/out}(),
/// ncfadectx_setup() can be paired with a loop over
/// ncplane_fade{in/out}_iteration() + ncfadectx_free().
pub fn setup(plane: &mut NcPlane) -> &mut NcFadeCtx {
unsafe { &mut *crate::ncfadectx_setup(plane) }
}
/// Releases the resources associated.
pub fn free(&mut self) {
unsafe {
crate::ncfadectx_free(self);
}
}
/// Returns the number of iterations through which will fade.
pub fn iterations(&self) -> u32 {
unsafe { crate::ncfadectx_iterations(self) as u32 }
}
}

@ -1,366 +0,0 @@
//! `NcVisual*` methods and associated functions.
use core::ptr::null_mut;
use libc::c_void;
use crate::{
// cstring, error, error_ref_mut, rstring, NcBlitter, NcDim, NcError, NcIntResult, NcPixel,
// NcPlane, NcResult, NcRgba, NcScale, NcTime, NcVisual, NcVisualOptions, Notcurses, NCBLIT_PIXEL,
// NCRESULT_ERR,
};
/// # NcVisualOptions Constructors
impl NcSubprocOptions {
///
pub fn new(
curry: *mut c_void,
restart_period: u64,
// flags: u64,
) -> Self {
Self {
curry:,
// restart this many seconds after an exit (watch)
restart_period,
// bitfield over NCOPTION_SUBPROC_* (none yet)
flags: 0,
}
}
}
/// # NcSubproc Constructors & Destructors
impl NcSubproc {
/// Opens a visual at `file`, extracts the codec and parameters and
/// decodes the first image to memory.
///
/// *C style function: [ncvisual_from_file()][crate::ncvisual_from_file].*
pub fn new<'a>(file: &str) -> NcResult<&'a mut NcVisual> {
error_ref_mut![
unsafe { crate::ncvisual_from_file(cstring![file]) },
&format!("NcVisual::from_file()")
]
}
/// Promotes an NcPlane to an NcVisual.
///
/// The plane may contain only spaces, half blocks, and full blocks.
/// This will be checked, and any other glyph will result in an error.
///
/// This function exists so that planes can be subjected to NcVisual transformations.
/// If possible, it's better to create the ncvisual from memory using
/// [from_rgba][NcVisual#method.from_rgba].
///
/// *C style function: [ncvisual_from_plane()][crate::ncvisual_from_plane].*
pub fn from_plane<'a>(
plane: &NcPlane,
blitter: NcBlitter,
beg_y: NcDim,
beg_x: NcDim,
len_y: NcDim,
len_x: NcDim,
) -> NcResult<&'a mut NcVisual> {
error_ref_mut![
unsafe {
crate::ncvisual_from_plane(
plane,
blitter,
beg_y as i32,
beg_x as i32,
len_y as i32,
len_x as i32,
)
},
&format!("NcVisual::from_file()")
]
}
/// Prepares an NcVisual, and its underlying NcPlane, based off RGBA content
/// in memory at `rgba`.
///
/// `rgba` is laid out as `rows` lines, each of which is `rowstride` bytes in length.
/// Each line has `cols` 32-bit 8bpc RGBA pixels followed by possible padding
/// (there will be rowstride - cols * 4 bytes of padding).
///
/// The total size of `rgba` is thus (rows * rowstride) bytes, of which
/// (rows * cols * 4) bytes are actual non-padding data.
///
/// *C style function: [ncvisual_from_rgba()][crate::ncvisual_from_rgba].*
pub fn from_rgba<'a>(
rgba: &[u8],
rows: NcDim,
rowstride: NcDim,
cols: NcDim,
) -> NcResult<&'a mut NcVisual> {
error_ref_mut![
unsafe {
crate::ncvisual_from_rgba(
rgba.as_ptr() as *const c_void,
rows as i32,
rowstride as i32,
cols as i32,
)
},
&format!("NcVisual::from_rgba()")
]
}
/// Destroys this NcVisual.
///
/// Rendered elements will not be disrupted, but the visual can be neither
/// decoded nor rendered any further.
///
/// *C style function: [ncvisual_destroy()][crate::ncvisual_destroy].*
pub fn destroy(&mut self) {
unsafe { crate::ncvisual_destroy(self) }
}
}
/// # NcVisual Methods
impl NcVisual {
/// Gets the specified pixel from this NcVisual.
///
/// *C style function: [ncvisual_at_yx()][crate::ncvisual_at_yx].*
pub fn at_yx(&self, y: NcDim, x: NcDim) -> NcResult<NcPixel> {
let mut pixel = 0;
let res = unsafe { crate::ncvisual_at_yx(self, y as i32, x as i32, &mut pixel) };
error![res, "NcVisual.at_yx()", pixel]
}
/// Extracts the next frame from the NcVisual.
///
/// Returns 0 for normal frames, and 1 to indicate EOF.
///
/// *C style function: [ncvisual_decode()][crate::ncvisual_decode].*
pub fn decode(&mut self) -> NcResult<NcIntResult> {
let res = unsafe { crate::ncvisual_decode(self) };
if res == NCRESULT_ERR {
return Err(NcError::with_msg(res, "NcVisual.decode()"));
} else {
Ok(res)
}
}
/// Extracts the next frame from the NcVisual, ala [decode][NcVisual#method.decode],
/// but if we have reached the end, rewinds to the first frame.
///
/// *A subsequent [NcVisual.render]() will render the first frame,
/// as if the ncvisual had been closed and reopened.*
///
/// Returns 0 for normal frames and 1 to indicate EOF.
///
/// *C style function: [ncvisual_decode_loop()][crate::ncvisual_decode_loop].*
pub fn decode_loop(&mut self) -> NcResult<NcIntResult> {
let res = unsafe { crate::ncvisual_decode_loop(self) };
if res == NCRESULT_ERR {
return Err(NcError::with_msg(res, "NcVisual.decode_loop()"));
} else {
Ok(res)
}
}
/// Inflates each pixel in the image to 'scale'x'scale' pixels.
///
/// The original color is retained.
pub fn inflate(&mut self, scale: u32) -> NcResult<NcIntResult> {
let res = unsafe { crate::ncvisual_inflate(self, scale as i32) };
error![res, &format!["NcVisual.inflate({})", scale], res]
}
/// Gets the size and ratio of NcVisual pixels to output cells along the
/// `y→to_y` and `x→to_x` axes.
///
/// Returns a tuple with (y, x, to_y, to_x)
///
/// An NcVisual of `y` by `x` pixels will require
/// (`y` * `to_y`) by (`x` * `to_x`) cells for full output.
///
/// Errors on invalid blitter in `options`. Scaling is taken into consideration.
///
/// *C style function: [ncvisual_blitter_geom()][crate::ncvisual_blitter_geom].*
pub fn geom(
&self,
nc: &Notcurses,
options: &NcVisualOptions,
) -> NcResult<(NcDim, NcDim, NcDim, NcDim)> {
let mut y = 0;
let mut x = 0;
let mut to_y = 0;
let mut to_x = 0;
let res = unsafe {
crate::ncvisual_blitter_geom(
nc,
self,
options,
&mut y,
&mut x,
&mut to_y,
&mut to_x,
null_mut(),
)
};
error![
res,
"NcVisual.geom()",
(y as NcDim, x as NcDim, to_y as NcDim, to_x as NcDim)
];
}
/// Gets the default media (not plot) blitter for this environment when using
/// the specified scaling method.
///
/// Currently, this means:
/// - if lacking UTF-8, NCBLIT_1x1.
/// - otherwise, if not NCSCALE_STRETCH, NCBLIT_2x1.
/// - otherwise, if sextants are not known to be good, NCBLIT_2x2.
/// - otherwise NCBLIT_3x2 NCBLIT_2x2 and NCBLIT_3x2 both distort the original
/// aspect ratio, thus NCBLIT_2x1 is used outside of NCSCALE_STRETCH.
///
/// *C style function: [ncvisual_media_defblitter()][crate::ncvisual_media_defblitter].*
pub fn media_defblitter(nc: &Notcurses, scale: NcScale) -> NcBlitter {
unsafe { crate::ncvisual_media_defblitter(nc, scale) }
}
/// Polyfills at the specified location using `rgba`.
///
/// *C style function: [ncvisual_polyfill_yx()][crate::ncvisual_polyfill_yx].*
pub fn polyfill_yx(&mut self, y: NcDim, x: NcDim, rgba: NcRgba) -> NcResult<()> {
error![
unsafe { crate::ncvisual_polyfill_yx(self, y as i32, x as i32, rgba) },
&format!["NcVisual.polyfill_yx({}, {}, {})", y, x, rgba]
]
}
/// Renders the decoded frame to the specified [NcPlane].
///
/// See [`NcVisualOptions`].
///
/// *C style function: [ncvisual_render()][crate::ncvisual_render].*
pub fn render(
&mut self,
nc: &mut Notcurses,
options: &NcVisualOptions,
) -> NcResult<&mut NcPlane> {
error_ref_mut![
unsafe { crate::ncvisual_render(nc, self, options) },
"NcVisual.render()"
]
}
/// Resizes the visual to `rows` X `columns` pixels.
///
/// This is a lossy transformation, unless the size is unchanged.
///
/// *C style function: [ncvisual_resize()][crate::ncvisual_resize].*
pub fn resize(&mut self, rows: NcDim, cols: NcDim) -> NcResult<()> {
error![
unsafe { crate::ncvisual_resize(self, rows as i32, cols as i32) },
&format!["NcVisual.resize({}, {})", rows, cols]
]
}
/// Rotates the visual `rads` radians.
///
/// Only M_PI/2 and -M_PI/2 are supported at the moment,
/// but this will change. (FIXME)
///
/// *C style function: [ncvisual_rotate()][crate::ncvisual_rotate].*
pub fn rotate(&mut self, rads: f64) -> NcResult<()> {
error![
unsafe { crate::ncvisual_rotate(self, rads) },
&format!["NcVisual.rotate({})", rads]
]
}
/// Sets the specified pixel.
///
/// *C style function: [ncvisual_set_yx()][crate::ncvisual_set_yx].*
pub fn set_yx(&mut self, y: NcDim, x: NcDim, pixel: NcPixel) -> NcResult<()> {
error![
unsafe { crate::ncvisual_set_yx(self, y as i32, x as i32, pixel) },
&format!["NcVisual.set_yx({}, {}, {})", y, x, pixel]
]
}
/// Displays frames.
///
/// *Provide as an argument to ncvisual_stream().*
///
/// If you'd like subtitles to be decoded, provide an ncplane as the curry.
/// If the curry is NULL, subtitles will not be displayed.
///
/// *C style function: [ncvisual_simple_streamer()][crate::ncvisual_simple_streamer].*
pub fn simple_streamer(
&mut self,
options: &mut NcVisualOptions,
time: &NcTime,
curry: Option<&mut NcPlane>,
) -> NcResult<()> {
if let Some(plane) = curry {
error![
unsafe {
crate::ncvisual_simple_streamer(
self,
options,
time,
plane as *mut _ as *mut libc::c_void,
)
},
&format![
"NcVisual.simple_streamer({:?}, {:?}, ncplane)",
options, time
]
]
} else {
error![
unsafe { crate::ncvisual_simple_streamer(self, options, time, null_mut()) },
&format!["NcVisual.simple_streamer({:?}, {:?}, null)", options, time]
]
}
}
// // TODO
//
// /// Streams the entirety of the media, according to its own timing.
// ///
// /// Blocking, obviously.
// ///
// /// If `streamer` is provided it will be called for each frame, and its return
// /// value handled as outlined for streamcb.
// /// If streamer() returns non-zero, the stream is aborted, and that value is
// /// returned. By convention, return a positive number to indicate intentional
// /// abort from within streamer().
// ///
// /// `timescale` allows the frame duration time to be scaled.
// /// For a visual naturally running at 30FPS, a 'timescale' of 0.1 will result
// /// in 300 FPS, and a `timescale` of 10 will result in 3 FPS.
// /// It is an error to supply `timescale` less than or equal to 0.
// ///
// /// *C style function: [ncvisual_streamer()][crate::ncvisual_streamer].*
// //
// // TODO: add streamcb
// // INFO: QUESTION: is curry also optional like in simple_streamer?
// //
// pub fn simple_streamer(
// &mut self,
// nc: &mut Notcurses,
// timescale: f32,
// //streamer: Option<streamcb>
// options: &NcVisualOptions,
// curry: Option<&mut NcPlane>,
// ) -> NcResult<()> {
// }
/// If a subtitle ought be displayed at this time, returns a heap-allocated
/// copy of the UTF8 text.
///
/// *C style function: [ncvisual_subtitle()][crate::ncvisual_subtitle].*
pub fn subtitle(&self) -> NcResult<&str> {
let res = unsafe { crate::ncvisual_subtitle(self) };
if res != null_mut() {
return Ok(rstring![res]);
} else {
Err(NcError::with_msg(NCRESULT_ERR, "NcVisual.subtitle()"))
}
}
}

@ -1,335 +0,0 @@
//! Wrapper for `libc::FILE`, both as used by notcurses and the libc crate
//!
//! The interface is largely based on the implementation of the
//! [cfile-rs crate](https://github.com/jkarns275/cfile) by Joshua Karns
use core::ptr::{null_mut, NonNull};
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom};
use libc::{
c_long, c_void, fclose, /* feof, */ fread, fseek, ftell, SEEK_CUR, SEEK_END, SEEK_SET,
};
/// See [NcFile]. Notcurses functions expects this type of `*FILE` (a struct)
#[allow(clippy::upper_case_acronyms)]
pub type FILE_NC = crate::ffi::FILE;
/// See [NcFile]. The [`libc`](https://docs.rs/libc/) crate expects this type
/// of `*FILE` (an opaque enum)
#[allow(clippy::upper_case_acronyms)]
pub type FILE_LIBC = libc::FILE;
// TODO: the following static strings aren't made public
/// Intended to be passed into the CFile::open method.
/// It will open the file in a way that will allow reading and writing,
/// including overwriting old data.
/// It will not create the file if it does not exist.
pub static RANDOM_ACCESS_MODE: &str = "rb+";
/// Intended to be passed into the CFile::open method.
/// It will open the file in a way that will allow reading and writing,
/// including overwriting old data
pub static UPDATE: &str = "rb+";
/// Intended to be passed into the CFile::open method.
/// It will only allow reading.
pub static READ_ONLY: &str = "r";
/// Intended to be passed into the CFile::open method.
/// It will only allow writing.
pub static WRITE_ONLY: &str = "w";
/// Intended to be passed into the CFile::open method.
/// It will only allow data to be appended to the end of the file.
pub static APPEND_ONLY: &str = "a";
/// Intended to be passed into the CFile::open method.
/// It will allow data to be appended to the end of the file, and data to be
/// read from the file. It will create the file if it doesn't exist.
pub static APPEND_READ: &str = "a+";
/// Intended to be passed into the CFile::open method.
/// It will open the file in a way that will allow reading and writing,
/// including overwriting old data. It will create the file if it doesn't exist
pub static TRUNCATE_RANDOM_ACCESS_MODE: &str = "wb+";
/// A utility function to pull the current value of errno and put it into an
/// Error::Errno
fn get_error<T>() -> Result<T, Error> {
Err(Error::last_os_error())
}
/// A wrapper struct around
/// [`libc::FILE`](https://docs.rs/libc/0.2.80/libc/enum.FILE.html)
///
/// The notcurses `FILE` type [`FILE_NC`] a struct imported through bindgen,
/// while the equivalent [`libc`](https://docs.rs/libc) crate FILE
/// ([`FILE_LIBC`]) is an opaque enum.
///
/// Several methods are provided to cast back and forth between both types,
/// in order to allow both rust libc operations and notcurses file operations
/// over the same underlying `*FILE`.
#[derive(Debug)]
pub struct NcFile {
file_ptr: NonNull<FILE_LIBC>,
}
impl NcFile {
// constructors --
/// `NcFile` constructor from a file produced by notcurses
pub fn from_nc(file: *mut FILE_NC) -> Self {
NcFile {
file_ptr: unsafe { NonNull::new_unchecked(NcFile::nc2libc(file)) },
}
}
/// `NcFile` constructor from a file produced by the libc crate
#[allow(clippy::missing_safety_doc)]
pub unsafe fn from_libc(file: *mut FILE_LIBC) -> Self {
NcFile {
file_ptr: NonNull::new_unchecked(file),
}
}
// methods --
/// Returns the file pointer in the format expected by the [`libc`] crate
#[inline]
pub fn as_libc_ptr(&self) -> *mut FILE_LIBC {
self.file_ptr.as_ptr()
}
/// Returns the file pointer in the format expected by notcurses
#[inline]
pub fn as_nc_ptr(&self) -> *mut FILE_NC {
Self::libc2nc(self.file_ptr.as_ptr())
}
/// Returns the current position in the file.
///
/// On error `Error::Errno(errno)` is returned.
pub fn current_pos(&self) -> Result<u64, Error> {
unsafe {
let pos = ftell(self.as_libc_ptr());
if pos != -1 {
Ok(pos as u64)
} else {
get_error()
}
}
}
/// Reads the file from start to end. Convenience method
///
#[inline]
pub fn read_all(&mut self, buf: &mut Vec<u8>) -> Result<usize, Error> {
let _ = self.seek(SeekFrom::Start(0));
self.read_to_end(buf)
}
// private methods --
/// Converts a file pointer from the struct notcurses uses to the
/// opaque enum type libc expects
#[inline]
fn nc2libc(file: *mut FILE_NC) -> *mut FILE_LIBC {
file as *mut _ as *mut FILE_LIBC
}
/// Converts a file pointer from the libc opaque enum format to the struct
/// expected by notcurses
#[inline]
fn libc2nc(file: *mut FILE_LIBC) -> *mut FILE_NC {
file as *mut _ as *mut FILE_NC
}
/// A utility function to expand a vector without increasing its capacity
/// more than it needs to be expanded.
fn expand_buffer(buff: &mut Vec<u8>, by: usize) {
if buff.capacity() < buff.len() + by {
buff.reserve(by);
}
for _ in 0..by {
buff.push(0u8);
}
}
}
impl Read for NcFile {
/// Reads exactly the number of bytes required to fill buf.
///
/// If the end of the file is reached before buf is filled,
/// `Err(EndOfFile(bytes_read))` will be returned. The data that was read
/// before that will still have been placed into buf.
///
/// Upon some other error, `Err(Errno(errno))` will be returned.
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
unsafe {
let result = fread(
buf.as_ptr() as *mut c_void,
1,
buf.len(),
self.as_libc_ptr(),
);
if result != buf.len() {
match get_error::<u8>() {
Err(err) => {
if err.kind() == ErrorKind::UnexpectedEof {
Ok(result)
} else {
Err(err)
}
}
Ok(_) => panic!("This is impossible"),
}
} else {
Ok(result)
}
}
}
/// Reads the entire file starting from the current_position
/// expanding buf as needed.
///
/// On a successful read, this function will return `Ok(bytes_read)`.
///
/// If an error occurs during reading, some varient of error will be returned.
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, Error> {
let pos = self.current_pos();
let _ = self.seek(SeekFrom::End(0));
let end = self.current_pos();
match pos {
Ok(cur_pos) => match end {
Ok(end_pos) => {
if end_pos == cur_pos {
return Ok(0);
}
let to_read = (end_pos - cur_pos) as usize;
if buf.len() < to_read {
let to_reserve = to_read - buf.len();
Self::expand_buffer(buf, to_reserve);
}
let _ = self.seek(SeekFrom::Start(cur_pos as u64));
match self.read_exact(buf) {
Ok(()) => Ok(to_read),
Err(e) => Err(e),
}
}
Err(e) => Err(e),
},
Err(e) => Err(e),
}
}
/// Reads the entire file from the beginning and stores it in a string
///
/// On a successful read, this function will return `Ok(bytes_read)`.
///
/// If an error occurs during reading, some varient of error will be returned.
fn read_to_string(&mut self, strbuf: &mut String) -> Result<usize, Error> {
let mut bytes_read = 0_usize;
let mut buffer = vec![0u8];
let result = self.read_all(&mut buffer);
if let Ok(bytes) = result {
bytes_read = bytes;
}
if let Err(e) = result {
return Err(e);
}
let result = std::str::from_utf8(&buffer);
if let Ok(strslice) = result {
*strbuf = strslice.to_string();
Ok(bytes_read)
} else {
get_error()
}
}
/// Reads exactly the number of bytes required to fill buf.
///
/// If the end of the file is reached before buf is filled,
/// `Err(EndOfFile(bytes_read))` will be returned. The data that was read
/// before that will still have been placed into buf.
///
/// Upon some other error, `Err(Errno(errno))` will be returned.
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error> {
unsafe {
let result = fread(
buf.as_ptr() as *mut c_void,
1,
buf.len(),
self.as_libc_ptr(),
);
if result == buf.len() {
Ok(())
} else {
// Check if we hit the end of the file
// FIXME
// if feof(self.as_libc_ptr()) != 0 {
// get_error()
// } else {
// get_error()
// }
get_error()
}
}
}
}
impl Seek for NcFile {
/// Changes the current position in the file using the [`SeekFrom`] enum.
///
/// To set relative to the beginning of the file (i.e. index is 0 + offset):
/// ```ignore
/// SeekFrom::Start(offset)
/// ```
/// To set relative to the end of the file (i.e. index is file_lenth - 1 - offset):
/// ```ignore
/// SeekFrom::End(offset)
/// ```
/// To set relative to the current position:
/// ```ignore
/// SeekFrom::End(offset)
/// ```
///
/// On error `Error::Errno(errno)` is returned.
fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error> {
unsafe {
let result = match pos {
SeekFrom::Start(from) => fseek(self.as_libc_ptr(), from as c_long, SEEK_SET),
SeekFrom::End(from) => fseek(self.as_libc_ptr(), from as c_long, SEEK_END),
SeekFrom::Current(delta) => fseek(self.as_libc_ptr(), delta as c_long, SEEK_CUR),
};
if result == 0 {
self.current_pos()
} else {
get_error()
}
}
}
}
impl Drop for NcFile {
/// Ensures the file stream is closed before abandoning the data.
fn drop(&mut self) {
let _ = unsafe {
if !(self.as_libc_ptr()).is_null() {
let res = fclose(self.as_libc_ptr());
if res == 0 {
self.file_ptr = NonNull::new_unchecked(null_mut::<FILE_LIBC>());
Ok(())
} else {
get_error()
}
} else {
Ok(())
}
};
}
}

@ -1,25 +0,0 @@
// functions manually reimplemented: 2
// ------------------------------------------
// (+) done: 2 / 0
// (#) test: 0 / 2
// ------------------------------------------
// + nckey_mouse_p
// + nckey_supppuab_p
use crate::{NCKEY_BUTTON1, NCKEY_RELEASE};
/// Is this [char] a Supplementary Private Use Area-B codepoint?
///
/// Links:
/// - https://en.wikipedia.org/wiki/Private_Use_Areas
/// - https://codepoints.net/supplementary_private_use_area-b
#[inline]
pub fn nckey_supppuab_p(w: char) -> bool {
w as u32 >= 0x100000_u32 && w as u32 <= 0x10fffd_u32
}
/// Is the event a synthesized mouse event?
#[inline]
pub const fn nckey_mouse_p(r: char) -> bool {
r >= NCKEY_BUTTON1 && r <= NCKEY_RELEASE
}

@ -1,137 +0,0 @@
//! Special composed key definitions. These values are added to 0x100000.
#![allow(clippy::transmute_int_to_char)]
use std::mem::transmute;
// NOTE: Waiting for: https://github.com/rust-lang/rust/issues/53605
// const fn suppuabize(w: u32) -> char {
const fn suppuabize(w: u32) -> u32 {
// unsafe { transmute(w + 0x100000) }
w + 0x100000
}
pub const NCKEY_INVALID: char = unsafe { transmute(suppuabize(0)) };
///generated interally in response to SIGWINCH
pub const NCKEY_RESIZE: char = unsafe { transmute(suppuabize(1)) };
pub const NCKEY_UP: char = unsafe { transmute(suppuabize(2)) };
pub const NCKEY_RIGHT: char = unsafe { transmute(suppuabize(3)) };
pub const NCKEY_DOWN: char = unsafe { transmute(suppuabize(4)) };
pub const NCKEY_LEFT: char = unsafe { transmute(suppuabize(5)) };
pub const NCKEY_INS: char = unsafe { transmute(suppuabize(6)) };
pub const NCKEY_DEL: char = unsafe { transmute(suppuabize(7)) };
/// backspace (sometimes)
pub const NCKEY_BACKSPACE: char = unsafe { transmute(suppuabize(8)) };
pub const NCKEY_PGDOWN: char = unsafe { transmute(suppuabize(9)) };
pub const NCKEY_PGUP: char = unsafe { transmute(suppuabize(10)) };
pub const NCKEY_HOME: char = unsafe { transmute(suppuabize(11)) };
pub const NCKEY_END: char = unsafe { transmute(suppuabize(12)) };
pub const NCKEY_F00: char = unsafe { transmute(suppuabize(20)) };
pub const NCKEY_F01: char = unsafe { transmute(suppuabize(21)) };
pub const NCKEY_F02: char = unsafe { transmute(suppuabize(22)) };
pub const NCKEY_F03: char = unsafe { transmute(suppuabize(23)) };
pub const NCKEY_F04: char = unsafe { transmute(suppuabize(24)) };
pub const NCKEY_F05: char = unsafe { transmute(suppuabize(25)) };
pub const NCKEY_F06: char = unsafe { transmute(suppuabize(26)) };
pub const NCKEY_F07: char = unsafe { transmute(suppuabize(27)) };
pub const NCKEY_F08: char = unsafe { transmute(suppuabize(28)) };
pub const NCKEY_F09: char = unsafe { transmute(suppuabize(29)) };
pub const NCKEY_F10: char = unsafe { transmute(suppuabize(30)) };
pub const NCKEY_F11: char = unsafe { transmute(suppuabize(31)) };
pub const NCKEY_F12: char = unsafe { transmute(suppuabize(32)) };
pub const NCKEY_F13: char = unsafe { transmute(suppuabize(33)) };
pub const NCKEY_F14: char = unsafe { transmute(suppuabize(34)) };
pub const NCKEY_F15: char = unsafe { transmute(suppuabize(35)) };
pub const NCKEY_F16: char = unsafe { transmute(suppuabize(36)) };
pub const NCKEY_F17: char = unsafe { transmute(suppuabize(37)) };
pub const NCKEY_F18: char = unsafe { transmute(suppuabize(38)) };
pub const NCKEY_F19: char = unsafe { transmute(suppuabize(39)) };
pub const NCKEY_F20: char = unsafe { transmute(suppuabize(40)) };
pub const NCKEY_F21: char = unsafe { transmute(suppuabize(41)) };
pub const NCKEY_F22: char = unsafe { transmute(suppuabize(42)) };
pub const NCKEY_F23: char = unsafe { transmute(suppuabize(43)) };
pub const NCKEY_F24: char = unsafe { transmute(suppuabize(44)) };
pub const NCKEY_F25: char = unsafe { transmute(suppuabize(45)) };
pub const NCKEY_F26: char = unsafe { transmute(suppuabize(46)) };
pub const NCKEY_F27: char = unsafe { transmute(suppuabize(47)) };
pub const NCKEY_F28: char = unsafe { transmute(suppuabize(48)) };
pub const NCKEY_F29: char = unsafe { transmute(suppuabize(49)) };
pub const NCKEY_F30: char = unsafe { transmute(suppuabize(50)) };
pub const NCKEY_F31: char = unsafe { transmute(suppuabize(51)) };
pub const NCKEY_F32: char = unsafe { transmute(suppuabize(52)) };
pub const NCKEY_F33: char = unsafe { transmute(suppuabize(53)) };
pub const NCKEY_F34: char = unsafe { transmute(suppuabize(54)) };
pub const NCKEY_F35: char = unsafe { transmute(suppuabize(55)) };
pub const NCKEY_F36: char = unsafe { transmute(suppuabize(56)) };
pub const NCKEY_F37: char = unsafe { transmute(suppuabize(57)) };
pub const NCKEY_F38: char = unsafe { transmute(suppuabize(58)) };
pub const NCKEY_F39: char = unsafe { transmute(suppuabize(59)) };
pub const NCKEY_F40: char = unsafe { transmute(suppuabize(60)) };
pub const NCKEY_F41: char = unsafe { transmute(suppuabize(61)) };
pub const NCKEY_F42: char = unsafe { transmute(suppuabize(62)) };
pub const NCKEY_F43: char = unsafe { transmute(suppuabize(63)) };
pub const NCKEY_F44: char = unsafe { transmute(suppuabize(64)) };
pub const NCKEY_F45: char = unsafe { transmute(suppuabize(65)) };
pub const NCKEY_F46: char = unsafe { transmute(suppuabize(66)) };
pub const NCKEY_F47: char = unsafe { transmute(suppuabize(67)) };
pub const NCKEY_F48: char = unsafe { transmute(suppuabize(68)) };
pub const NCKEY_F49: char = unsafe { transmute(suppuabize(69)) };
pub const NCKEY_F50: char = unsafe { transmute(suppuabize(70)) };
pub const NCKEY_F51: char = unsafe { transmute(suppuabize(71)) };
pub const NCKEY_F52: char = unsafe { transmute(suppuabize(72)) };
pub const NCKEY_F53: char = unsafe { transmute(suppuabize(73)) };
pub const NCKEY_F54: char = unsafe { transmute(suppuabize(74)) };
pub const NCKEY_F55: char = unsafe { transmute(suppuabize(75)) };
pub const NCKEY_F56: char = unsafe { transmute(suppuabize(76)) };
pub const NCKEY_F57: char = unsafe { transmute(suppuabize(77)) };
pub const NCKEY_F58: char = unsafe { transmute(suppuabize(78)) };
pub const NCKEY_F59: char = unsafe { transmute(suppuabize(79)) };
pub const NCKEY_F60: char = unsafe { transmute(suppuabize(80)) };
// ... leave room for up to 100 function keys, egads
pub const NCKEY_ENTER: char = unsafe { transmute(suppuabize(121)) };
/// "clear-screen or erase"
pub const NCKEY_CLS: char = unsafe { transmute(suppuabize(122)) };
/// down + left on keypad
pub const NCKEY_DLEFT: char = unsafe { transmute(suppuabize(123)) };
pub const NCKEY_DRIGHT: char = unsafe { transmute(suppuabize(124)) };
/// up + left on keypad
pub const NCKEY_ULEFT: char = unsafe { transmute(suppuabize(125)) };
pub const NCKEY_URIGHT: char = unsafe { transmute(suppuabize(126)) };
/// the most truly neutral of keypresses
pub const NCKEY_CENTER: char = unsafe { transmute(suppuabize(127)) };
pub const NCKEY_BEGIN: char = unsafe { transmute(suppuabize(128)) };
pub const NCKEY_CANCEL: char = unsafe { transmute(suppuabize(129)) };
pub const NCKEY_CLOSE: char = unsafe { transmute(suppuabize(130)) };
pub const NCKEY_COMMAND: char = unsafe { transmute(suppuabize(131)) };
pub const NCKEY_COPY: char = unsafe { transmute(suppuabize(132)) };
pub const NCKEY_EXIT: char = unsafe { transmute(suppuabize(133)) };
pub const NCKEY_PRINT: char = unsafe { transmute(suppuabize(134)) };
pub const NCKEY_REFRESH: char = unsafe { transmute(suppuabize(135)) };
// Mouse events. We try to encode some details into the char32_t (i.e. which
// button was pressed);, but some is embedded in the ncinput event. The release
// event is generic across buttons; callers must maintain state, if they care.
pub const NCKEY_BUTTON1: char = unsafe { transmute(suppuabize(201)) };
pub const NCKEY_BUTTON2: char = unsafe { transmute(suppuabize(202)) };
pub const NCKEY_BUTTON3: char = unsafe { transmute(suppuabize(203)) };
/// scrollwheel up
pub const NCKEY_BUTTON4: char = unsafe { transmute(suppuabize(204)) };
/// scrollwheel down
pub const NCKEY_BUTTON5: char = unsafe { transmute(suppuabize(205)) };
pub const NCKEY_BUTTON6: char = unsafe { transmute(suppuabize(206)) };
pub const NCKEY_BUTTON7: char = unsafe { transmute(suppuabize(207)) };
pub const NCKEY_BUTTON8: char = unsafe { transmute(suppuabize(208)) };
pub const NCKEY_BUTTON9: char = unsafe { transmute(suppuabize(209)) };
pub const NCKEY_BUTTON10: char = unsafe { transmute(suppuabize(210)) };
pub const NCKEY_BUTTON11: char = unsafe { transmute(suppuabize(211)) };
pub const NCKEY_RELEASE: char = unsafe { transmute(suppuabize(212)) };
// Synonyms (so far as we're concerned)
pub const NCKEY_SCROLL_UP: char = NCKEY_BUTTON4;
pub const NCKEY_SCROLL_DOWN: char = NCKEY_BUTTON5;
pub const NCKEY_RETURN: char = NCKEY_ENTER;
// Aliases, from the 128 characters common to ASCII+UTF8
pub const NCKEY_ESC: char = unsafe { transmute(0x1b) };
pub const NCKEY_SPACE: char = unsafe { transmute(0x20) };

@ -1,139 +0,0 @@
//! `NcInput` & `NcKey`
// functions manually reimplemented: 4
// ------------------------------------------
// (+) done: 4
// (#) test: 0
// ------------------------------------------
// + ncinput_equal_p
// + ncinput_nomod_p
// + nckey_mouse_p
// + nckey_supppuab_p
use crate::NcDim;
mod keycodes;
pub use keycodes::*;
/// Reads and decodes input events.
///
/// Reads from stdin and decodes the input to stdout, including synthesized
/// events and mouse events. Notcurses provides input from keyboards and mice.
/// Single Unicode codepoints are received from the keyboard, directly encoded
/// as `u32`.
///
/// The input system must deal with numerous keyboard signals which do not map
/// to Unicode code points. This includes the keypad arrows and function keys.
/// These "synthesized" codepoints are enumerated in , and mapped into the
/// Supplementary Private Use Area-B (U+100000..U+10FFFD).
/// Mouse button events are similarly mapped into the SPUA-B.
///
/// All events carry a ncinput structure with them.
/// For mouse events, the x and y coordinates are reported within this struct.
/// For all events, modifiers (e.g. "Alt") are carried as bools in this struct.
pub type NcInput = crate::bindings::ffi::ncinput;
/// New NcInput.
impl NcInput {
/// New empty NcInput.
pub const fn new_empty() -> NcInput {
NcInput {
id: 0,
y: 0,
x: 0,
alt: false,
shift: false,
ctrl: false,
seqnum: 0,
}
}
/// New NcInput.
pub const fn new(id: char) -> NcInput {
Self::with_all_args(id, None, None, false, false, false, 0)
}
/// New NcInput with alt key.
pub const fn with_alt(id: char) -> NcInput {
Self::with_all_args(id, None, None, true, false, false, 0)
}
/// New NcInput with shift key.
pub const fn with_shift(id: char) -> NcInput {
Self::with_all_args(id, None, None, false, true, false, 0)
}
/// New NcInput with ctrl key.
pub const fn with_ctrl(id: char) -> NcInput {
Self::with_all_args(id, None, None, false, false, true, 0)
}
/// New NcInput, expecting all the arguments.
pub const fn with_all_args(
id: char,
x: Option<NcDim>,
y: Option<NcDim>,
alt: bool,
shift: bool,
ctrl: bool,
seqnum: u64,
) -> NcInput {
let (ix, iy);
if let Some(x) = x {
ix = x as i32
} else {
ix = -1
};
if let Some(y) = y {
iy = y as i32
} else {
iy = -1
};
NcInput {
id: id as u32,
y: ix,
x: iy,
alt,
shift,
ctrl,
seqnum,
}
}
}
/// Compares two ncinput structs for data equality by doing a field-by-field
/// comparison for equality (excepting seqnum).
///
/// Returns true if the two are data-equivalent.
pub const fn ncinput_equal_p(n1: NcInput, n2: NcInput) -> bool {
if n1.id != n2.id {
return false;
}
if n1.y != n2.y || n1.x != n2.x {
return false;
}
// do not check seqnum
true
}
/// Are all the modifiers off (alt, control, shift)?
pub const fn ncinput_nomod_p(input: &NcInput) -> bool {
!input.alt && !input.ctrl && !input.shift
}
/// Is this [char] a Supplementary Private Use Area-B codepoint?
///
/// Links:
/// - <https://en.wikipedia.org/wiki/Private_Use_Areas>
/// - <https://codepoints.net/supplementary_private_use_area-b>
#[inline]
pub const fn nckey_supppuab_p(w: char) -> bool {
w as u32 >= 0x100000_u32 && w as u32 <= 0x10fffd_u32
}
/// Is the event a synthesized mouse event?
#[inline]
pub const fn nckey_mouse_p(r: char) -> bool {
r >= NCKEY_BUTTON1 && r <= NCKEY_RELEASE
}

@ -1,162 +0,0 @@
//! `libnotcurses-sys` is a low-level Rust wrapper for the [notcurses
//! C library](https://www.github.com/dankamongmen/notcurses/)
//!
//! *This is a work in progress.*
//!
//! This library is built with several layers of zero-overhead abstractions
//! over the C functions and pointers accessed through FFI.
//!
//! # How to use this library
//!
//! There are basically two ways: The [**Rust way**](#1-the-rust-way),
//! and the [**C way**](#2-the-c-way). (Or a mix of both).
//!
//! ## 1. The Rust way
//!
//! Where you use the safely wrapped types, with its methods and constructors,
//! and painless error handling, like this:
//!
//! ### Example
//!
//! ```rust
//! use libnotcurses_sys::*;
//!
//! # #[cfg(not(miri))]
//! fn main() -> NcResult<()> {
//! let mut nc = Nc::with_flags(NCOPTION_NO_ALTERNATE_SCREEN)?;
//! let plane = nc.stdplane();
//! plane.putstr("hello world")?;
//! nc.render()?;
//! nc.stop()?;
//! Ok(())
//! }
//! # #[cfg(miri)]
//! # fn main() {}
//! ```
//!
//! Although you still have to manually call the `stop()` method for [`Nc`] and
//! [`NcDirect`] objects, and the `destroy()` method for the rest of types that
//! allocate, (like [`NcPlane`], [`NcVisual`]…) at the end of their scope, since
//! the Drop trait is not implemented for any wrapping type in libnotcurses-sys.
//!
//! But they do implement methods and use [`NcResult`] as the return type,
//! for handling errors in the way we are used to in Rust.
//!
//! For the types that don't allocate, most are based on primitives like `i32`,
//! `u32`, `u64`… without a name in the C library. In Rust they are type aliased
//! (e.g.: [`NcChannel`], [`NcChannels`], [`NcRgb`], [`NcComponent`]…), to
//! leverage type checking, and they implement methods through [traits](#traits)
//! (e.g. [`NcChannelMethods`] must be in scope to use the `NcChannel` methods.
//!
//!
//! ## 2. The C way
//!
//! You can always use the C API functions directly if you prefer,
//! in a very similar way as the C library is used.
//!
//! It requires the use of unsafe, since most functions are wrapped directly
//! by `bindgen` marked as such.
//!
//! Error handling is done this way by checking the returned [`NcIntResult`],
//! or in case of receiving a pointer, by comparing it
//! to [null_mut()][core::ptr::null_mut].
//!
//! ### Example
//!
//! ```rust
//! use core::ptr::{null, null_mut};
//! use std::process::exit;
//!
//! use libnotcurses_sys::*;
//!
//! # #[cfg(not(miri))]
//! fn main() {
//! let options = ffi::notcurses_options {
//! termtype: null(),
//! renderfp: null_mut(),
//! loglevel: 0,
//! margin_t: 0,
//! margin_r: 0,
//! margin_b: 0,
//! margin_l: 0,
//! flags: NCOPTION_NO_ALTERNATE_SCREEN,
//! };
//! unsafe {
//! let nc = notcurses_init(&options, null_mut());
//! if nc.is_null() {
//! exit(1);
//! }
//! let plane = notcurses_stdplane(nc);
//! let cols = ncplane_putstr(&mut *plane, "hello world");
//! if cols < NCRESULT_OK {
//! notcurses_stop(nc);
//! exit(cols.abs());
//! }
//! if notcurses_stop(nc) < NCRESULT_OK {
//! exit(2);
//! }
//! }
//! }
//! # #[cfg(miri)]
//! # fn main() {}
//! ```
//!
//! ### The `notcurses` C API docs
//!
//! - [API reference (man pages)](https://notcurses.com/)
//! - [Wiki Page](https://nick-black.com/dankwiki/index.php/Notcurses)
//! - [The Book Guide (pdf)](https://nick-black.com/htp-notcurses.pdf)
//! - [USAGE.md](https://github.com/dankamongmen/notcurses/blob/master/USAGE.md)
//! - [HACKING.md](https://github.com/dankamongmen/notcurses/blob/master/doc/HACKING.md)
//! - [Doxygen Documentation](https://nick-black.com/notcurses/html/index.html)
//! - [FOSDEM 2021 presentation](https://fosdem.org/2021/schedule/event/notcurses/)
//!
#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case)]
#![allow(clippy::too_many_arguments, clippy::needless_doctest_main)]
mod bindings;
#[doc(inline)]
pub use bindings::*;
mod r#box;
mod capabilities;
mod cells;
mod channel;
mod dimension;
mod direct;
mod error;
mod fade;
mod file;
mod input;
mod macros;
mod metric;
mod notcurses;
mod palette;
mod pixel;
mod plane;
mod resizecb;
mod stats;
mod time;
mod visual;
pub mod widgets;
pub use crate::input::*;
pub use capabilities::*;
pub use cells::*;
pub use channel::*;
pub use dimension::*;
pub use direct::*;
pub use error::*;
pub use fade::*;
pub use file::*;
pub use macros::*;
pub use metric::*;
pub use notcurses::*;
pub use palette::*;
pub use pixel::*;
pub use plane::*;
pub use r#box::*;
pub use resizecb::*;
pub use stats::*;
pub use time::*;
pub use visual::*;

@ -1,276 +0,0 @@
//! Macros
//!
//
// NOTE: Use full paths everywhere. Don't assume anything will be in scope.
#[allow(unused_imports)]
// enjoy briefer doc comments
use crate::{Nc, NcDirect, NcError, NcPlane, NcResult, NCRESULT_ERR, NCRESULT_OK};
// Sleep, Render & Flush Macros ------------------------------------------------
/// Sleeps for `$s` seconds + `$ms` milliseconds
/// + `$us` microseconds + `$ns` nanoseconds
#[macro_export]
macro_rules! sleep {
($s:expr) => {
std::thread::sleep(std::time::Duration::from_secs($s));
};
($s:expr, $ms:expr) => {
std::thread::sleep(std::time::Duration::from_millis($s * 1000 + $ms));
};
($s:expr, $ms:expr, $us:expr) => {
std::thread::sleep(std::time::Duration::from_micros(
$s * 1_000_000 + $ms * 1_000 + $us,
));
};
($s:expr, $ms:expr, $us:expr, $ns:expr) => {
std::thread::sleep(std::time::Duration::from_nanos(
$s * 1_000_000_000 + $ms * 1_000_000 + $us * 1_000 + $ns,
));
};
}
/// notcurses render sleep:
/// [`Nc::render`][Nc#method.render]\(`$nc`\)? + [`sleep!`]`[$sleep_args]`.
///
/// Renders the `$nc` [`Nc`] object's standard plane pile and then,
/// if there's no error, calls the sleep macro with the rest of the arguments.
///
/// Returns [NcResult].
#[macro_export]
macro_rules! nrs {
($nc:expr, $( $sleep_args:expr),+ ) => {
crate::Nc::render($nc)?;
sleep![$( $sleep_args ),+];
};
($nc:expr, $( $sleep_args:expr),+ ,) => {
rsleep![$nc, $( $sleep_args ),* ]
};
}
/// plane render sleep:
/// [`NcPlane::render`][NcPlane#method.render]\(`$p`\)? +
/// [`NcPlane::rasterize`][NcPlane#method.rasterize]\(`$p`\)? +
/// [`sleep!`]`[$sleep_args]`.
///
/// Renders and rasterizes the `$p` [NcPlane] pile and then, if there are
/// no errors, calls the sleep macro with the rest of the arguments.
///
/// Returns [NcResult].
#[macro_export]
macro_rules! prs {
($p:expr, $( $sleep_args:expr),+ ) => {
crate::NcPlane::render($p)?;
crate::NcPlane::rasterize($p)?;
sleep![$( $sleep_args ),+];
};
($nc:expr, $( $sleep_args:expr),+ ,) => {
rsleep![$nc, $( $sleep_args ),* ]
};
}
/// [`NcDirect::flush`][NcDirect#method.flush]\(`$ncd`\)? + [`sleep!`]`[$sleep_args]`.
///
/// Flushes the `$ncd` [NcDirect] object and, if there's no error,
/// calls the sleep macro with the rest of the arguments.
///
/// Returns [NcResult].
#[macro_export]
#[deprecated]
#[doc(hidden)]
macro_rules! fsleep {
($ncd:expr, $( $sleep_args:expr),+ ) => {
// Rust style, with methods & NcResult
crate::NcDirect::flush($ncd)?;
sleep![$( $sleep_args ),+];
};
($ncd:expr, $( $sleep_args:expr),+ ,) => {
rsleep![$ncd, $( $sleep_args ),* ]
};
}
#[deprecated]
#[doc(hidden)]
#[allow(unused_macros)]
macro_rules! prsleep {
($p:expr, $( $sleep_args:expr),+ ) => {
prs![$p, $( $sleep_args ),+];
};
}
#[deprecated]
#[doc(hidden)]
#[allow(unused_macros)]
macro_rules! psleep {
($p:expr, $( $sleep_args:expr),+ ) => {
prs![$p, $( $sleep_args ),+];
};
}
#[deprecated]
#[doc(hidden)]
#[allow(unused_macros)]
macro_rules! rsleep {
($nc:expr, $( $sleep_args:expr),+ ) => {
nrs![$nc, $( $sleep_args ),+];
};
}
// String & Print Macros -------------------------------------------------------
/// Converts an `&str` into `*const c_char`.
#[macro_export]
#[doc(hidden)]
macro_rules! cstring {
($s:expr) => {
std::ffi::CString::new($s).unwrap().as_ptr()
};
}
/// Converts an `&str` into `*mut c_char`.
#[macro_export]
#[doc(hidden)]
macro_rules! cstring_mut {
($s:expr) => {
std::ffi::CString::new($s).unwrap().into_raw()
};
}
/// Converts a `*const c_char` into an `&str`.
#[macro_export]
#[doc(hidden)]
macro_rules! rstring {
($s:expr) => {
unsafe { std::ffi::CStr::from_ptr($s).to_str().unwrap() }
// possible alternative:
// unsafe { std::ffi::CStr::from_ptr($s).to_string_lossy() }
};
}
/// Wrapper around [libc::printf].
#[macro_export]
#[doc(hidden)]
macro_rules! printf {
($s:expr) => {
unsafe { libc::printf(cstring![$s]) }
};
($s:expr $(, $opt:expr)*) => {
unsafe { libc::printf(cstring![$s], $($opt),*) }
};
}
// Error Wrappers Macros -------------------------------------------------------
/// Returns an `Ok($ok)`,
/// or an `Err(`[`NcError`]`)` if `$res` < [`NCRESULT_OK`].
///
/// In other words:
/// Returns Ok(`$ok`) if `$res` >= [NCRESULT_OK], otherwise returns
/// Err([NcError]::[new][NcError#method.new](`$res`, `$msg`)).
///
/// `$ok` & `$msg` are optional. By default they will be the unit
/// type `()`, and an empty `&str` `""`, respectively.
#[macro_export]
#[doc(hidden)]
macro_rules! error {
($res:expr, $msg:expr, $ok:expr) => {{
let res = $res;
if res >= crate::NCRESULT_OK {
return Ok($ok);
} else {
return Err(crate::NcError::with_msg(res, $msg));
}
}};
($res:expr, $msg:expr) => {
error![$res, $msg, ()]
};
($res:expr) => {
error![$res, "", ()]
};
}
/// Returns an `Ok(&T)` from a `*const T` pointer,
/// or an `Err(`[`NcError`]`)` if the pointer is null.
///
/// In other words:
/// Returns Ok(&*`$ptr`) if `!$ptr.is_null()`, otherwise returns
/// Err([NcError]]::[new][NcError#method.new]([NCRESULT_ERR], `$msg`)).
///
/// `$msg` is optional. By default it will be an empty `&str` `""`.
#[macro_export]
#[doc(hidden)]
macro_rules! error_ref {
($ptr:expr, $msg:expr, $ok:expr) => {{
let ptr = $ptr; // avoid calling a function multiple times
if ptr.is_null() {
return Err(crate::NcError::with_msg(crate::NCRESULT_ERR, $msg));
} else {
#[allow(unused_unsafe)]
return Ok(unsafe { $ok });
}
}};
($ptr:expr, $msg:expr) => {{
let ptr = $ptr;
error_ref![$ptr, $msg, unsafe { &*ptr }];
}};
($ptr:expr) => {{
let ptr = $ptr;
error_ref![$ptr, "", unsafe { &*ptr }];
}};
}
/// Returns an `Ok(&mut T)` from a `*mut T` pointer,
/// or an `Err(`[`NcError`]`)` if the pointer is null.
///
/// In other words:
/// Returns Ok(&mut *`$ptr`) if `!$ptr._is_null()`, otherwise returns
/// Err([NcError]]::[new][NcError#method.new]([NCRESULT_ERR], `$msg`)).
///
/// `$msg` is optional. By default it will be an empty `&str` `""`.
#[macro_export]
#[doc(hidden)]
macro_rules! error_ref_mut {
($ptr:expr, $msg:expr, $ok:expr) => {{
let ptr = $ptr; // avoid calling a function multiple times
if ptr.is_null() {
return Err(crate::NcError::with_msg(crate::NCRESULT_ERR, $msg));
} else {
#[allow(unused_unsafe)]
return Ok(unsafe { $ok });
}
}};
($ptr:expr, $msg:expr) => {{
let ptr = $ptr;
error_ref_mut![ptr, $msg, unsafe { &mut *ptr }];
}};
($ptr:expr) => {{
let ptr = $ptr;
error_ref_mut![ptr, "", unsafe { &mut *ptr }];
}};
}
/// Returns an `Ok(String)` from a `*const` pointer to a C string,
/// or an `Err(`[`NcError`]`)` if the pointer is null.
///
/// In other words:
/// Returns Ok((&*`$str`).to_string()) if `!$str.is_null()`, otherwise returns
/// Err([NcError]]::[new][NcError#method.new]([NCRESULT_ERR], `$msg`)).
///
/// `$msg` is optional. By default it will be an empty `&str` `""`.
#[macro_export]
#[doc(hidden)]
macro_rules! error_str {
($str:expr, $msg:expr) => {
if !$str.is_null() {
#[allow(unused_unsafe)]
return Ok(unsafe { (&*$str).to_string() });
} else {
return Err(crate::NcError::with_msg(crate::NCRESULT_ERR, $msg));
}
};
($str:expr) => {
error_str![$str, ""];
};
}

@ -1,66 +0,0 @@
//! `NcMetric`
use crate::{cstring_mut, rstring};
// TODO: clarify, update and visibilize doc-comments
/// Takes an arbitrarily large number, and prints it into a fixed-size buffer by
/// adding the necessary SI suffix.
///
/// Usually, pass a `|[IB]PREFIXSTRLEN+1|-sized` buffer to generate up to
/// `|[IB]PREFIXCOLUMNS|` columns' worth of EGCs. The characteristic can occupy
/// up through `|mult-1|` characters (3 for 1000, 4 for 1024).
/// The mantissa can occupy either zero or two characters.
///
/// Floating-point is never used, because an IEEE758 double can only losslessly
/// represent integers through 2^53-1.
///
/// 2^64-1 is 18446744073709551615, 18.45E(xa). KMGTPEZY thus suffice to handle
/// an 89-bit uintmax_t. Beyond Z(etta) and Y(otta) lie lands unspecified by SI.
/// 2^-63 is 0.000000000000000000108, 1.08a(tto). val: value to print decimal:
/// scaling. '1' if none has taken place. buf: buffer in which string will be
/// generated omitdec: inhibit printing of all-0 decimal portions mult: base of
/// suffix system (almost always 1000 or 1024) uprefix: character to print
/// following suffix ('i' for kibibytes basically). only printed if suffix is
/// actually printed (input >= mult).
///
/// You are encouraged to consult notcurses_metric(3).
///
pub fn ncmetric(val: u64, decimal: u64, buf: &str, omitdec: i32, mult: u64, uprefix: i32) -> &str {
let buf = cstring_mut![buf];
rstring![crate::ffi::ncmetric(
val, decimal, buf, omitdec, mult, uprefix
)]
}
// The number of columns is one fewer, as the STRLEN expressions must leave
// an extra byte open in case 'µ' (U+00B5, 0xC2 0xB5) shows up.
// This is the true number of columns;
//
// to set up a printf()-style maximum field width,
// you should use [IB]PREFIXFMT (see below).
pub const NCMETRIC_PREFIXCOLUMNS: u32 = crate::bindings::ffi::PREFIXCOLUMNS;
// The maximum number of columns used by a mult == 1000 (standard)
// ncmetric() call.
pub const NCMETRIC_BPREFIXCOLUMNS: u32 = crate::bindings::ffi::BPREFIXCOLUMNS;
// IPREFIXCOLUMNS is the maximum number of columns used by a mult == 1024
// (digital information) ncmetric().
pub const NCMETRIC_IPREFIXCOLUMNS: u32 = crate::bindings::ffi::IPREFIXCOLUMNS;
//
// Does not include a '\0' (xxx.xxU)
pub const NCMETRIC_PREFIXSTRLEN: u32 = crate::bindings::ffi::PREFIXSTRLEN;
// The maximum number of columns used by a mult == 1024 call making use of
// the 'i' suffix.
// Does not include a '\0' (xxxx.xxUi), i == prefix
pub const NCMETRIC_BPREFIXSTRLEN: u32 = crate::bindings::ffi::BPREFIXSTRLEN;
// Does not include a '\0' (xxxx.xxU)
pub const NCMETRIC_IPREFIXSTRLEN: u32 = crate::bindings::ffi::IPREFIXSTRLEN;
// TODO:?
// WCHAR_MAX_UTF8BYTES

@ -1,10 +0,0 @@
use crate::{notcurses_init, Nc, NcOptions, NCOPTION_SUPPRESS_BANNERS};
/// Helper function for initializing Nc on C style tests.
#[allow(dead_code)]
pub(crate) unsafe fn notcurses_init_test<'a>() -> &'a mut Nc {
&mut *notcurses_init(
&NcOptions::with_flags(NCOPTION_SUPPRESS_BANNERS),
core::ptr::null_mut(),
)
}

@ -1,740 +0,0 @@
//! `Nc*` methods and associated functions.
use core::ptr::{null, null_mut};
use crate::{
cstring, error, error_ref_mut, notcurses_init, rstring, Nc, NcAlign, NcBlitter, NcChannels,
NcDim, NcError, NcFile, NcInput, NcLogLevel, NcOptions, NcPixelImpl, NcPlane, NcResult,
NcScale, NcStats, NcStyle, NcStyleMethods, NcTime, NCOPTION_NO_ALTERNATE_SCREEN,
NCOPTION_SUPPRESS_BANNERS, NCRESULT_ERR, NCSTYLE_BOLD, NCSTYLE_ITALIC, NCSTYLE_NONE,
NCSTYLE_STRUCK, NCSTYLE_UNDERCURL, NCSTYLE_UNDERLINE,
};
/// # `NcOptions` Constructors
impl NcOptions {
/// New NcOptions.
pub const fn new() -> Self {
Self::with_all_options(0, 0, 0, 0, 0, 0)
}
/// New NcOptions, with margins.
pub const fn with_margins(top: NcDim, right: NcDim, bottom: NcDim, left: NcDim) -> Self {
Self::with_all_options(0, top, right, bottom, left, 0)
}
/// New NcOptions, with flags.
pub const fn with_flags(flags: u64) -> Self {
Self::with_all_options(0, 0, 0, 0, 0, flags)
}
/// New NcOptions, with all the options.
///
/// ## Arguments
///
/// - loglevel
///
/// Progressively higher log levels result in more logging to stderr. By
/// default, nothing is printed to stderr once fullscreen service begins.
///
/// - margin_t, margin_r, margin_b, margin_l
///
/// Desirable margins (top, right, bottom, left).
///
/// If all are 0 (default), we will render to the entirety of the screen.
/// If the screen is too small, we do what we can.
/// Absolute coordinates are relative to the rendering area
/// ((0, 0) is always the origin of the rendering area).
///
/// - flags
///
/// General flags; This is expressed as a bitfield so that future options
/// can be added without reshaping the struct.
/// Undefined bits must be set to 0.
///
/// - [`NCOPTION_INHIBIT_SETLOCALE`][crate::NCOPTION_INHIBIT_SETLOCALE]
/// - [`NCOPTION_NO_ALTERNATE_SCREEN`]
/// - [`NCOPTION_NO_FONT_CHANGES`][crate::NCOPTION_NO_FONT_CHANGES]
/// - [`NCOPTION_NO_QUIT_SIGHANDLERS`][crate::NCOPTION_NO_QUIT_SIGHANDLERS]
/// - [`NCOPTION_NO_WINCH_SIGHANDLER`][crate::NCOPTION_NO_WINCH_SIGHANDLER]
/// - [`NCOPTION_SUPPRESS_BANNERS`]
///
pub const fn with_all_options(
loglevel: NcLogLevel,
margin_t: NcDim,
margin_r: NcDim,
margin_b: NcDim,
margin_l: NcDim,
flags: u64,
) -> Self {
Self {
termtype: null(),
loglevel,
renderfp: null_mut(),
margin_t: margin_t as i32,
margin_r: margin_r as i32,
margin_b: margin_b as i32,
margin_l: margin_l as i32,
flags,
}
}
}
/// # `Nc` Constructors
impl Nc {
/// New notcurses context (without banners).
pub fn new<'a>() -> NcResult<&'a mut Nc> {
Self::with_flags(NCOPTION_SUPPRESS_BANNERS)
}
/// New notcurses context, with banners.
///
/// This is the default in the C library.
pub fn with_banners<'a>() -> NcResult<&'a mut Nc> {
Self::with_flags(0)
}
/// New notcurses context, without an alternate screen (nor banners).
pub fn without_altscreen<'a>() -> NcResult<&'a mut Nc> {
Self::with_flags(NCOPTION_NO_ALTERNATE_SCREEN | NCOPTION_SUPPRESS_BANNERS)
}
/// New notcurses context, expects `NCOPTION_*` flags.
pub fn with_flags<'a>(flags: u64) -> NcResult<&'a mut Nc> {
Self::with_options(NcOptions::with_flags(flags))
}
/// New notcurses context, expects [NcOptions].
pub fn with_options<'a>(options: NcOptions) -> NcResult<&'a mut Nc> {
let res = unsafe { notcurses_init(&options, null_mut()) };
error_ref_mut![res, "Notcurses.with_options()"]
}
/// New notcurses context, expects [NcLogLevel] and flags.
pub fn with_debug<'a>(loglevel: NcLogLevel, flags: u64) -> NcResult<&'a mut Nc> {
Self::with_options(NcOptions::with_all_options(loglevel, 0, 0, 0, 0, flags))
}
}
/// # `Nc` methods
impl Nc {
/// Returns the offset into `availcols` at which `cols` ought be output given
/// the requirements of `align`.
///
/// Returns `-`[`NCRESULT_MAX`][crate::NCRESULT_MAX] if
/// [NCALIGN_UNALIGNED][crate::NCALIGN_UNALIGNED] or invalid [NcAlign].
///
/// *C style function: [notcurses_align()][crate::notcurses_align].*
//
// TODO: handle error rightfully.
pub fn align(availcols: NcDim, align: NcAlign, cols: NcDim) -> NcResult<()> {
error![crate::notcurses_align(availcols, align, cols)]
}
/// Retrieves the current contents of the specified [NcCell][crate::NcCell]
/// as last rendered, returning the `EGC` (or None on error) and writing
/// out the [`NcStyle`] and the [`NcChannels`].
///
// possible BUG? CHECK:
/// This `EGC` must be freed by the caller.
///
/// *C style function: [notcurses_at_yx()][crate::notcurses_at_yx].*
pub fn at_yx(
&mut self,
y: NcDim,
x: NcDim,
stylemask: &mut NcStyle,
channels: &mut NcChannels,
) -> Option<String> {
let egc = unsafe { crate::notcurses_at_yx(self, x as i32, y as i32, stylemask, channels) };
if egc.is_null() {
return None;
}
Some(rstring![egc].into())
}
/// Returns the bottommost [`NcPlane`] on the standard pile,
/// of which there is always at least one.
///
/// *C style function: [notcurses_bottom()][crate::notcurses_bottom].*
pub fn bottom(&mut self) -> &mut NcPlane {
unsafe { &mut *crate::notcurses_bottom(self) }
}
/// Returns true if we can reliably use Unicode Braille.
///
/// See also [NCBLIT_BRAILLE][crate::NCBLIT_BRAILLE].
///
/// *C style function: [notcurses_canbraille()][crate::notcurses_canbraille].*
pub fn canbraille(&self) -> bool {
unsafe { crate::notcurses_canbraille(self) }
}
/// Returns true if it's possible to set the "hardware" palette.
///
/// Requires the "ccc" terminfo capability.
///
/// *C style function: [notcurses_canchangecolor()][crate::notcurses_canchangecolor].*
pub fn canchangecolor(&self) -> bool {
unsafe { crate::notcurses_canchangecolor(self) }
}
/// Returns true if fading is possible.
///
/// Fading requires either the "rgb" or "ccc" terminfo capability.
///
/// *C style function: [notcurses_canfade()][crate::notcurses_canfade].*
pub fn canfade(&self) -> bool {
unsafe { crate::notcurses_canfade(self) }
}
/// Returns true if we can reliably use Unicode half blocks.
///
/// See also [NCBLIT_2x1][crate::NCBLIT_2x1].
///
/// *C style function: [notcurses_canhalfblock()][crate::notcurses_canhalfblock].*
pub fn canhalfblock(&self) -> bool {
unsafe { crate::notcurses_canhalfblock(self) }
}
/// Returns true if loading images is possible.
///
/// This requires being built against FFmpeg/OIIO.
///
/// *C style function: [notcurses_canopen_images()][crate::notcurses_canopen_images].*
pub fn canopen_images(&self) -> bool {
unsafe { crate::notcurses_canopen_images(self) }
}
/// Returns true if loading videos is possible.
///
/// This requires being built against FFmpeg.
///
/// *C style function: [notcurses_canopen_videos()][crate::notcurses_canopen_videos].*
pub fn canopen_videos(&self) -> bool {
unsafe { crate::notcurses_canopen_videos(self) }
}
/// Returns true if we can reliably use Unicode quadrant blocks.
///
/// See also [NCBLIT_2x2][crate::NCBLIT_2x2].
///
/// *C style function: [notcurses_canquadrant()][crate::notcurses_canquadrant].*
pub fn canquadrant(&self) -> bool {
unsafe { crate::notcurses_canquadrant(self) }
}
/// Returns true if we can reliably use Unicode 13 sextants.
///
/// See also [NCBLIT_3x2][crate::NCBLIT_3x2].
///
/// *C style function: [notcurses_cansextant()][crate::notcurses_cansextant].*
pub fn cansextant(&self) -> bool {
unsafe { crate::notcurses_cansextant(self) }
}
/// Returns true if it's possible to directly specify RGB values per cell,
/// or false if it's only possible to use palettes.
///
/// *C style function: [notcurses_cantruecolor()][crate::notcurses_cantruecolor].*
pub fn cantruecolor(&self) -> bool {
unsafe { crate::notcurses_cantruecolor(self) }
}
/// Returns true if the encoding is UTF-8.
///
/// Requires `LANG` being set to a UTF-8 locale.
///
/// *C style function: [notcurses_canutf8()][crate::notcurses_canutf8].*
pub fn canutf8(&self) -> bool {
unsafe { crate::notcurses_canutf8(self) }
}
/// Checks for pixel support.
///
/// Returns [`NcPixelImpl`] with a non-zero constant corresponding to some
/// pixel-blitting mechanism if bitmap support (via any mechanism) has been
/// detected, or else 0 (NCPIXEL_NONE).
///
/// *C style function: [notcurses_check_pixel_support()][crate::notcurses_check-pixel_support].*
#[allow(clippy::wildcard_in_or_patterns)]
pub fn check_pixel_support(&self) -> NcPixelImpl {
unsafe { crate::notcurses_check_pixel_support(self) }
}
/// Disables the terminal's cursor, if supported.
///
/// Immediate effect (no need for a call to notcurses_render()).
///
/// *C style function: [notcurses_cursor_disable()][crate::notcurses_cursor_disable].*
pub fn cursor_disable(&mut self) -> NcResult<()> {
error![unsafe { crate::notcurses_cursor_disable(self) }]
}
/// Enables the terminal's cursor, if supported, placing it at `y`, `x`.
///
/// Immediate effect (no need for a call to notcurses_render()).
/// It is an error if `y`, `x` lies outside the standard plane.
///
/// *C style function: [notcurses_cursor_enable()][crate::notcurses_cursor_enable].*
pub fn cursor_enable(&mut self, y: NcDim, x: NcDim) -> NcResult<()> {
error![unsafe { crate::notcurses_cursor_enable(self, y as i32, x as i32) }]
}
/// Dumps notcurses state to the supplied `debugfp`.
///
/// Output is freeform, and subject to change. It includes geometry of all
/// planes, from all piles.
///
/// *C style function: [notcurses_debug()][crate::notcurses_debug].*
pub fn debug(&mut self, debugfp: &mut NcFile) {
unsafe {
crate::notcurses_debug(self, debugfp.as_nc_ptr());
}
}
/// Returns the name of the detected terminal.
///
/// *C style function: [notcurses_detected_terminal()][crate::notcurses_detected_terminal].*
pub fn detected_terminal(&self) -> String {
rstring![crate::notcurses_detected_terminal(self)].to_string()
}
/// Destroys all [`NcPlane`]s other than the stdplane.
///
/// *C style function: [notcurses_drop_planes()][crate::notcurses_drop_planes].*
pub fn drop_planes(&mut self) {
unsafe {
crate::notcurses_drop_planes(self);
}
}
/// Returns a [char] representing a single unicode point.
///
/// If an event is processed, the return value is the `id` field from that
/// event.
///
/// Provide a None `time` to block at length, a `time` of 0 for non-blocking
/// operation, and otherwise a timespec to bound blocking.
///
/// *C style function: [notcurses_getc()][crate::notcurses_getc].*
pub fn getc(&mut self, time: Option<NcTime>, input: Option<&mut NcInput>) -> NcResult<char> {
let ntime;
if let Some(time) = time {
ntime = &time as *const _;
} else {
ntime = null();
}
let ninput;
if let Some(input) = input {
ninput = input as *mut _;
} else {
ninput = null_mut();
}
let c =
unsafe { core::char::from_u32_unchecked(crate::notcurses_get(self, ntime, ninput)) };
if c as u32 as i32 == NCRESULT_ERR {
return Err(NcError::new());
}
Ok(c)
}
/// If no event is ready, returns 0.
///
/// *C style function: [notcurses_getc_nblock()][crate::notcurses_getc_nblock].*
pub fn getc_nblock(&mut self, input: &mut NcInput) -> char {
crate::notcurses_getc_nblock(self, input)
}
/// Blocks until a codepoint or special key is read,
/// or until interrupted by a signal.
///
/// In the case of a valid read, a 32-bit Unicode codepoint is returned.
///
/// Optionally writes the event details in `input`.
///
/// *C style function: [notcurses_getc_blocking()][crate::notcurses_getc_blocking].*
pub fn getc_blocking(&mut self, input: Option<&mut NcInput>) -> NcResult<char> {
let input_txt;
if cfg!(debug_assertions) {
input_txt = format!("{:?}", input);
} else {
input_txt = String::from("");
}
let res = crate::notcurses_getc_blocking(self, input);
// An invalid read is indicated with -1
if res as u32 as i32 != -1 {
Ok(res)
} else {
error![-1, &format!("Nc.getc_blocking({:?})", input_txt), res]
}
}
/// Gets a file descriptor suitable for input event poll()ing.
///
/// When this descriptor becomes available, you can call
/// [getc_nblock()][Nc#method.getc_nblock], and input ought be ready.
///
/// This file descriptor is not necessarily the file descriptor associated
/// with stdin (but it might be!).
///
/// *C style function: [notcurses_inputready_fd()][crate::notcurses_inputready_fd].*
pub fn inputready_fd(&mut self) -> NcResult<()> {
error![unsafe { crate::notcurses_inputready_fd(self) }]
}
/// Returns an [`NcBlitter`] from a string representation.
///
/// *C style function: [notcurses_lex_blitter()][crate::notcurses_lex_blitter].*
pub fn lex_blitter(blitter_str: &str) -> NcResult<NcBlitter> {
let mut blitter = 0;
error![
unsafe { crate::notcurses_lex_blitter(cstring![blitter_str], &mut blitter) },
"Invalid blitter name", blitter
]
}
/// Lexes a margin argument according to the standard notcurses definition.
///
/// There can be either a single number, which will define all margins equally,
/// or there can be four numbers separated by commas.
///
/// *C style function: [notcurses_lex_margins()][crate::notcurses_lex_margins].*
pub fn lex_margins(margins_str: &str, options: &mut NcOptions) -> NcResult<()> {
error![unsafe { crate::notcurses_lex_margins(cstring![margins_str], options) }]
}
/// Returns an [`NcScale`] from a string representation.
///
/// *C style function: [notcurses_lex_scalemode()][crate::notcurses_lex_scalemode].*
pub fn lex_scalemode(scalemode_str: &str) -> NcResult<NcScale> {
let mut scalemode = 0;
error![
unsafe { crate::notcurses_lex_scalemode(cstring![scalemode_str], &mut scalemode) },
"", scalemode
]
}
/// Returns an [`NcStyle`] from a string representation.
///
/// It is case-insensitive, and supports multiple styles separated by
/// spaces.
///
/// The supported styles are: `italic`, `underline`, `undercurl`,
/// `struck`, `bold`, and `none`.
///
/// If a style is are not recognized returns an error.
///
/// *(No equivalent C style function)*
pub fn lex_styles(styles_str: &str) -> NcResult<NcStyle> {
let mut style = NCSTYLE_NONE;
let mut errstr = String::new();
for s in styles_str.split(' ') {
match s.to_lowercase().as_str() {
"italic" => style.add(NCSTYLE_ITALIC),
"underline" => style.add(NCSTYLE_UNDERLINE),
"undercurl" => style.add(NCSTYLE_UNDERCURL),
"struck" => style.add(NCSTYLE_STRUCK),
"bold" => style.add(NCSTYLE_BOLD),
"none" => (),
_ => {
errstr.push_str(s);
errstr.push(' ');
}
}
}
if errstr.is_empty() {
Ok(style)
} else {
let _ = errstr.pop();
Err(NcError::new_msg(&format![
"the following styles are not recognized: '{}'",
errstr
]))
}
}
/// Disables signals originating from the terminal's line discipline, i.e.
/// SIGINT (^C), SIGQUIT (^), and SIGTSTP (^Z). They are enabled by default.
///
/// *C style function: [notcurses_linesigs_disable()][crate::notcurses_linesigs_disable].*
pub fn linesigs_disable(&mut self) -> NcResult<()> {
error![unsafe { crate::notcurses_linesigs_disable(self) }]
}
/// Restores signals originating from the terminal's line discipline, i.e.
/// SIGINT (^C), SIGQUIT (^), and SIGTSTP (^Z), if disabled.
///
/// *C style function: [notcurses_linesigs_enable()][crate::notcurses_linesigs_enable].*
pub fn linesigs_enable(&mut self) -> NcResult<()> {
error![unsafe { crate::notcurses_linesigs_enable(self) }]
}
/// Disables mouse events.
///
/// Any events in the input queue can still be delivered.
///
/// *C style function: [notcurses_mouse_disable()][crate::notcurses_mouse_disable].*
pub fn mouse_disable(&mut self) -> NcResult<()> {
error![unsafe { crate::notcurses_mouse_disable(self) }]
}
/// Enable the mouse in "button-event tracking" mode with focus detection
/// and UTF8-style extended coordinates.
///
/// On success, mouse events will be published to [getc()][Nc#method.getc].
///
/// *C style function: [notcurses_mouse_enable()][crate::notcurses_mouse_enable].*
pub fn mouse_enable(&mut self) -> NcResult<()> {
error![
unsafe { crate::notcurses_mouse_enable(self) },
"Nc.mouse_enable()"
]
}
/// Returns the number of simultaneous colors claimed to be supported,
/// if there is color support.
///
/// Note that several terminal emulators advertise more colors than they
/// actually support, downsampling internally.
///
/// *C style function: [notcurses_palette_size()][crate::notcurses_palette_size].*
pub fn palette_size(&self) -> NcResult<u32> {
let res = unsafe { crate::notcurses_palette_size(self) };
if res == 1 {
return Err(NcError::with_msg(1, "No color support ← Nc.palette_size()"));
}
Ok(res)
}
/// Refreshes the physical screen to match what was last rendered (i.e.,
/// without reflecting any changes since the last call to
/// [`render`][crate::Nc#method.render]).
///
/// Returns the current screen geometry (`y`, `x`).
///
/// This is primarily useful if the screen is externally corrupted, or if an
/// [NCKEY_RESIZE][crate::NCKEY_RESIZE] event has been read and you're not
/// yet ready to render.
///
/// *C style function: [notcurses_refresh()][crate::notcurses_refresh].*
//
pub fn refresh(&mut self) -> NcResult<(NcDim, NcDim)> {
let (mut y, mut x) = (0, 0);
error![
unsafe { crate::notcurses_refresh(self, &mut y, &mut x) },
"",
(y as NcDim, x as NcDim)
]
}
/// Renders and rasterizes the standard pile in one shot. Blocking call.
///
/// *C style function: [notcurses_render()][crate::notcurses_render].*
pub fn render(&mut self) -> NcResult<()> {
error![unsafe { crate::notcurses_render(self) }, "Nc.render()"]
}
/// Performs the rendering and rasterization portion of
/// [`render`][Nc#method.render] but do not write the resulting buffer
/// out to the terminal.
///
/// Using this function, the user can control the writeout process,
/// and render a second frame while writing another.
///
// possible BUG? CHECK:
/// The returned buffer must be freed by the caller.
///
/// *C style function: [notcurses_render_to_buffer()][crate::notcurses_render_to_buffer].*
//
// CHECK that this works.
pub fn render_to_buffer(&mut self, buffer: &mut Vec<u8>) -> NcResult<()> {
#[allow(unused_mut)] // CHECK whether it actually works without the mut
let mut len = buffer.len() as u32;
// https://github.com/dankamongmen/notcurses/issues/1339
#[cfg(any(target_arch = "x86_64", target_arch = "i686", target_arch = "x86"))]
let mut buf = buffer.as_mut_ptr() as *mut i8;
#[cfg(not(any(target_arch = "x86_64", target_arch = "i686", target_arch = "x86")))]
let mut buf = buffer.as_mut_ptr() as *mut u8;
error![unsafe { crate::notcurses_render_to_buffer(self, &mut buf, &mut len.into()) }]
}
/// Writes the last rendered frame, in its entirety, to 'fp'.
///
/// If [`render`][Nc#method.render] has not yet been called,
/// nothing will be written.
///
/// *C style function: [notcurses_render_to_file()][crate::notcurses_render_to_file].*
pub fn render_to_file(&mut self, fp: &mut NcFile) -> NcResult<()> {
error![unsafe { crate::notcurses_render_to_file(self, fp.as_nc_ptr()) }]
}
/// Acquires an atomic snapshot of the notcurses object's stats.
///
/// *C style function: [notcurses_stats()][crate::notcurses_stats].*
pub fn stats(&mut self, stats: &mut NcStats) {
unsafe {
crate::notcurses_stats(self, stats);
}
}
/// Allocates an [`NcStats`] object.
///
/// Use this rather than allocating your own, since future versions of
/// notcurses might enlarge this structure.
///
/// *C style function: [notcurses_stats_alloc()][crate::notcurses_stats_alloc].*
pub fn stats_alloc(&mut self) -> &mut NcStats {
unsafe { &mut *crate::notcurses_stats_alloc(self) }
}
/// Resets all cumulative stats (immediate ones, such as fbbytes, are not reset).
///
/// *C style function: [notcurses_stats_reset()][crate::notcurses_stats_reset].*
pub fn stats_reset(&mut self, stats: &mut NcStats) {
unsafe {
crate::notcurses_stats_reset(self, stats);
}
}
// TODO: decide what to do with these two:
//
// /// [notcurses_stdplane()][crate::notcurses_stdplane], plus free bonus
// /// dimensions written to non-NULL y/x!
// ///
// /// *C style function: [notcurses_stddim_yx()][crate::notcurses_stddim_yx].*
// #[inline]
// pub fn stddim_yx<'a>(
// &'a mut self,
// y: &mut NcDim,
// x: &mut NcDim,
// ) -> NcResult<&'a mut NcPlane> {
// crate::notcurses_stddim_yx(self, y, x)
// }
// /// [stdplane_const()][Notcurses#method.stdplane_const], plus free
// /// bonus dimensions written to non-NULL y/x!
// ///
// /// *C style function: [notcurses_stddim_yx()][crate::notcurses_stddim_yx].*
// #[inline]
// pub fn stddim_yx_const<'a>(
// &'a self,
// y: &mut NcDim,
// x: &mut NcDim,
// ) -> NcResult<&'a NcPlane> {
// crate::notcurses_stddim_yx_const(self, y, x)
// }
/// Returns a mutable reference to the standard [`NcPlane`] for this terminal.
///
/// The standard plane always exists, and its origin is always at the
/// uppermost, leftmost cell.
///
/// *C style function: [notcurses_stdplane()][crate::notcurses_stdplane].*
pub fn stdplane<'a>(&mut self) -> &'a mut NcPlane {
unsafe { &mut *crate::notcurses_stdplane(self) }
}
/// Returns a reference to the standard [`NcPlane`] for this terminal.
///
/// The standard plane always exists, and its origin is always at the
/// uppermost, leftmost cell.
///
/// *C style function: [notcurses_stdplane_const()][crate::notcurses_stdplane_const].*
pub fn stdplane_const<'a>(&self) -> &'a NcPlane {
unsafe { &*crate::notcurses_stdplane_const(self) }
}
/// Destroys the notcurses context.
///
/// *C style function: [notcurses_stop()][crate::notcurses_stop].*
pub fn stop(&mut self) -> NcResult<()> {
error![unsafe { crate::notcurses_stop(self) }]
}
/// Gets the name of an [`NcBlitter`] blitter.
///
/// *C style function: [notcurses_str_blitter()][crate::notcurses_str_blitter].*
pub fn str_blitter(blitter: NcBlitter) -> String {
rstring![crate::notcurses_str_blitter(blitter)].to_string()
}
/// Gets the name of an [`NcScale`] scaling mode.
///
/// *C style function: [notcurses_str_scalemode()][crate::notcurses_str_scalemode].*
pub fn str_scalemode(scalemode: NcScale) -> String {
rstring![crate::notcurses_str_scalemode(scalemode)].to_string()
}
/// Gets the lowercase name (or names) of the styles included in an [`NcStyle`].
///
/// *(No equivalent C style function)*
pub fn str_styles(style: NcStyle) -> String {
let mut string = String::new();
for s in style.to_vec() {
string.push_str(match s {
NCSTYLE_ITALIC => "italic",
NCSTYLE_UNDERLINE => "underline",
NCSTYLE_UNDERCURL => "undercurl",
NCSTYLE_STRUCK => "struck",
NCSTYLE_BOLD => "bold",
#[allow(unreachable_patterns)] // FIXME
NCSTYLE_NONE => "none",
_ => "none",
});
string.push(' ');
}
let _ = string.pop();
string
}
/// Returns an [`NcStyle`] with the supported curses-style attributes.
///
/// The attribute is only indicated as supported if the terminal can support
/// it together with color.
///
/// For more information, see the "ncv" capability in terminfo(5).
///
/// *C style function: [notcurses_supported_styles()][crate::notcurses_supported_styles].*
pub fn supported_styles(&self) -> NcStyle {
unsafe { crate::notcurses_supported_styles(self) as NcStyle }
}
/// Returns our current idea of the terminal dimensions in rows and cols.
///
/// *C style function: [notcurses_term_dim_yx()][crate::notcurses_term_dim_yx].*
pub fn term_dim_yx(&self) -> (NcDim, NcDim) {
crate::notcurses_term_dim_yx(self)
}
/// Returns the topmost [`NcPlane`], of which there is always at least one.
///
/// *C style function: [notcurses_top()][crate::notcurses_top].*
pub fn top(&mut self) -> &mut NcPlane {
unsafe { &mut *crate::notcurses_top(self) }
}
/// Returns a human-readable string describing the running notcurses version.
///
/// *C style function: [notcurses_version()][crate::notcurses_version].*
pub fn version() -> String {
rstring![crate::notcurses_version()].to_string()
}
/// Returns the running notcurses version components
/// (major, minor, patch, tweak).
///
/// *C style function: [notcurses_version_components()][crate::notcurses_version_components].*
pub fn version_components() -> (u32, u32, u32, u32) {
let (mut major, mut minor, mut patch, mut tweak) = (0, 0, 0, 0);
unsafe {
crate::notcurses_version_components(&mut major, &mut minor, &mut patch, &mut tweak);
}
(major as u32, minor as u32, patch as u32, tweak as u32)
}
}

@ -1,247 +0,0 @@
//! `Nc`
// total: 53
// ---------------------------------------------------
// (X) 1 : wont do
// (…) 4 : TODO / WIP
//
// (f) 45 : unsafe ffi function exported by bindgen
// (w) 0 : safely wrapped ffi function
// (r) 6 : static function manually reimplemented
//
// (m) 38 : method implemented
//
// (t) 13 : unit test done for the function
// (T) 0 : unit test done also for the method
// ---------------------------------------------------
// fm notcurses_at_yx
// fm notcurses_bottom
// fm notcurses_canbraille
// fmt notcurses_canchangecolor
// fmt notcurses_canfade
// fmt notcurses_canopen_images
// fmt notcurses_canopen_videos
// fmt notcurses_cansextant
// fmt notcurses_cantruecolor
// fmt notcurses_canutf8
// fm notcurses_check_pixel_support
//~f notcurses_core_init
// fm notcurses_cursor_disable
// fm notcurses_cursor_enable
// f notcurses_cursor_yx
// fmt notcurses_debug
//~f notcurses_detected_terminal
// fmt notcurses_drop_planes
// fm notcurses_getc
// fmt notcurses_init
// fm notcurses_inputready_fd
// fm notcurses_lex_blitter
// fm notcurses_lex_margins
// fm notcurses_lex_scalemode
// fm notcurses_linesigs_disable
// fm notcurses_linesigs_enable
// fm notcurses_mouse_disable
// fm notcurses_mouse_enable
// fm notcurses_palette_size
// fm notcurses_refresh
// fm notcurses_render
// fm notcurses_render_to_buffer
// fm notcurses_render_to_file
// fm notcurses_stats
// fm notcurses_stats_alloc
// fm notcurses_stats_reset
// fm notcurses_stdplane
// fm notcurses_stdplane_const
// fmt notcurses_stop
// fm notcurses_str_blitter
// fm notcurses_str_scalemode
// fm notcurses_supported_styles
// fm notcurses_top
//X notcurses_ucs32_to_utf8 (not needed in rust)
// fmt notcurses_version
// fm notcurses_version_components
// rmt notcurses_align
// rm notcurses_getc_blocking
// rm notcurses_getc_nblock
//~r notcurses_stddim_yx // multiple mutable references errors
//~r notcurses_stddim_yx_const //
// rm notcurses_term_dim_yx
#[cfg(test)]
mod test;
mod helpers;
mod methods;
mod reimplemented;
#[allow(unused_imports)]
pub(crate) use helpers::*;
pub use reimplemented::*;
/// The full **notcurses** context.
///
/// It's built atop the terminfo abstraction layer to provide reasonably
/// portable vivid character displays.
pub type Nc = crate::bindings::ffi::notcurses;
#[deprecated]
#[doc(hidden)]
pub type Notcurses = Nc;
/// Options struct for [`Notcurses`]
pub type NcOptions = crate::bindings::ffi::notcurses_options;
#[deprecated]
#[doc(hidden)]
pub type NotcursesOptions = NcOptions;
/// Do not call setlocale()
///
/// notcurses_init() will call setlocale() to inspect the current locale. If
/// that locale is "C" or "POSIX", it will call setlocale(LC_ALL, "") to set
/// the locale according to the LANG environment variable. Ideally, this will
/// result in UTF8 being enabled, even if the client app didn't call
/// setlocale() itself. Unless you're certain that you're invoking setlocale()
/// prior to notcurses_init(), you should not set this bit. Even if you are
/// invoking setlocale(), this behavior shouldn't be an issue unless you're
/// doing something weird (setting a locale not based on LANG).
pub const NCOPTION_INHIBIT_SETLOCALE: u64 = crate::bindings::ffi::NCOPTION_INHIBIT_SETLOCALE as u64;
/// Do not enter alternate mode.
///
/// If smcup/rmcup capabilities are indicated, notcurses defaults to making use
/// of the "alternate screen". This flag inhibits use of smcup/rmcup.
pub const NCOPTION_NO_ALTERNATE_SCREEN: u64 =
crate::bindings::ffi::NCOPTION_NO_ALTERNATE_SCREEN as u64;
/// Do not try to clear any preexisting bitmaps.
///
/// Note that they might still get cleared even if this is set, and they might
/// not get cleared even if this is not set.
pub const NCOPTION_NO_CLEAR_BITMAPS: u64 = crate::bindings::ffi::NCOPTION_NO_CLEAR_BITMAPS as u64;
/// Do not modify the font.
///
/// Notcurses might attempt to change the font slightly, to support certain
/// glyphs (especially on the Linux console). If this is set, no such
/// modifications will be made. Note that font changes will not affect anything
/// but the virtual console/terminal in which notcurses is running.
pub const NCOPTION_NO_FONT_CHANGES: u64 = crate::bindings::ffi::NCOPTION_NO_FONT_CHANGES as u64;
/// Do not handle SIG{ING, SEGV, ABRT, QUIT}.
///
/// A signal handler will usually be installed for SIGINT, SIGQUIT, SIGSEGV,
/// SIGTERM, and SIGABRT, cleaning up the terminal on such exceptions.
/// With this flag, the handler will not be installed.
pub const NCOPTION_NO_QUIT_SIGHANDLERS: u64 =
crate::bindings::ffi::NCOPTION_NO_QUIT_SIGHANDLERS as u64;
/// Do not handle SIGWINCH.
///
/// A signal handler will usually be installed for SIGWINCH, resulting in
/// NCKEY_RESIZE events being generated on input.
/// With this flag, the handler will not be installed.
pub const NCOPTION_NO_WINCH_SIGHANDLER: u64 =
crate::bindings::ffi::NCOPTION_NO_WINCH_SIGHANDLER as u64;
/// Initialize the standard plane's virtual cursor to match the physical cursor
/// at context creation time.
///
/// Together with [`NCOPTION_NO_ALTERNATE_SCREEN`] and a scrolling standard plane,
/// this facilitates easy scrolling-style programs in rendered mode.
pub const NCOPTION_PRESERVE_CURSOR: u64 = crate::bindings::ffi::NCOPTION_PRESERVE_CURSOR as u64;
/// Do not print banners.
///
/// Notcurses typically prints version info in notcurses_init() and performance
/// info in notcurses_stop(). This inhibits that output.
pub const NCOPTION_SUPPRESS_BANNERS: u64 = crate::bindings::ffi::NCOPTION_SUPPRESS_BANNERS as u64;
// NcLogLevel ------------------------------------------------------------------
/// Log level for [`NcOptions`]
///
/// These log levels consciously map cleanly to those of libav; notcurses itself
/// does not use this full granularity. The log level does not affect the opening
/// and closing banners, which can be disabled via the `NcOptions`
/// `NCOPTION_SUPPRESS_BANNERS`.
/// Note that if stderr is connected to the same terminal on which we're
/// rendering, any kind of logging will disrupt the output.
pub type NcLogLevel = crate::bindings::ffi::ncloglevel_e;
/// this is honestly a bit much
pub const NCLOGLEVEL_DEBUG: NcLogLevel = crate::bindings::ffi::ncloglevel_e_NCLOGLEVEL_DEBUG;
/// we can't keep doin' this, but we can do other things
pub const NCLOGLEVEL_ERROR: NcLogLevel = crate::bindings::ffi::ncloglevel_e_NCLOGLEVEL_ERROR;
/// we're hanging around, but we've had a horrible fault
pub const NCLOGLEVEL_FATAL: NcLogLevel = crate::bindings::ffi::ncloglevel_e_NCLOGLEVEL_FATAL;
/// "detailed information
pub const NCLOGLEVEL_INFO: NcLogLevel = crate::bindings::ffi::ncloglevel_e_NCLOGLEVEL_INFO;
/// print diagnostics immediately related to crashing
pub const NCLOGLEVEL_PANIC: NcLogLevel = crate::bindings::ffi::ncloglevel_e_NCLOGLEVEL_PANIC;
/// default. print nothing once fullscreen service begins
pub const NCLOGLEVEL_SILENT: NcLogLevel = crate::bindings::ffi::ncloglevel_e_NCLOGLEVEL_SILENT;
/// there's probably a better way to do what you want
pub const NCLOGLEVEL_TRACE: NcLogLevel = crate::bindings::ffi::ncloglevel_e_NCLOGLEVEL_TRACE;
/// "detailed information
pub const NCLOGLEVEL_VERBOSE: NcLogLevel = crate::bindings::ffi::ncloglevel_e_NCLOGLEVEL_VERBOSE;
/// you probably don't want what's happening to happen
pub const NCLOGLEVEL_WARNING: NcLogLevel = crate::bindings::ffi::ncloglevel_e_NCLOGLEVEL_WARNING;
// NcAlign ---------------------------------------------------------------------
/// Alignment within a plane or terminal.
/// Left/right-justified, or centered.
///
/// ## Defined constants
///
/// - [NCALIGN_UNALIGNED]
/// - [NCALIGN_LEFT]
/// - [NCALIGN_CENTER]
/// - [NCALIGN_RIGHT]
pub type NcAlign = crate::bindings::ffi::ncalign_e;
/// Left alignment within an [`NcPlane`][crate::NcPlane] or terminal.
pub const NCALIGN_LEFT: NcAlign = crate::bindings::ffi::ncalign_e_NCALIGN_LEFT;
/// Right alignment within an [`NcPlane`][crate::NcPlane] or terminal.
pub const NCALIGN_RIGHT: NcAlign = crate::bindings::ffi::ncalign_e_NCALIGN_RIGHT;
/// Center alignment within an [`NcPlane`][crate::NcPlane] or terminal.
pub const NCALIGN_CENTER: NcAlign = crate::bindings::ffi::ncalign_e_NCALIGN_CENTER;
/// Do not align an [`NcPlane`][crate::NcPlane] or terminal.
pub const NCALIGN_UNALIGNED: NcAlign = crate::bindings::ffi::ncalign_e_NCALIGN_UNALIGNED;
// NcPixelImpl -----------------------------------------------------------------
/// Pixel blitting implementations. (Informative only).
///
/// Returned by [`check_pixel_support`][Notcurses#method.check_pixel_support].
pub type NcPixelImpl = crate::bindings::ffi::ncpixelimpl_e;
/// No pixel support.
pub const NCPIXEL_NONE: NcPixelImpl = crate::bindings::ffi::ncpixelimpl_e_NCPIXEL_NONE;
/// Sixel
pub const NCPIXEL_SIXEL: NcPixelImpl = crate::bindings::ffi::ncpixelimpl_e_NCPIXEL_SIXEL;
/// Linux framebuffer.
pub const NCPIXEL_LINUXFB: NcPixelImpl = crate::bindings::ffi::ncpixelimpl_e_NCPIXEL_LINUXFB;
/// iTerm2
pub const NCPIXEL_ITERM2: NcPixelImpl = crate::bindings::ffi::ncpixelimpl_e_NCPIXEL_ITERM2;
/// Kitty prior to C=1 and animation.
pub const NCPIXEL_KITTY_STATIC: NcPixelImpl =
crate::bindings::ffi::ncpixelimpl_e_NCPIXEL_KITTY_STATIC;
/// Kitty with animation but not reflexive composition.
pub const NCPIXEL_KITTY_ANIMATED: NcPixelImpl =
crate::bindings::ffi::ncpixelimpl_e_NCPIXEL_KITTY_ANIMATED;
/// Kitty with reflexive composition.
pub const NCPIXEL_KITTY_SELFREF: NcPixelImpl =
crate::bindings::ffi::ncpixelimpl_e_NCPIXEL_KITTY_SELFREF;

@ -1,119 +0,0 @@
//! `notcurses_*` reimplemented functions.
use core::ptr::{null, null_mut};
use crate::{
Nc, NcAlign, NcDim, NcError, NcInput, NcOffset, NcPlane, NcResult, NcTime, NCALIGN_CENTER,
NCALIGN_LEFT, NCALIGN_RIGHT, NCRESULT_MAX,
};
/// Returns the offset into `availcols` at which `cols` ought be output given
/// the requirements of `align`.
///
/// Returns `-`[`NCRESULT_MAX`] if [NCALIGN_UNALIGNED][crate::NCALIGN_UNALIGNED]
/// or invalid [NcAlign].
///
/// *Method: Nc.[align()][Nc#method.align].*
#[inline]
pub fn notcurses_align(availcols: NcDim, align: NcAlign, cols: NcDim) -> NcOffset {
if align == NCALIGN_LEFT {
return 0;
}
if cols > availcols {
return 0;
}
if align == NCALIGN_CENTER {
return ((availcols - cols) / 2) as NcOffset;
}
if align == NCALIGN_RIGHT {
return (availcols - cols) as NcOffset;
}
-NCRESULT_MAX // NCALIGN_UNALIGNED
}
///
/// If no event is ready, returns 0.
///
/// *Method: Nc.[getc_nblock()][Nc#method.getc_nblock].*
//
// TODO: use from_u32 & return Option.
#[inline]
pub fn notcurses_getc_nblock(nc: &mut Nc, input: &mut NcInput) -> char {
unsafe {
let ts = NcTime {
tv_sec: 0,
tv_nsec: 0,
};
core::char::from_u32_unchecked(crate::notcurses_get(nc, &ts, input))
}
}
/// Blocks until an event is processed or a signal is received.
///
/// Optionally writes the event details in `input`.
///
/// In case of an invalid read (including on EOF) *-1 as char* is returned.
///
/// *Method: Nc.[getc_blocking()][Nc#method.getc_blocking].*
#[inline]
pub fn notcurses_getc_blocking(nc: &mut Nc, input: Option<&mut NcInput>) -> char {
let input_ptr;
if let Some(i) = input {
input_ptr = i as *mut _;
} else {
input_ptr = null_mut();
}
unsafe { core::char::from_u32_unchecked(crate::notcurses_get(nc, null(), input_ptr)) }
}
/// [notcurses_stdplane()][crate::notcurses_stdplane], plus free bonus
/// dimensions written to non-NULL y/x!
///
/// *Method: Nc.[getc_stddim_yx()][Nc#method.stddim_yx].*
#[inline]
pub fn notcurses_stddim_yx<'a>(
nc: &'a mut Nc,
y: &mut NcDim,
x: &mut NcDim,
) -> NcResult<&'a mut NcPlane> {
unsafe {
let sp = crate::notcurses_stdplane(nc);
if !sp.is_null() {
crate::ncplane_dim_yx(sp, &mut (*y as i32), &mut (*x as i32));
return Ok(&mut *sp);
}
}
Err(NcError::new())
}
/// [notcurses_stdplane_const()][crate::notcurses_stdplane_const], plus free
/// bonus dimensions written to non-NULL y/x!
///
/// *Method: Nc.[getc_stddim_yx_const()][Nc#method.stddim_yx_const].*
#[inline]
pub fn notcurses_stddim_yx_const<'a>(
nc: &'a Nc,
y: &mut NcDim,
x: &mut NcDim,
) -> NcResult<&'a NcPlane> {
unsafe {
let sp = crate::notcurses_stdplane_const(nc);
if !sp.is_null() {
crate::ncplane_dim_yx(sp, &mut (*y as i32), &mut (*x as i32));
return Ok(&*sp);
}
}
Err(NcError::new())
}
/// Returns our current idea of the terminal dimensions in rows and cols.
///
/// *Method: Nc.[getc_term_yx()][Nc#method.term_yx].*
#[inline]
pub fn notcurses_term_dim_yx(nc: &Nc) -> (NcDim, NcDim) {
let (mut y, mut x) = (0, 0);
unsafe {
crate::ncplane_dim_yx(crate::notcurses_stdplane_const(nc), &mut y, &mut x);
}
(y as NcDim, x as NcDim)
}

@ -1,4 +0,0 @@
//! Test `Notcurses` methods and associated functions.
// use crate::Notcurses;
// use serial_test::serial;

@ -1,7 +0,0 @@
//! `Notcurses` tests.
#[cfg(test)]
mod methods;
#[cfg(test)]
mod reimplemented;

@ -1,191 +0,0 @@
//! Test `notcurses_*` reimplemented functions.
use serial_test::serial;
use std::io::Read;
use crate::{notcurses_init_test, notcurses_stop, NCRESULT_MAX};
use crate::NcFile;
#[test]
#[serial]
fn notcurses_align() {
unsafe {
let nc = notcurses_init_test();
assert_eq![0, crate::notcurses_align(30, crate::NCALIGN_LEFT, 20)];
assert_eq![5, crate::notcurses_align(30, crate::NCALIGN_CENTER, 20)];
assert_eq![10, crate::notcurses_align(30, crate::NCALIGN_RIGHT, 20)];
assert_eq![
-NCRESULT_MAX,
crate::notcurses_align(30, crate::NCALIGN_UNALIGNED, 20)
];
notcurses_stop(nc);
}
}
#[test]
#[serial]
fn notcurses_canchangecolor() {
unsafe {
let nc = notcurses_init_test();
let res = crate::notcurses_canchangecolor(nc);
notcurses_stop(nc);
print!("[{}] ", res);
}
}
#[test]
#[serial]
fn notcurses_canfade() {
unsafe {
let nc = notcurses_init_test();
let res = crate::notcurses_canfade(nc);
notcurses_stop(nc);
print!("[{}] ", res);
}
}
#[test]
#[serial]
fn notcurses_canopen_images() {
unsafe {
let nc = notcurses_init_test();
let res = crate::notcurses_canopen_images(nc);
notcurses_stop(nc);
print!("[{}] ", res);
}
}
#[test]
#[serial]
fn notcurses_canopen_videos() {
unsafe {
let nc = notcurses_init_test();
let res = crate::notcurses_canopen_videos(nc);
notcurses_stop(nc);
print!("[{}] ", res);
}
}
#[test]
#[serial]
fn notcurses_cansextant() {
unsafe {
let nc = notcurses_init_test();
let res = crate::notcurses_cansextant(nc);
notcurses_stop(nc);
print!("[{}] ", res);
}
}
#[test]
#[serial]
fn notcurses_cantruecolor() {
unsafe {
let nc = notcurses_init_test();
let res = crate::notcurses_cantruecolor(nc);
notcurses_stop(nc);
print!("[{}] ", res);
}
}
#[test]
#[serial]
fn notcurses_canutf8() {
unsafe {
let nc = notcurses_init_test();
let res = crate::notcurses_canutf8(nc);
notcurses_stop(nc);
print!("[{}] ", res);
}
}
#[test]
#[serial]
fn notcurses_drop_planes() {
unsafe {
let nc = notcurses_init_test();
let stdplane = crate::notcurses_stdplane(nc);
let plane1 = crate::ncplane_new_bound_test(&mut *stdplane, 0, 0, 10, 10);
let _plane2 = crate::ncplane_new_bound_test(plane1, 0, 0, 10, 10);
crate::notcurses_drop_planes(nc);
// TODO: CHECK that planes are really dropped.
notcurses_stop(nc);
}
}
#[test]
#[serial]
fn notcurses_initialization() {
unsafe {
let nc = notcurses_init_test();
assert![nc as *mut _ != core::ptr::null_mut()];
notcurses_stop(nc);
}
}
#[test]
#[serial]
#[ignore]
// FIXME: always return null
fn notcurses_at_yx() {
unsafe {
let nc = notcurses_init_test();
let mut sm = 0;
let mut ch = 0;
let res = crate::notcurses_at_yx(nc, 0, 0, &mut sm, &mut ch);
notcurses_stop(nc);
assert![!res.is_null()];
//print!("[{}] ", res);
}
}
#[test]
#[serial]
#[cfg_attr(target_os = "macos", ignore)] // FIXME
#[ignore] // FIXME https://github.com/dankamongmen/notcurses/issues/2111
fn notcurses_debug() {
unsafe {
let nc = notcurses_init_test();
#[cfg(any(
target_arch = "s390x",
target_arch = "powerpc64le",
target_arch = "armv7hl",
target_arch = "aarch64"
))]
let mut _p: *mut u8 = &mut 0;
#[cfg(not(any(
target_arch = "s390x",
target_arch = "powerpc64le",
target_arch = "armv7hl",
target_arch = "aarch64"
)))]
let mut _p: *mut i8 = &mut 0;
let mut _size: *mut usize = &mut 0;
let mut file = NcFile::from_libc(libc::open_memstream(&mut _p, _size));
crate::notcurses_debug(nc, file.as_nc_ptr());
notcurses_stop(nc);
let mut string1 = String::new();
let _result = file.read_to_string(&mut string1);
let string2 =
" -------------------------- notcurses debug state -----------------------------";
assert_eq![&string1[0..string2.len()], &string2[..]];
}
}
#[test]
#[serial]
// TODO test version_components
fn notcurses_version() {
let c_str = unsafe { crate::notcurses_version() };
assert!(!c_str.is_null());
print!("v{} ", crate::rstring![c_str]);
}

@ -1,54 +0,0 @@
//! `NcPalette` methods and associated functions.
use crate::{error, Nc, NcChannel, NcComponent, NcPalette, NcPaletteIndex, NcResult, NcRgb};
impl NcPalette {
/// New `NcPalette`.
///
/// *C style function: [ncpalette_new()][crate::ncpalette_new].*
pub fn new<'a>(nc: &mut Nc) -> &'a mut Self {
unsafe { &mut *crate::ncpalette_new(nc) }
}
/// Frees this `NcPalette`.
///
/// *C style function: [ncpalette_free()][crate::ncpalette_free].*
pub fn free(&mut self) {
unsafe {
crate::ncpalette_free(self);
}
}
/// Attempts to configure the terminal with this NcPalette.
///
/// *C style function: [ncpalette_use()][crate::ncpalette_use].*
pub fn r#use(&self, nc: &mut Nc) -> NcResult<()> {
error![unsafe { crate::ncpalette_use(nc, self) }]
}
/// Returns the [`NcComponent`]s from the [`NcChannel`] in this `NcPalette`.
///
/// *C style function: [ncpalette_get_rgb()][crate::ncpalette_get_rgb8].*
pub fn get_rgb8(&self, index: NcPaletteIndex) -> (NcComponent, NcComponent, NcComponent) {
let (mut r, mut g, mut b) = (0, 0, 0);
crate::ncchannel_rgb8(self.chans[index as usize], &mut r, &mut g, &mut b);
(r, g, b)
}
/// Extracts the [`NcComponent`]s from an [`NcChannel`] entry inside
/// this NcPalette, and returns the NcChannel.
///
/// *C style function: [ncpalette_get_rgb()][crate::ncpalette_get_rgb8].*
pub fn get_rgb(&self, index: NcPaletteIndex) -> NcChannel {
let (mut r, mut g, mut b) = (0, 0, 0);
crate::ncchannel_rgb8(self.chans[index as usize], &mut r, &mut g, &mut b)
}
/// Sets the [`NcRgb`] value of the [`NcChannel`][crate::NcChannel] entry
/// inside this NcPalette.
///
/// *C style function: [ncpalette_set()][crate::ncpalette_set].*
pub fn set(&mut self, index: NcPaletteIndex, rgb: NcRgb) {
crate::ncchannel_set(&mut self.chans[index as usize], rgb);
}
}

@ -1,49 +0,0 @@
//! `NcPalette*`
// -----------------------------------------------------------------------------
// Now none of these functions can't fail and therefore don't return errors.
// -----------------------------------------------------------------------------
//
// functions already exported by bindgen : 3
// -----------------------------------------
// (#) test: 0
// (W) wrap: 3 / 0
// -----------------------------------------
//W ncpalette_free
//W ncpalette_new
//W ncpalette_use
//
// functions manually reimplemented: 5
// -----------------------------------------
// (+) done: 3 / 0
// (#) test: 0
// (W) wrap: 3 / 0
// -----------------------------------------
//W+ ncpalette_get_rgb
// ncpalette_get_rgb8
//W+ ncpalette_set
//W+ ncpalette_set_rgb
// ncpalette_set_rgb8
mod methods;
mod reimplemented;
pub use methods::*;
pub use reimplemented::*;
/// NcPalette structure consisting of an array of 256
/// [`NcChannel`][crate::NcChannel]s.
///
/// See also [NcPaletteIndex].
///
/// Some terminals only support 256 colors, but allow the full
/// palette to be specified with arbitrary RGB colors. In all cases, it's more
/// performant to use indexed colors, since it's much less data to write to the
/// terminal. If you can limit yourself to 256 colors, that's probably best.
///
/// `type in C: ncncpalette (struct)`
///
pub type NcPalette = crate::bindings::ffi::ncpalette;
/// 8-bit value used for indexing into a [`NcPalette`]
///
pub type NcPaletteIndex = u8;

@ -1,42 +0,0 @@
//! `ncpalette_*` reimplemented functions.
use crate::{NcChannel, NcComponent, NcPalette, NcPaletteIndex, NcRgb};
/// Extracts the RGB [`NcComponent`]s from an [`NcChannel`] entry inside
/// an [`NcPalette`], and returns the `NcChannel`.
///
/// *Method: NcPalette.[get_rgb()][NcPalette#method.get_rgb].*
/// *Method: NcPalette.[get_rgb8()][NcPalette#method.get_rgb8].*
#[inline]
pub fn ncpalette_get_rgb8(
palette: &NcPalette,
index: NcPaletteIndex,
red: &mut NcComponent,
green: &mut NcComponent,
blue: &mut NcComponent,
) -> NcChannel {
crate::ncchannel_rgb8(palette.chans[index as usize], red, green, blue)
}
/// Sets the [`NcRgb`] value of the [`NcChannel`] entry inside an [`NcPalette`].
///
/// *Method: NcPalette.[set()][NcPalette#method.set].*
#[inline]
pub fn ncpalette_set(palette: &mut NcPalette, index: NcPaletteIndex, rgb: NcRgb) {
crate::ncchannel_set(&mut palette.chans[index as usize], rgb);
}
/// Sets the RGB [`NcComponent`]s of the [`NcChannel`] entry inside an
/// [`NcPalette`].
///
/// *Method: NcPalette.[set_rgb()][NcPalette#method.set_rgb].*
#[inline]
pub fn ncpalette_set_rgb8(
palette: &mut NcPalette,
index: NcPaletteIndex,
red: NcComponent,
green: NcComponent,
blue: NcComponent,
) {
crate::ncchannel_set_rgb8(&mut palette.chans[index as usize], red, green, blue)
}

@ -1,192 +0,0 @@
//! The ncpixel API facilitates direct management of the pixels within an
//! ncvisual (ncvisuals keep a backing store of 32-bit RGBA pixels, and render
//! them down to terminal graphics in ncvisual_render()).
//
// - NOTE: The pixel color & alpha [`NcComponent`]s are u8 instead of u32.
// Because of type enforcing, some runtime checks are now unnecessary.
//
// - NOTE: None of the functions can't fail anymore and don't have to return an error.
//
// functions manually reimplemented: 10
// ------------------------------------------
// (+) done: 10 / 0
// (#) test: 0
// (W) wrap: 10
// ------------------------------------------
//W+ ncpixel
//W+ ncpixel_a
//W+ ncpixel_b
//W+ ncpixel_g
//W+ ncpixel_r
//W+ ncpixel_set_a
//W+ ncpixel_set_b
//W+ ncpixel_set_g
//W+ ncpixel_set_r
//W+ ncpixel_set_rgb8
use crate::NcComponent;
// NcPixel (RGBA)
/// An ABGR pixel.
///
/// ## Diagram
///
/// ```txt
/// AAAAAAAA GGGGGGGG BBBBBBBB RRRRRRRR
/// ```
///
/// `type in C: ncpixel (uint32_t)`
///
/// NcPixel has 8 bits of alpha, more or less linear, contributing
/// directly to the usual alpha blending equation.
///
/// We map the 8 bits of alpha to 2 bits of alpha via a [level
/// function](https://nick-black.com/dankwiki/index.php?title=Notcurses#Transparency.2FContrasting)
///
/// The ncpixel API facilitates direct management of the pixels within an
/// ncvisual (ncvisuals keep a backing store of 32-bit RGBA pixels, and render
/// them down to terminal graphics in ncvisual_render()).
///
/// Per libav, we "store as BGRA on little-endian, and ARGB on big-endian".
/// This is an RGBA *byte-order* scheme. libav emits bytes, not words. Those
/// bytes are R-G-B-A. When read as words, on little endian this will be ABGR,
/// and on big-endian this will be RGBA. force everything to LE ABGR.
///
pub type NcPixel = u32;
/// Constructs a libav-compatible ABGR pixel from RGB [`NcComponent`]s.
#[inline]
#[allow(clippy::unnecessary_cast)]
pub const fn ncpixel(red: NcComponent, green: NcComponent, blue: NcComponent) -> NcPixel {
0xff000000 as NcPixel | red as NcPixel | (blue as NcPixel) << 8 | (green as NcPixel) << 16
}
/// Extracts the 8-bit alpha [`NcComponent`] from an ABGR pixel.
#[inline]
pub const fn ncpixel_a(pixel: NcPixel) -> NcComponent {
((pixel.to_le() & 0xff000000) >> 24) as NcComponent
}
/// Extracts the 8 bit blue [`NcComponent`] from an ABGR pixel.
#[inline]
pub const fn ncpixel_b(pixel: NcPixel) -> NcComponent {
((pixel.to_le() & 0x00ff0000) >> 16) as NcComponent
}
/// Extracts the 8 bit green [`NcComponent`] from an ABGR pixel.
#[inline]
pub const fn ncpixel_g(pixel: NcPixel) -> NcComponent {
((pixel.to_le() & 0x0000ff00) >> 8) as NcComponent
}
/// Extracts the 8 bit red [`NcComponent`] from an ABGR pixel.
#[inline]
pub const fn ncpixel_r(pixel: NcPixel) -> NcComponent {
(pixel.to_le() & 0x000000ff) as NcComponent
}
/// Sets the 8-bit alpha [`NcComponent`] of an ABGR pixel.
#[inline]
pub fn ncpixel_set_a(pixel: &mut NcPixel, alpha: NcComponent) {
*pixel = (((*pixel).to_le() & 0x00ffffff) | ((alpha as NcPixel) << 24)).to_le();
}
/// Sets the 8-bit blue [`NcComponent`] of an ABGR pixel.
#[inline]
pub fn ncpixel_set_b(pixel: &mut NcPixel, blue: NcComponent) {
*pixel = (((*pixel).to_le() & 0xffff00ff) | ((blue as NcPixel) << 8)).to_le();
}
/// Sets the 8-bit green [`NcComponent`] of an ABGR pixel.
#[inline]
pub fn ncpixel_set_g(pixel: &mut NcPixel, green: NcComponent) {
*pixel = (((*pixel).to_le() & 0xff00ffff) | ((green as NcPixel) << 16)).to_le();
}
/// Sets the 8-bit red [`NcComponent`] of an ABGR pixel.
#[inline]
pub fn ncpixel_set_r(pixel: &mut NcPixel, red: NcComponent) {
*pixel = (((*pixel).to_le() & 0xffffff00) | red as NcPixel).to_le();
}
/// Sets the RGB [`NcComponent`]s of an ABGR pixel.
#[inline]
pub fn ncpixel_set_rgb8(
pixel: &mut NcPixel,
red: NcComponent,
green: NcComponent,
blue: NcComponent,
) {
ncpixel_set_r(pixel, red);
ncpixel_set_g(pixel, green);
ncpixel_set_b(pixel, blue);
}
/// Enables the [NcPixel] methods.
//
// NOTE: waiting for: https://github.com/rust-lang/rust/issues/56546
// to move doc comments to the trait and appear unhidden at the implementation.
pub trait NcPixelMethods {
fn new(r: NcComponent, g: NcComponent, b: NcComponent) -> Self;
fn a(self) -> NcComponent;
fn b(self) -> NcComponent;
fn g(self) -> NcComponent;
fn r(self) -> NcComponent;
fn set_a(&mut self, green: NcComponent);
fn set_b(&mut self, blue: NcComponent);
fn set_g(&mut self, green: NcComponent);
fn set_r(&mut self, red: NcComponent);
fn set_rgb8(&mut self, red: NcComponent, green: NcComponent, blue: NcComponent);
}
impl NcPixelMethods for NcPixel {
/// Constructs a libav-compatible ABGR pixel from RGB [`NcComponent`]s.
fn new(red: NcComponent, green: NcComponent, blue: NcComponent) -> Self {
ncpixel(red, green, blue)
}
/// Extracts the 8-bit alpha [`NcComponent`] from an ABGR pixel.
fn a(self) -> NcComponent {
ncpixel_a(self)
}
/// Extracts the 8 bit blue [`NcComponent`] from an ABGR pixel.
fn b(self) -> NcComponent {
ncpixel_b(self)
}
/// Extracts the 8 bit green [`NcComponent`] from an ABGR pixel.
fn g(self) -> NcComponent {
ncpixel_g(self)
}
/// Extracts the 8 bit red [`NcComponent`] from an ABGR pixel.
fn r(self) -> NcComponent {
ncpixel_r(self)
}
/// Sets the 8-bit alpha [`NcComponent`] of an ABGR pixel.
fn set_a(&mut self, alpha: NcComponent) {
ncpixel_set_a(self, alpha)
}
/// Sets the 8-bit green [`NcComponent`] of an ABGR pixel.
fn set_g(&mut self, green: NcComponent) {
ncpixel_set_b(self, green)
}
/// Sets the 8-bit blue [`NcComponent`] of an ABGR pixel.
fn set_b(&mut self, blue: NcComponent) {
ncpixel_set_b(self, blue)
}
/// Sets the 8-bit red [`NcComponent`] of an ABGR pixel.
fn set_r(&mut self, red: NcComponent) {
ncpixel_set_r(self, red)
}
/// Sets the RGB [`NcComponent`]s of an ABGR pixel.
fn set_rgb8(&mut self, red: NcComponent, green: NcComponent, blue: NcComponent) {
ncpixel_set_rgb8(self, red, green, blue);
}
}

@ -1,25 +0,0 @@
use crate::{Nc, NcDim, NcOffset, NcPlane, NcPlaneOptions};
/// Helper function for a new NcPlane on C style tests.
#[allow(dead_code)]
pub(crate) unsafe fn ncplane_new_test<'a>(
nc: &mut Nc,
y: NcOffset,
x: NcOffset,
rows: NcDim,
cols: NcDim,
) -> &'a mut NcPlane {
&mut *crate::ncpile_create(nc, &NcPlaneOptions::new(y, x, rows, cols))
}
/// Helper function for a new bound NcPlane on C style tests.
#[allow(dead_code)]
pub(crate) unsafe fn ncplane_new_bound_test<'a>(
plane: &mut NcPlane,
y: NcOffset,
x: NcOffset,
rows: NcDim,
cols: NcDim,
) -> &'a mut NcPlane {
&mut *crate::ncplane_create(plane, &NcPlaneOptions::new(y, x, rows, cols))
}

File diff suppressed because it is too large Load Diff

@ -1,298 +0,0 @@
//! `NcPlane`
// functions already exported by bindgen : 117
// -------------------------------------------
// (X) wont: 10
// (D) depr: 4
// (#) test: 13
// (W) wrap: 83
// -------------------------------------------
//W ncpile_bottom
//W# ncpile_create
//W ncpile_rasterize
//W ncpile_render
//W ncpile_top
//W ncplane_above
//W ncplane_abs_x
//W ncplane_abs_y
//W ncplane_abs_yx
//W ncplane_at_cursor
//W ncplane_at_cursor_cell
//W ncplane_at_yx
//W ncplane_at_yx_cell
//W ncplane_base
//W ncplane_below
//W ncplane_box
//W ncplane_center_abs
//W# ncplane_channels
//W ncplane_contents
//W ncplane_create
//W# ncplane_cursor_move_yx
//W# ncplane_cursor_yx
//W ncplane_destroy
//W# ncplane_dim_yx
//W ncplane_dup
//W# ncplane_erase
// ncplane_erase_region
//W ncplane_fadein
//W ncplane_fadein_iteration
//W ncplane_fadeout
//W ncplane_fadeout_iteration
//W ncplane_format
//W ncplane_gradient
//W ncplane_greyscale
// ncplane_halign
//W ncplane_highgradient
//W ncplane_highgradient_sized
// ncplane_hline_interp
//W# ncplane_home
//W ncplane_mergedown
//W ncplane_mergedown_simple
//W ncplane_move_above
//W ncplane_move_below
//W ncplane_move_bottom
//W ncplane_move_top
//W ncplane_move_yx
//W# ncplane_notcurses
//W# ncplane_notcurses_const
//W ncplane_off_styles
//W ncplane_on_styles
//W ncplane_parent
//W ncplane_parent_const
//W ncplane_pixelgeom
// ncplane_polyfill_yx
//W ncplane_pulse
// ncplane_putchar_stained
// ncplane_putc_yx
// X ncplane_putegc_stained // unneeded
// X ncplane_putegc_yx // unneeded
// ncplane_putnstr_aligned
// ncplane_putnstr_yx
//W ncplane_putstr_aligned
//W ncplane_putstr_stained
//W ncplane_putstr_yx
// ncplane_puttext
// X ncplane_putwegc_stained // unneeded
// X ncplane_putwstr_stained // unneeded
// ncplane_qrcode
//W ncplane_reparent
//W ncplane_reparent_family
//W# ncplane_resize
//W ncplane_resizecb
//W ncplane_resize_marginalize
//W ncplane_resize_maximize
//W ncplane_resize_realign
//W ncplane_rgba
//W ncplane_rotate_ccw
//W ncplane_rotate_cw
//W ncplane_scrolling_p
//W ncplane_set_base
//W ncplane_set_base_cell
//W# ncplane_set_bchannel
//W ncplane_set_bg_alpha
//W ncplane_set_bg_default
//W ncplane_set_bg_palindex
//W ncplane_set_bg_rgb
//W ncplane_set_bg_rgb8
// X ncplane_set_bg_rgb8_clipped // unneeded
//W# ncplane_set_channels
//W# ncplane_set_fchannel
//W ncplane_set_fg_alpha
//W ncplane_set_fg_default
//W ncplane_set_fg_palindex
//W ncplane_set_fg_rgb
//W ncplane_set_fg_rgb8
// X ncplane_set_fg_rgb8_clipped // unneeded
//W ncplane_set_resizecb
//W ncplane_set_scrolling
//W ncplane_set_styles
// ncplane_set_userptr
//W ncplane_stain
//W ncplane_styles
//W ncplane_translate
//W ncplane_translate_abs
// ncplane_userptr
// ncplane_valign
// ncplane_vline_interp
// X ncplane_vprintf_aligned
// X ncplane_vprintf_stained
// X ncplane_vprintf_yx
//W ncplane_x
//W ncplane_y
//W ncplane_yx
//
// functions manually reimplemented: 40
// ------------------------------------------
// (X) wont: 9
// (+) done: 33 / 0
// (W) wrap: 25
// (#) test: 5
// ------------------------------------------
//W+ ncplane_bchannel
//W+ ncplane_bg_alpha
//W# ncplane_bg_default_p
//W+ ncplane_bg_rgb
//W+ ncplane_bg_rgb8
//W+ ncplane_box_sized
//W# ncplane_dim_x
//W# ncplane_dim_y
//W+ ncplane_double_box
//W+ ncplane_double_box_sized
//W+ ncplane_fchannel
//W+ ncplane_fg_alpha
//W# ncplane_fg_default_p
//W+ ncplane_fg_rgb
//W+ ncplane_fg_rgb8
//W+ ncplane_gradient_sized
//W+ ncplane_halign
// + ncplane_hline
//W ncplane_moverel
//W+ ncplane_perimeter
//W+ ncplane_perimeter_double
//W+ ncplane_perimeter_rounded
// + ncplane_putc
// + ncplane_putchar
// + ncplane_putchar_yx
// X ncplane_putegc // unneeded
// + ncplane_putnstr
//W+ ncplane_putstr
// X ncplane_putwc // unneeded
// X ncplane_putwc_stained // unneeded
// X ncplane_putwc_yx // unneeded
// X ncplane_putwegc // unneeded
// X ncplane_putwegc_yx // unneeded
// X ncplane_putwstr // unneeded
// X ncplane_putwstr_aligned // unneeded
// X ncplane_putwstr_yx // unneeded
//W# ncplane_resize_simple
// + ncplane_rounded_box
// + ncplane_rounded_box_sized
//W+ ncplane_halign
// + ncplane_vline
// X ncplane_vprintf
#[cfg(test)]
mod test;
mod helpers;
mod methods;
mod reimplemented;
#[allow(unused_imports)]
pub(crate) use helpers::*;
pub use reimplemented::*;
// NcPlane
/// Fundamental drawing surface.
///
/// Unites a:
/// - CellMatrix
/// - EgcPool
///
/// `type in C: ncplane (struct)`
///
///
/// # About planes and piles
///
/// A given notcurses context is made up of one or more piles.
///
/// A pile is made up of [`NcPlane`]s, totally ordered on a z-axis.
///
/// You can't manage the piles directly, but only the `NcPlanes`.
///
/// A pile is destroyed when all its planes are destroyed or moved to other
/// piles.
///
/// A pile has a top and bottom plane (this might be a single `NcPlane`),
/// and one or more root planes (`NcPlane`s which are bound to themselves).
///
/// Multiple threads can concurrently operate on distinct piles, rendering or
/// mutating it, while another thread concurrently renders or mutates another.
///
/// Each `NcPlane` is part of one and only one pile. By default, an `NcPlane` is
/// part of the same pile that contains the `NcPlane` to which it is bound.
///
/// When an `NcPlane` is created without being bound to another `NcPlane`, then
/// it becomes the root plane, top, and bottom of a new pile. As a root plane,
/// it is bound to itself.
///
/// A new pile can also be created by reparenting an `NcPlane` to itself,
/// though if the plane is already a root plane, this is a no-op.
///
/// When an `NcPlane` is moved to a different pile (whether new or preexisting),
/// any `NcPlane`s which were bound to it are rebound to its previous parent.
/// If the `NcPlane` was a root plane of some pile, any bound planes become root
/// planes. The new `NcPlane` is placed immediately atop its new parent on its
/// new pile's z-axis.
///
/// When [`NcPlane::reparent_family`][NcPlane#method.reparent_family] is used,
/// all `NcPlanes` bound to the reparented `NcPlane` are moved along with it.
/// Their relative z-order is maintained.
//
/// Rendering reduces a pile of `NcPlane`s to a single `NcPlane`, proceeding
/// from the top to the bottom along a pile's z-axis. The result is a matrix of
/// [`NcCell`][crate::NcCell]s. Rasterizing takes this matrix, together with the
/// current state of the visual area, and produces a stream of optimized control
/// sequences and `EGC`s for the terminal. By writing this stream to the
/// terminal, the physical display is synced to some pile's `NcPlane`s.
///
/// [`NcPlane.render`][crate::NcPlane#method.render] performs the first of these
/// tasks for the pile of which the plane is a part. The output is maintained
/// internally; calling `render` again on the same pile will replace this state
/// with a fresh render. Multiple piles can be concurrently rendered.
/// [`NcPlane.rasterize`][crate::NcPlane#method.rasterize] performs
/// rasterization, and writes the result to the terminal. It is a blocking call,
/// and only one rasterization operation may proceed at a time.
///
/// It is necessary to call `NcPlane.rasterize` to generate any visible output;
/// the various *output calls* only draw to the virtual `NcPlane`s. Most of the
/// notcurses `statistics` are updated as a result of a render, and screen
/// geometry is refreshed (similarly to
/// [`Notcurses.refresh`][crate::Notcurses#method.refresh]) following the render.
///
/// # Methods & Associated Functions
///
/// - [Constructors & Destructors](#ncplane-constructors--destructors)
///
/// Methods:
/// - [`NcAlphaBits`](#ncplane-methods-ncalphabits)
/// - [`NcChannel` & `NcChannels`](#ncplane-methods-ncchannel)
/// - [`NcComponent`, `NcRgb` & default color](#ncplane-methods-nccomponent-ncrgb--default-color)
/// - [`NcStyle` & `NcPaletteIndex`](#ncplane-methods-ncstylemask--paletteindex)
/// - [`NcCell` & strings](#ncplane-methods-nccell--strings)
/// - [cursor](#ncplane-methods-cursor)
/// - [`NcPlane` & `Notcurses`](#ncplane-methods-ncplane--notcurses)
/// - [boxes & perimeters](#ncplane-methods-boxes--perimeters)
/// - [Size, position & alignment](#ncplane-methods-size-position--alignment)
/// - [fading, gradients & greyscale](#ncplane-methods-fading-gradients--greyscale)
///
pub type NcPlane = crate::bindings::ffi::ncplane;
/// Options struct for [`NcPlane`]
pub type NcPlaneOptions = crate::bindings::ffi::ncplane_options;
/// Horizontal alignment relative to the parent plane. Use NcAlign for 'x'.
pub const NCPLANE_OPTION_HORALIGNED: u64 = crate::bindings::ffi::NCPLANE_OPTION_HORALIGNED as u64;
/// Vertical alignment relative to the parent plane. Use NcAlign for 'y'.
pub const NCPLANE_OPTION_VERALIGNED: u64 = crate::bindings::ffi::NCPLANE_OPTION_VERALIGNED as u64;
/// Maximize relative to the parent plane, modulo the provided margins.
///
/// The margins are best-effort; the plane will always be at least 1 column by
/// 1 row. If the margins can be effected, the plane will be sized to all
/// remaining space. 'y' and 'x' are overloaded as the top and left margins
/// when this flag is used. 'rows' and 'cols' must be 0 when this flag is
/// used. This flag is exclusive with both of the alignment flags.
pub const NCPLANE_OPTION_MARGINALIZED: u64 =
crate::bindings::ffi::NCPLANE_OPTION_MARGINALIZED as u64;
/// I/O wrapper to dump file descriptor to [`NcPlane`]
///
/// `type in C: ncfdplane (struct)`
pub type NcFdPlane = crate::bindings::ffi::ncfdplane;
/// Options struct for [`NcFdPlane`]
///
/// `type in C: ncplane_options (struct)`
pub type NcFdPlaneOptions = crate::bindings::ffi::ncfdplane_options;

@ -1,854 +0,0 @@
//! `ncplane_*` reimplemented functions.
use core::ptr::null_mut;
use crate::{
cstring, nccell_release, NcAlign, NcAlphaBits, NcBoxMask, NcCell, NcChannel, NcChannels,
NcComponent, NcDim, NcIntResult, NcOffset, NcPlane, NcRgb, NcStyle, NCRESULT_ERR, NCRESULT_OK,
};
// Alpha -----------------------------------------------------------------------
/// Gets the foreground [NcAlphaBits] from the [NcPlane], shifted to LSBs.
///
/// *Method: NcPlane.[fg_alpha()][NcPlane#method.fg_alpha].*
#[inline]
pub fn ncplane_fg_alpha(plane: &NcPlane) -> NcAlphaBits {
crate::ncchannels_fg_alpha(ncplane_channels(plane))
}
/// Gets the background [NcAlphaBits] from the [NcPlane], shifted to LSBs.
///
/// *Method: NcPlane.[bg_alpha()][NcPlane#method.bg_alpha].*
#[inline]
pub fn ncplane_bg_alpha(plane: &NcPlane) -> NcAlphaBits {
crate::ncchannels_bg_alpha(ncplane_channels(plane))
}
// NcChannel -------------------------------------------------------------------
/// Gets the foreground [NcChannel] from an [NcPlane].
///
/// *Method: NcPlane.[fchannel()][NcPlane#method.fchannel].*
#[inline]
pub fn ncplane_fchannel(plane: &NcPlane) -> NcChannel {
crate::ncchannels_fchannel(ncplane_channels(plane))
}
/// Gets the background [NcChannel] from an [NcPlane].
///
/// *Method: NcPlane.[bchannel()][NcPlane#method.bchannel].*
#[inline]
pub fn ncplane_bchannel(plane: &NcPlane) -> NcChannel {
crate::ncchannels_bchannel(ncplane_channels(plane))
}
/// Sets the foreground [NcChannel] on an [NcPlane],
/// and returns the new [NcChannels].
///
/// *Method: NcPlane.[set_fchannel()][NcPlane#method.set_fchannel].*
#[inline]
pub fn ncplane_set_fchannel(plane: &mut NcPlane, channel: NcChannel) -> NcChannels {
unsafe { crate::ffi::ncplane_set_fchannel(plane, channel) }
}
/// Sets the background [NcChannel] on an [NcPlane],
/// and returns the new [NcChannels].
///
/// *Method: NcPlane.[set_bchannel()][NcPlane#method.set_bchannel].*
#[inline]
pub fn ncplane_set_bchannel(plane: &mut NcPlane, channel: NcChannel) -> NcChannels {
unsafe { crate::ffi::ncplane_set_bchannel(plane, channel) }
}
/// Gets the [NcChannels] of an [NcPlane].
///
/// *Method: NcPlane.[channels()][NcPlane#method.channels].*
#[inline]
pub fn ncplane_channels(plane: &NcPlane) -> NcChannels {
unsafe { crate::ffi::ncplane_channels(plane) }
}
/// Sets the [NcChannels] of an [NcPlane].
///
/// *Method: NcPlane.[set_channels()][NcPlane#method.set_channels].*
#[inline]
pub fn ncplane_set_channels(plane: &mut NcPlane, channels: NcChannels) {
unsafe { crate::ffi::ncplane_set_channels(plane, channels) };
}
// NcComponent ---------------------------------------------------------------------
/// Gets the foreground RGB [NcComponent]s from an [NcPlane].
/// and returns the background [NcChannel].
///
/// *Method: NcPlane.[fg_rgb8()][NcPlane#method.fg_rgb8].*
#[inline]
pub fn ncplane_fg_rgb8(
plane: &NcPlane,
red: &mut NcComponent,
green: &mut NcComponent,
blue: &mut NcComponent,
) -> NcChannel {
crate::ncchannels_fg_rgb8(ncplane_channels(plane), red, green, blue)
}
/// Gets the background RGB [NcComponent]s from an [NcPlane],
/// and returns the background [NcChannel].
///
/// *Method: NcPlane.[bg_rgb8()][NcPlane#method.bg_rgb8].*
#[inline]
pub fn ncplane_bg_rgb8(
plane: &NcPlane,
red: &mut NcComponent,
green: &mut NcComponent,
blue: &mut NcComponent,
) -> NcChannel {
crate::ncchannels_bg_rgb8(ncplane_channels(plane), red, green, blue)
}
// NcRgb -----------------------------------------------------------------------
/// Gets the foreground [NcRgb] from an [NcPlane], shifted to LSBs.
///
/// *Method: NcPlane.[fg_rgb()][NcPlane#method.fg_rgb].*
#[inline]
pub fn ncplane_fg_rgb(plane: &NcPlane) -> NcRgb {
crate::ncchannels_fg_rgb(ncplane_channels(plane))
}
/// Gets the background [NcRgb] from an [NcPlane], shifted to LSBs.
///
/// *Method: NcPlane.[bg_rgb()][NcPlane#method.bg_rgb].*
#[inline]
pub fn ncplane_bg_rgb(plane: &NcPlane) -> NcRgb {
crate::ncchannels_bg_rgb(ncplane_channels(plane))
}
// Default ---------------------------------------------------------------------
/// Is the plane's foreground using the "default foreground color"?
///
/// *Method: NcPlane.[fg_default_p()][NcPlane#method.fg_default_p].*
#[inline]
pub fn ncplane_fg_default_p(plane: &NcPlane) -> bool {
crate::ncchannels_fg_default_p(ncplane_channels(plane))
}
/// Is the plane's background using the "default background color"?
///
/// *Method: NcPlane.[bg_default_p()][NcPlane#method.bg_default_p].*
#[inline]
pub fn ncplane_bg_default_p(plane: &NcPlane) -> bool {
crate::ncchannels_bg_default_p(ncplane_channels(plane))
}
/// Marks both the foreground and background as using the "default color",
/// and returns the new [NcChannels].
///
/// *Method: NcPlane.[set_default()][NcPlane#method.set_default].*
//
// Not in the C API.
#[inline]
pub fn ncplane_set_default(plane: &mut NcPlane) -> NcChannels {
let channels = crate::ncchannels_set_default(&mut ncplane_channels(plane));
ncplane_set_channels(plane, channels);
channels
}
/// Marks both the foreground and background as NOT using the "default color",
/// and returns the new [NcChannels].
///
/// *Method: NcPlane.[set_not_default()][NcPlane#method.set_not_default].*
//
// Not in the C API.
#[inline]
pub fn ncplane_set_not_default(plane: &mut NcPlane) -> NcChannels {
let channels = crate::ncchannels_set_not_default(&mut ncplane_channels(plane));
crate::ncplane_set_channels(plane, channels);
channels
}
/// Marks the foreground as NOT using the "default color",
/// and returns the new [NcChannels].
///
/// *Method: NcPlane.[set_fg_not_default()][NcPlane#method.set_fg_not_default].*
//
// Not in the C API.
#[inline]
pub fn ncplane_set_fg_not_default(plane: &NcPlane) -> NcChannels {
crate::ncchannels_set_fg_not_default(&mut ncplane_channels(plane))
}
/// Marks the background as NOT using the "default color",
/// and returns the new [NcChannels].
///
/// *Method: NcPlane.[set_bg_not_default()][NcPlane#method.set_bg_not_default].*
//
// Not in the C API.
#[inline]
pub fn ncplane_set_bg_not_default(plane: &NcPlane) -> NcChannels {
crate::ncchannels_set_bg_not_default(&mut ncplane_channels(plane))
}
// put & print -----------------------------------------------------------------
/// Calls [ncplane_putc_yx()][crate::ncplane_putc_yx] for the current cursor location.
///
/// *Method: NcPlane.[putc()][NcPlane#method.putc].*
#[inline]
pub fn ncplane_putc(plane: &mut NcPlane, cell: &NcCell) -> NcIntResult {
unsafe { crate::ncplane_putc_yx(plane, -1, -1, cell) }
}
/// Calls ncplane_putchar_yx() at the current cursor location.
///
/// *Method: NcPlane.[putchar()][NcPlane#method.putchar].*
#[inline]
pub fn ncplane_putchar(plane: &mut NcPlane, ch: char) -> NcIntResult {
unsafe {
let cell = NcCell::from_char(ch, plane);
crate::ncplane_putc_yx(plane, -1, -1, &cell)
}
}
/// Replaces the [NcCell] at the specified coordinates with the provided char.
/// Advances the cursor by 1.
///
/// *Method: NcPlane.[putchar_yx()][NcPlane#method.putchar_yx].*
#[inline]
pub fn ncplane_putchar_yx(plane: &mut NcPlane, y: NcDim, x: NcDim, ch: char) -> NcIntResult {
unsafe {
let cell = NcCell::from_char(ch, plane);
crate::ncplane_putc_yx(plane, y as i32, x as i32, &cell)
}
}
/// Writes a series of `EGC`s to the current location, using the current style.
///
/// Advances the cursor by some positive number of columns
/// (though not beyond the end of the plane),
/// and this number is returned on success.
///
/// On error, a non-positive number is returned, indicating
/// the number of columns which were written before the error.
///
/// *Method: NcPlane.[putstr()][NcPlane#method.putstr].*
#[inline]
pub fn ncplane_putstr(plane: &mut NcPlane, string: &str) -> NcIntResult {
unsafe { crate::ncplane_putstr_yx(plane, -1, -1, cstring![string]) }
}
///
///
/// *Method: NcPlane.[putnstr()][NcPlane#method.putnstr].*
#[inline]
pub fn ncplane_putnstr(plane: &mut NcPlane, size: u32, gclustarr: &[u8]) -> NcIntResult {
unsafe { crate::ncplane_putnstr_yx(plane, -1, -1, size.into(), cstring![gclustarr]) }
}
// movement, size & alignment --------------------------------------------------
/// Moves this `NcPlane` relative to its current location.
///
/// Negative values move up and left, respectively.
/// Pass 0 to hold an axis constant.
///
/// It is an error to attempt to move the standard plane.
///
/// *C style function: [ncplane_moverel()][crate::ncplane_moverel].*
pub fn ncplane_moverel(plane: &mut NcPlane, rows: NcOffset, cols: NcOffset) -> NcIntResult {
let (mut orig_y, mut orig_x) = (0, 0);
unsafe {
crate::ncplane_dim_yx(plane, &mut orig_y, &mut orig_x);
crate::ncplane_move_yx(plane, orig_y + rows, orig_x + cols)
}
}
/// Gets the columns of the [NcPlane].
///
/// *Method: NcPlane.[dim_x()][NcPlane#method.dim_x].*
#[inline]
pub fn ncplane_dim_x(plane: &NcPlane) -> NcDim {
unsafe {
let mut x = 0;
crate::ncplane_dim_yx(plane, null_mut(), &mut x);
x as NcDim
}
}
/// Gets the rows of the [NcPlane].
///
/// *Method: NcPlane.[dim_y()][NcPlane#method.dim_y].*
#[inline]
#[inline]
pub fn ncplane_dim_y(plane: &NcPlane) -> NcDim {
unsafe {
let mut y = 0;
crate::ncplane_dim_yx(plane, &mut y, null_mut());
y as NcDim
}
}
/// Resizes the plane, retaining what data we can (everything, unless we're
/// shrinking in some dimension). Keep the origin where it is.
///
/// *Method: NcPlane.[resize_simple()][NcPlane#method.resize_simple].*
#[inline]
pub fn ncplane_resize_simple(plane: &mut NcPlane, y_len: NcDim, x_len: NcDim) -> NcIntResult {
let (mut old_y, mut old_x) = (0, 0);
unsafe {
crate::ncplane_dim_yx(plane, &mut old_y, &mut old_x);
}
let keep_len_y = {
if old_y > y_len as i32 {
y_len as i32
} else {
old_y
}
};
let keep_len_x = {
if old_x > x_len as i32 {
x_len as i32
} else {
old_x
}
};
unsafe {
crate::ncplane_resize(
plane,
0,
0,
keep_len_y,
keep_len_x,
0,
0,
y_len as i32,
x_len as i32,
)
}
}
/// Returns the column at which `cols` columns ought start in order to be aligned
/// according to `align` within this NcPlane.
///
/// Returns `-`[`NCRESULT_MAX`][crate::NCRESULT_MAX] if
/// [NCALIGN_UNALIGNED][crate::NCALIGN_UNALIGNED] or invalid [NcAlign].
///
/// *Method: NcPlane.[halign()][NcPlane#method.halign].*
#[inline]
pub fn ncplane_halign(plane: &NcPlane, align: NcAlign, cols: NcDim) -> NcIntResult {
crate::notcurses_align(ncplane_dim_x(plane), align, cols)
}
/// Returns the row at which `rows` rows ought start in order to be aligned
/// according to `align` within this NcPlane.
///
/// Returns `-`[`NCRESULT_MAX`][crate::NCRESULT_MAX] if
/// [NCALIGN_UNALIGNED][crate::NCALIGN_UNALIGNED] or invalid [NcAlign].
///
/// *Method: NcPlane.[valign()][NcPlane#method.valign].*
#[inline]
pub fn ncplane_valign(plane: &NcPlane, align: NcAlign, rows: NcDim) -> NcIntResult {
crate::notcurses_align(ncplane_dim_y(plane), align, rows)
}
// line ------------------------------------------------------------------------
/// Draws horizontal lines using the specified NcCell, starting at the current
/// cursor position.
///
/// The cursor will end at the cell following the last cell output,
/// just as if ncplane_putc() was called at that spot.
///
/// Returns the number of cells drawn on success. On error, returns the negative
/// number of cells drawn.
///
/// *Method: NcPlane.[hline()][NcPlane#method.hline].*
#[inline]
pub fn ncplane_hline(plane: &mut NcPlane, cell: &NcCell, len: NcDim) -> NcIntResult {
unsafe { crate::ncplane_hline_interp(plane, cell, len as i32, cell.channels, cell.channels) }
}
/// Draws vertical lines using the specified NcCell, starting at the current
/// cursor position.
///
/// The cursor will end at the cell following the last cell output,
/// just as if ncplane_putc() was called at that spot.
///
/// Returns the number of cells drawn on success. On error, returns the negative
/// number of cells drawn.
///
/// *Method: NcPlane.[vline()][NcPlane#method.vline].*
#[inline]
pub fn ncplane_vline(plane: &mut NcPlane, cell: &NcCell, len: NcDim) -> NcIntResult {
unsafe { crate::ncplane_vline_interp(plane, cell, len as i32, cell.channels, cell.channels) }
}
// perimeter -------------------------------------------------------------------
///
///
/// *Method: NcPlane.[perimeter()][NcPlane#method.perimeter].*
#[inline]
pub fn ncplane_perimeter(
plane: &mut NcPlane,
ul: &NcCell,
ur: &NcCell,
ll: &NcCell,
lr: &NcCell,
hline: &NcCell,
vline: &NcCell,
boxmask: NcBoxMask,
) -> NcIntResult {
unsafe {
crate::ncplane_cursor_move_yx(plane, 0, 0);
let (mut dimy, mut dimx) = (0, 0);
crate::ncplane_dim_yx(plane, &mut dimy, &mut dimx);
ncplane_box_sized(
plane,
ul,
ur,
ll,
lr,
hline,
vline,
dimy as NcDim,
dimx as NcDim,
boxmask,
)
}
}
///
///
/// *Method: NcPlane.[perimeter_double()][NcPlane#method.perimeter_double].*
#[inline]
pub fn ncplane_perimeter_double(
plane: &mut NcPlane,
stylemask: NcStyle,
channels: NcChannels,
boxmask: NcBoxMask,
) -> NcIntResult {
if unsafe { crate::ncplane_cursor_move_yx(plane, 0, 0) } != NCRESULT_OK {
return NCRESULT_ERR;
}
let (mut dimy, mut dimx) = (0, 0);
unsafe {
crate::ncplane_dim_yx(plane, &mut dimy, &mut dimx);
}
let mut ul = NcCell::new();
let mut ur = NcCell::new();
let mut ll = NcCell::new();
let mut lr = NcCell::new();
let mut hl = NcCell::new();
let mut vl = NcCell::new();
if unsafe {
crate::nccells_double_box(
plane,
stylemask as u32,
channels,
&mut ul,
&mut ur,
&mut ll,
&mut lr,
&mut hl,
&mut vl,
)
} != NCRESULT_OK
{
return NCRESULT_ERR;
}
let ret = ncplane_box_sized(
plane,
&ul,
&ur,
&ll,
&lr,
&hl,
&vl,
dimy as NcDim,
dimx as NcDim,
boxmask,
);
unsafe {
nccell_release(plane, &mut ul);
nccell_release(plane, &mut ur);
nccell_release(plane, &mut ll);
nccell_release(plane, &mut lr);
nccell_release(plane, &mut hl);
nccell_release(plane, &mut vl);
}
ret
}
///
///
/// *Method: NcPlane.[perimeter_rounded()][NcPlane#method.perimeter_rounded].*
#[inline]
pub fn ncplane_perimeter_rounded(
plane: &mut NcPlane,
stylemask: NcStyle,
channels: NcChannels,
boxmask: NcBoxMask,
) -> NcIntResult {
if unsafe { crate::ncplane_cursor_move_yx(plane, 0, 0) } != NCRESULT_OK {
return NCRESULT_ERR;
}
let (mut dimy, mut dimx) = (0, 0);
unsafe {
crate::ncplane_dim_yx(plane, &mut dimy, &mut dimx);
}
let mut ul = NcCell::new();
let mut ur = NcCell::new();
let mut ll = NcCell::new();
let mut lr = NcCell::new();
let mut hl = NcCell::new();
let mut vl = NcCell::new();
if unsafe {
crate::nccells_rounded_box(
plane,
stylemask as u32,
channels,
&mut ul,
&mut ur,
&mut ll,
&mut lr,
&mut hl,
&mut vl,
)
} != NCRESULT_OK
{
return NCRESULT_ERR;
}
let ret = ncplane_box_sized(
plane,
&ul,
&ur,
&ll,
&lr,
&hl,
&vl,
dimy as NcDim,
dimx as NcDim,
boxmask,
);
unsafe {
nccell_release(plane, &mut ul);
nccell_release(plane, &mut ur);
nccell_release(plane, &mut ll);
nccell_release(plane, &mut lr);
nccell_release(plane, &mut hl);
nccell_release(plane, &mut vl);
}
ret
}
// box -------------------------------------------------------------------------
/// Draws a box with its upper-left corner at the current cursor position,
/// having dimensions `y_len` * `x_len`.
///
/// The minimum box size is 2x2, and it cannot be drawn off-screen.
///
/// See [ncplane_box()](crate::ncplane_box) for more information.
///
/// *Method: NcPlane.[box_sized()][NcPlane#method.box_sized].*
#[inline]
pub fn ncplane_box_sized(
plane: &mut NcPlane,
ul: &NcCell,
ur: &NcCell,
ll: &NcCell,
lr: &NcCell,
hline: &NcCell,
vline: &NcCell,
y_len: NcDim,
x_len: NcDim,
boxmask: NcBoxMask,
) -> NcIntResult {
let (mut y, mut x) = (0, 0);
unsafe {
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
crate::ncplane_box(
plane,
ul,
ur,
ll,
lr,
hline,
vline,
y + y_len as i32 - 1,
x + x_len as i32 - 1,
boxmask,
)
}
}
///
///
/// *Method: NcPlane.[double_box()][NcPlane#method.double_box].*
#[inline]
pub fn ncplane_double_box(
plane: &mut NcPlane,
stylemask: NcStyle,
channels: NcChannels,
y_stop: NcDim,
x_stop: NcDim,
boxmask: NcBoxMask,
) -> NcIntResult {
#[allow(unused_assignments)]
let mut ret = NCRESULT_OK;
let mut ul = NcCell::new();
let mut ur = NcCell::new();
let mut ll = NcCell::new();
let mut lr = NcCell::new();
let mut hl = NcCell::new();
let mut vl = NcCell::new();
unsafe {
ret = crate::nccells_double_box(
plane,
stylemask as u32,
channels,
&mut ul,
&mut ur,
&mut ll,
&mut lr,
&mut hl,
&mut vl,
);
if ret == NCRESULT_OK {
ret = crate::ncplane_box(
plane,
&ul,
&ur,
&ll,
&lr,
&hl,
&vl,
y_stop as i32,
x_stop as i32,
boxmask,
);
}
nccell_release(plane, &mut ul);
nccell_release(plane, &mut ur);
nccell_release(plane, &mut ll);
nccell_release(plane, &mut lr);
nccell_release(plane, &mut hl);
nccell_release(plane, &mut vl);
}
ret
}
///
///
/// *Method: NcPlane.[double_box_sized()][NcPlane#method.double_box_sized].*
#[inline]
pub fn ncplane_double_box_sized(
plane: &mut NcPlane,
stylemask: NcStyle,
channels: NcChannels,
y_len: NcDim,
x_len: NcDim,
boxmask: NcBoxMask,
) -> NcIntResult {
let (mut y, mut x) = (0, 0);
unsafe {
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
}
crate::ncplane_double_box(
plane,
stylemask,
channels,
y as NcDim + y_len - 1,
x as NcDim + x_len - 1,
boxmask,
)
}
///
///
/// *Method: NcPlane.[rounded_box()][NcPlane#method.rounded_box].*
#[inline]
pub fn ncplane_rounded_box(
plane: &mut NcPlane,
stylemask: NcStyle,
channels: NcChannels,
y_stop: NcDim,
x_stop: NcDim,
boxmask: NcBoxMask,
) -> NcIntResult {
#[allow(unused_assignments)]
let mut ret = NCRESULT_OK;
let mut ul = NcCell::new();
let mut ur = NcCell::new();
let mut ll = NcCell::new();
let mut lr = NcCell::new();
let mut hl = NcCell::new();
let mut vl = NcCell::new();
unsafe {
ret = crate::nccells_rounded_box(
plane,
stylemask as u32,
channels,
&mut ul,
&mut ur,
&mut ll,
&mut lr,
&mut hl,
&mut vl,
);
if ret == NCRESULT_OK {
ret = crate::ncplane_box(
plane,
&ul,
&ur,
&ll,
&lr,
&hl,
&vl,
y_stop as i32,
x_stop as i32,
boxmask,
);
}
nccell_release(plane, &mut ul);
nccell_release(plane, &mut ur);
nccell_release(plane, &mut ll);
nccell_release(plane, &mut lr);
nccell_release(plane, &mut hl);
nccell_release(plane, &mut vl);
}
ret
}
///
///
/// *Method: NcPlane.[rounded_box_sized()][NcPlane#method.rounded_box_sized].*
#[inline]
pub fn ncplane_rounded_box_sized(
plane: &mut NcPlane,
stylemask: NcStyle,
channels: NcChannels,
y_len: NcDim,
x_len: NcDim,
boxmask: NcBoxMask,
) -> NcIntResult {
let (mut y, mut x) = (0, 0);
unsafe {
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
}
ncplane_rounded_box(
plane,
stylemask,
channels,
y as NcDim + y_len - 1,
x as NcDim + x_len - 1,
boxmask,
)
}
// gradient --------------------------------------------------------------------
/// Draws a gradient with its upper-left corner at the current cursor position,
/// stopping at `ystop`×`xstop`.
///
/// The glyph composed of `egc` and `stylemask` is used for all cells. The
/// `NcChannels` specified by `ul`, `ur`, `ll`, and `lr` are composed into
/// foreground and background gradients.
///
/// - To do a vertical gradient, `ul` ought equal `ur` and `ll` ought equal `lr`.
/// - To do a horizontal gradient, `ul` ought equal `ll` and `ur` ought equal `ul`.
/// - To color everything the same, all four channels should be equivalent. The
/// resulting alpha values are equal to incoming alpha values. Returns the number
/// of cells filled on success, or -1 on failure.
///
/// Palette-indexed color is not supported.
///
/// Preconditions for gradient operations (error otherwise):
/// - all: only RGB colors, unless all four channels match as default
/// - all: all alpha values must be the same
/// - 1x1: all four colors must be the same
/// - 1xN: both top and both bottom colors must be the same (vertical gradient)
/// - Nx1: both left and both right colors must be the same (horizontal gradient)
///
/// *Method: NcPlane.[gradient()][NcPlane#method.gradient].*
#[inline]
pub fn ncplane_gradient(
plane: &mut NcPlane,
egc: &str,
stylemask: NcStyle,
ul: NcChannels,
ur: NcChannels,
ll: NcChannels,
lr: NcChannels,
y_len: NcDim,
x_len: NcDim,
) -> NcIntResult {
if y_len < 1 || x_len < 1 {
return NCRESULT_ERR;
}
#[cfg(any(target_arch = "armv7l", target_arch = "i686"))]
let egc_ptr = cstring![egc] as *const i8;
#[cfg(not(any(target_arch = "armv7l", target_arch = "i686")))]
let egc_ptr = cstring![egc];
unsafe {
crate::bindings::ffi::ncplane_gradient(
plane,
egc_ptr,
stylemask as u32,
ul,
ur,
ll,
lr,
y_len as i32,
x_len as i32,
)
}
}
/// Draw a gradient with its upper-left corner at the current cursor position,
/// having dimensions `y_len` * `x_len`.
///
/// See [ncplane_gradient][crate::ncplane_gradient] for more information.
///
/// *Method: NcPlane.[gradient_sized()][NcPlane#method.gradient_sized].*
#[inline]
pub fn ncplane_gradient_sized(
plane: &mut NcPlane,
egc: &str,
stylemask: NcStyle,
ul: NcChannels,
ur: NcChannels,
ll: NcChannels,
lr: NcChannels,
y_len: NcDim,
x_len: NcDim,
) -> NcIntResult {
if y_len < 1 || x_len < 1 {
return NCRESULT_ERR;
}
let (mut y, mut x) = (0, 0);
unsafe {
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
ncplane_gradient(
plane,
egc,
stylemask,
ul,
ur,
ll,
lr,
y as u32 + y_len - 1,
x as u32 + x_len - 1,
)
}
}

@ -1,4 +0,0 @@
//! Test `NcPlane` methods and associated functions.
// use crate::NcPlane;
// use serial_test::serial;

@ -1,7 +0,0 @@
//! `NcPlane` tests.
#[cfg(test)]
mod methods;
#[cfg(test)]
mod reimplemented;

@ -1,240 +0,0 @@
//! Test `ncplane_*` reimplemented functions.
use crate::{ncplane_new_test, notcurses_init_test, notcurses_stop, NCRESULT_OK};
use serial_test::serial;
#[test]
#[serial]
fn ncplane_notcurses() {
unsafe {
let nc = notcurses_init_test();
let plane = ncplane_new_test(nc, 0, 0, 20, 20);
let nc2 = crate::ncplane_notcurses(plane);
assert_eq![nc as *mut _, nc2];
let nc3 = crate::ncplane_notcurses_const(plane);
assert_eq![nc as *const _, nc3];
notcurses_stop(nc);
}
}
#[test]
#[serial]
fn ncplane_cursor() {
unsafe {
let nc = notcurses_init_test();
let plane = ncplane_new_test(nc, 0, 0, 20, 20);
let (mut y, mut x) = (0, 0);
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
assert_eq![x, 0];
assert_eq![y, 0];
let res = crate::ncplane_cursor_move_yx(plane, 10, 15);
assert_eq![res, 0];
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
assert_eq![x, 15];
assert_eq![y, 10];
crate::ncplane_home(plane);
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
assert_eq![x, 0];
assert_eq![y, 0];
let _res = crate::ncplane_cursor_move_yx(plane, 10, 15);
crate::ncplane_erase(plane); // has to move the cursor to 0,0
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
assert_eq![x, 0];
assert_eq![y, 0];
notcurses_stop(nc);
}
}
#[test]
#[serial]
fn ncplane_channels() {
unsafe {
let nc = notcurses_init_test();
let plane = ncplane_new_test(nc, 0, 0, 20, 20);
let channels = crate::ncplane_channels(plane);
assert_eq![channels, 0];
crate::ncplane_set_channels(plane, 0x1122334455667788);
assert_eq![0x1122334455667788, crate::ncplane_channels(plane)];
notcurses_stop(nc);
}
}
#[test]
#[serial]
fn ncplane_fchannel() {
unsafe {
let nc = notcurses_init_test();
let plane = ncplane_new_test(nc, 0, 0, 20, 20);
crate::ncplane_set_channels(plane, 0x1122334455667788);
let channels = crate::ncplane_channels(plane);
assert_eq![0x11223344, crate::ncchannels_fchannel(channels)];
let channels = crate::ncplane_set_fchannel(plane, 0x10203040);
assert_eq![0x10203040, crate::ncchannels_fchannel(channels)];
assert_eq![0x1020304055667788, channels];
notcurses_stop(nc);
}
}
#[test]
#[serial]
fn ncplane_bchannel() {
unsafe {
let nc = notcurses_init_test();
let plane = ncplane_new_test(nc, 0, 0, 20, 20);
crate::ncplane_set_channels(plane, 0x1122334455667788);
let channels = crate::ncplane_channels(plane);
assert_eq![0x55667788, crate::ncchannels_bchannel(channels)];
// BUG? ncplane_set_bchannel and ncplane_set_fchannel don't get
// applied unless they are assigned to a variable. Weird.
let channels = crate::ncplane_set_bchannel(plane, 0x50607080);
assert_eq![0x50607080, crate::ncchannels_bchannel(channels)];
assert_eq![0x1122334450607080, channels];
notcurses_stop(nc);
}
}
#[test]
#[serial]
fn ncplane_rgb() {
unsafe {
let nc = notcurses_init_test();
let plane = ncplane_new_test(nc, 0, 0, 20, 20);
crate::ncplane_set_fg_rgb(plane, 0x112233);
assert_eq![0x112233, crate::ncplane_fg_rgb(plane)];
notcurses_stop(nc);
}
}
#[test]
#[serial]
fn ncplane_default() {
unsafe {
let nc = notcurses_init_test();
let plane = ncplane_new_test(nc, 0, 0, 20, 20);
assert_eq![true, crate::ncplane_bg_default_p(plane)];
assert_eq![true, crate::ncplane_fg_default_p(plane)];
crate::ncplane_set_bg_rgb8(plane, 11, 22, 33);
crate::ncplane_set_fg_rgb8(plane, 44, 55, 66);
assert_eq![false, crate::ncplane_bg_default_p(plane)];
assert_eq![false, crate::ncplane_fg_default_p(plane)];
crate::ncplane_set_bg_default(plane);
crate::ncplane_set_fg_default(plane);
assert_eq![true, crate::ncplane_bg_default_p(plane)];
assert_eq![true, crate::ncplane_fg_default_p(plane)];
notcurses_stop(nc);
}
}
#[test]
#[serial]
fn ncplane_dimensions() {
unsafe {
let nc = notcurses_init_test();
let plane = ncplane_new_test(nc, 0, 0, 10, 20);
let (mut y, mut x) = (0, 0);
crate::ncplane_dim_yx(plane, &mut y, &mut x);
assert_eq!((10, 20), (y, x));
assert_eq!(10, crate::ncplane_dim_y(plane));
assert_eq!(20, crate::ncplane_dim_x(plane));
notcurses_stop(nc);
}
}
#[test]
#[serial]
fn ncplane_resize() {
unsafe {
let nc = notcurses_init_test();
let plane = ncplane_new_test(nc, 0, 0, 20, 20);
let res = crate::ncplane_resize_simple(plane, 40, 40);
assert_eq![NCRESULT_OK, res];
let (mut y, mut x) = (0, 0);
crate::ncplane_dim_yx(plane, &mut y, &mut x);
assert_eq!((40, 40), (y, x));
// TODO: test further plane subset keeping unchanged features
let res = crate::ncplane_resize(plane, 0, 0, 0, 0, 0, 0, 60, 70);
assert_eq![NCRESULT_OK, res];
assert_eq!(60, crate::ncplane_dim_y(plane));
assert_eq!(70, crate::ncplane_dim_x(plane));
notcurses_stop(nc);
}
}
// TODO: resizecb
#[test]
#[serial]
// TODO: CHECK: zeroes out every cell of the plane, dumps the egcpool,
// The base cell is preserved.
fn ncplane_erase() {
unsafe {
let nc = notcurses_init_test();
let plane = ncplane_new_test(nc, 0, 0, 20, 20);
crate::ncplane_set_bg_rgb(plane, 0x112233);
crate::ncplane_set_fg_rgb(plane, 0x445566);
assert_eq![false, crate::ncplane_bg_default_p(plane)];
assert_eq![false, crate::ncplane_fg_default_p(plane)];
// FIXME? DEBUG
crate::ncplane_erase(plane);
// assert_eq![true, crate::ncplane_bg_default_p(plane)];
// assert_eq![true, crate::ncplane_fg_default_p(plane)];
//print!(" C: {:#0x} ", crate::ncplane_channels(plane));
notcurses_stop(nc);
}
}
// #[test]
// #[serial]
// fn ncplane_at_cursor() {
// unsafe {
// let nc = notcurses_init_test();
// let plane = ncplane_new_test(nc, 0, 0, 20, 20);
//
// notcurses_stop(nc);
// }
// }
//
// #[test]
// #[serial]
// fn ncplane_at_cursor_cell() {
// unsafe {
// let nc = notcurses_init_test();
// let plane = ncplane_new_test(nc, 0, 0, 20, 20);
//
// notcurses_stop(nc);
// }
// }

@ -1,58 +0,0 @@
//! `NcResizeCb`
use crate::{NcIntResult, NcPlane};
/// A callback function called when an [NcPlane] is resized.
///
/// See also [ncresizecb_to_rust] & [ncresizecb_to_c].
///
pub type NcResizeCb = fn(&mut NcPlane) -> NcIntResult;
/// The unsafe version of [NcResizeCb] expected by the notcurses C API.
pub type NcResizeCbUnsafe = unsafe extern "C" fn(*mut NcPlane) -> NcIntResult;
/// Converts [NcResizeCbUnsafe] to [NcResizeCb].
pub fn ncresizecb_to_rust(resizecb: Option<NcResizeCbUnsafe>) -> Option<NcResizeCb> {
resizecb.map(|cb| unsafe { core::mem::transmute(cb) })
}
/// Converts [NcResizeCb] to [NcResizeCbUnsafe].
///
// waiting for https://github.com/rust-lang/rust/issues/53605
// to make this function const, and then NcPlaneOptions constructors.
pub fn ncresizecb_to_c(resizecb: Option<NcResizeCb>) -> Option<NcResizeCbUnsafe> {
resizecb.map(|cb| unsafe { core::mem::transmute(cb) })
}
/// Enables the [NcResizeCb] methods.
pub trait NcResizeCbMethods {
fn to_rust(&self) -> Option<NcResizeCb>;
fn to_c(&self) -> Option<NcResizeCbUnsafe>;
}
impl NcResizeCbMethods for NcResizeCb {
/// Returns [NcResizeCbUnsafe].
///
/// *C style function: [ncresizecb_to_c()][ncresizecb_to_c].*
fn to_c(&self) -> Option<NcResizeCbUnsafe> {
ncresizecb_to_c(Some(*self))
}
/// no-op.
fn to_rust(&self) -> Option<NcResizeCb> {
Some(*self)
}
}
impl NcResizeCbMethods for NcResizeCbUnsafe {
/// no-op.
fn to_c(&self) -> Option<NcResizeCbUnsafe> {
Some(*self)
}
/// Returns [NcResizeCb].
///
/// *C style function: [ncresizecb_to_rust()][ncresizecb_to_rust].*
fn to_rust(&self) -> Option<NcResizeCb> {
ncresizecb_to_rust(Some(*self))
}
}

@ -1,24 +0,0 @@
//! `NcStats`
use crate::Nc;
/// notcurses runtime statistics
pub type NcStats = crate::bindings::ffi::ncstats;
/// # `NcStats` Methods.
impl NcStats {
/// Allocates an NcStats object.
pub fn new(nc: &mut Nc) -> &mut Self {
unsafe { &mut *crate::notcurses_stats_alloc(nc) }
}
/// Acquires an atomic snapshot of the notcurses object's stats.
pub fn stats(&mut self, nc: &mut Nc) {
unsafe { crate::notcurses_stats(nc, self) }
}
/// Resets all cumulative stats (immediate ones are not reset).
pub fn reset(&mut self, nc: &mut Nc) {
unsafe { crate::notcurses_stats_reset(nc, self) }
}
}

@ -1,15 +0,0 @@
//! `NcTime`
///
// Expected by [`notcurses_getc`] & [`notcurses_getc_nblock`], that can't use
// libc::timespec
pub type NcTime = crate::bindings::ffi::timespec;
impl NcTime {
pub fn new() -> Self {
Self {
tv_sec: 0,
tv_nsec: 0,
}
}
}

@ -1,618 +0,0 @@
//! `NcVisual*` methods and associated functions.
use core::ptr::null_mut;
use libc::c_void;
use crate::{
cstring, error, error_ref_mut, rstring, Nc, NcBlitter, NcComponent, NcDim, NcDirect, NcDirectF,
NcError, NcIntResult, NcPixel, NcPlane, NcResult, NcRgba, NcScale, NcTime, NcVGeom, NcVisual,
NcVisualOptions, NCBLIT_PIXEL, NCRESULT_ERR,
};
/// # NcVisualOptions Constructors
impl NcVisualOptions {
// /// New NcVisualOptions
// pub fn new() -> Self {
// Self::with_flags()
// }
//
// pub fn new_aligned() -> Self {
// Self::with_flags_aligned()
// }
// TODO:
// - horizontally aligned
// - copy from NcPlaneOptions (with_flags_aligned & with_flags,)
// y is an ncalign_e if NCVISUAL_OPTION_VERALIGNED is provided.
// x is an ncalign_e value if NCVISUAL_OPTION_HORALIGNED is provided.
/// Specify an existing plane.
///
/// If [`NCVISUAL_OPTION_CHILDPLANE`][crate::NCVISUAL_OPTION_CHILDPLANE] is
/// used in `flags` then the `plane` is interpreted as the parent [`NcPlane`]
/// of the new plane created for this [`NcVisual`].
pub fn with_plane(
plane: &mut NcPlane,
scale: NcScale,
y: NcDim,
x: NcDim,
begy: NcDim,
begx: NcDim,
leny: NcDim,
lenx: NcDim,
blitter: NcBlitter,
flags: u32,
transcolor: NcRgba,
) -> Self {
Self {
// provided plane
n: plane,
// the source is stretched/scaled relative to the provided ncplane
scaling: scale,
y: y as i32,
x: x as i32,
// origin of rendered section
begy: begy as i32,
begx: begx as i32,
// size of rendered section
leny: leny as i32,
lenx: lenx as i32,
// glyph set to use
blitter,
// bitmask over NCVISUAL_OPTION_*
flags: flags as u64,
transcolor,
}
}
pub fn without_plane(
y: NcDim,
x: NcDim,
begy: NcDim,
begx: NcDim,
leny: NcDim,
lenx: NcDim,
blitter: NcBlitter,
flags: u32,
transcolor: u32,
) -> Self {
Self {
n: null_mut(),
scaling: crate::NCSCALE_NONE,
// where the created ncplane will be placed relative to the standard plane's origin
y: y as i32,
x: x as i32,
// origin of rendered section
begy: begy as i32,
begx: begx as i32,
// size of rendered section
leny: leny as i32,
lenx: lenx as i32,
// glyph set to use
blitter,
// bitmask over NCVISUAL_OPTION_*
flags: flags as u64,
// This color will be treated as transparent with flag [NCVISUAL_OPTION_ADDALPHA].
transcolor,
}
}
pub fn fullsize_pixel_without_plane(y: NcDim, x: NcDim, leny: NcDim, lenx: NcDim) -> Self {
Self::without_plane(y, x, 0, 0, leny, lenx, NCBLIT_PIXEL, 0, 0)
}
}
/// # NcVisual Constructors & destructors
impl NcVisual {
/// Like [from_rgba][NcVisual#method.from_rgba], but 'bgra' is arranged as BGRA.
///
/// *C style function: [ncvisual_from_bgra()][crate::ncvisual_from_bgra].*
pub fn from_bgra<'a>(
bgra: &[u8],
rows: NcDim,
rowstride: NcDim,
cols: NcDim,
) -> NcResult<&'a mut NcVisual> {
error_ref_mut![
unsafe {
crate::ncvisual_from_bgra(
bgra.as_ptr() as *const c_void,
rows as i32,
rowstride as i32,
cols as i32,
)
},
&format![
"NcVisual::from_bgra(bgra, {}, {}, {})",
rows, rowstride, cols
]
]
}
/// Opens a visual at `file`, extracts the codec and parameters and
/// decodes the first image to memory.
///
/// *C style function: [ncvisual_from_file()][crate::ncvisual_from_file].*
pub fn from_file<'a>(file: &str) -> NcResult<&'a mut NcVisual> {
error_ref_mut![
unsafe { crate::ncvisual_from_file(cstring![file]) },
&format!("NcVisual::from_file({})", file)
]
}
/// Promotes an NcPlane to an NcVisual.
///
/// The plane may contain only spaces, half blocks, and full blocks.
/// This will be checked, and any other glyph will result in an error.
///
/// This function exists so that planes can be subjected to NcVisual transformations.
/// If possible, it's better to create the ncvisual from memory using
/// [from_rgba][NcVisual#method.from_rgba].
///
/// *C style function: [ncvisual_from_plane()][crate::ncvisual_from_plane].*
pub fn from_plane<'a>(
plane: &NcPlane,
blitter: NcBlitter,
beg_y: NcDim,
beg_x: NcDim,
len_y: NcDim,
len_x: NcDim,
) -> NcResult<&'a mut NcVisual> {
error_ref_mut![
unsafe {
crate::ncvisual_from_plane(
plane,
blitter,
beg_y as i32,
beg_x as i32,
len_y as i32,
len_x as i32,
)
},
&format!(
"NcVisual::from_file(plane, {}, {}, {}, {}, {})",
blitter, beg_y, beg_x, len_y, len_x
)
]
}
/// Like [`from_rgba`][NcVisual#method.from_rgba], but the pixels are
/// 4-byte RGBX. Alpha is filled in throughout using 'alpha'.
///
/// `rowstride` must be a multiple of 4.
///
/// *C style function: [ncvisual_from_rgb_loose()][crate::ncvisual_from_rgb_loose].*
pub fn from_rgb_loose<'a>(
rgb: &[u8],
rows: NcDim,
rowstride: NcDim,
cols: NcDim,
alpha: NcComponent,
) -> NcResult<&'a mut NcVisual> {
error_ref_mut![
unsafe {
crate::ncvisual_from_rgb_loose(
rgb.as_ptr() as *const c_void,
rows as i32,
rowstride as i32,
cols as i32,
alpha as i32,
)
},
&format!(
"NcVisual::from_rgb_loose(rgba, {}, {}, {}, {})",
rows, rowstride, cols, alpha
)
]
}
/// Like [`from_rgba`][NcVisual#method.from_rgba], but the pixels are
/// 3-byte RGB. Alpha is filled in throughout using 'alpha'.
///
/// *C style function: [ncvisual_from_rgb_packed()][crate::ncvisual_from_rgb_packed].*
pub fn from_rgb_packed<'a>(
rgb: &[u8],
rows: NcDim,
rowstride: NcDim,
cols: NcDim,
alpha: NcComponent,
) -> NcResult<&'a mut NcVisual> {
error_ref_mut![
unsafe {
crate::ncvisual_from_rgb_packed(
rgb.as_ptr() as *const c_void,
rows as i32,
rowstride as i32,
cols as i32,
alpha as i32,
)
},
&format!(
"NcVisual::from_rgb_packed(rgba, {}, {}, {}, {})",
rows, rowstride, cols, alpha
)
]
}
/// Prepares an NcVisual, and its underlying NcPlane, based off RGBA content
/// in memory at `rgba`.
///
/// `rgba` is laid out as `rows` lines, each of which is `rowstride` bytes in length.
/// Each line has `cols` 32-bit 8bpc RGBA pixels followed by possible padding
/// (there will be rowstride - cols * 4 bytes of padding).
///
/// The total size of `rgba` is thus (rows * rowstride) bytes, of which
/// (rows * cols * 4) bytes are actual non-padding data.
///
/// *C style function: [ncvisual_from_rgba()][crate::ncvisual_from_rgba].*
pub fn from_rgba<'a>(
rgba: &[u8],
rows: NcDim,
rowstride: NcDim,
cols: NcDim,
) -> NcResult<&'a mut NcVisual> {
error_ref_mut![
unsafe {
crate::ncvisual_from_rgba(
rgba.as_ptr() as *const c_void,
rows as i32,
rowstride as i32,
cols as i32,
)
},
&format!(
"NcVisual::from_rgba(rgba, {}, {}, {})",
rows, rowstride, cols
)
]
}
/// Destroys this NcVisual.
///
/// Rendered elements will not be disrupted, but the visual can be neither
/// decoded nor rendered any further.
///
/// *C style function: [ncvisual_destroy()][crate::ncvisual_destroy].*
pub fn destroy(&mut self) {
unsafe { crate::ncvisual_destroy(self) }
}
}
/// # NcVisual Methods
impl NcVisual {
/// Gets the specified pixel from this NcVisual.
///
/// *C style function: [ncvisual_at_yx()][crate::ncvisual_at_yx].*
pub fn at_yx(&self, y: NcDim, x: NcDim) -> NcResult<NcPixel> {
let mut pixel = 0;
let res = unsafe { crate::ncvisual_at_yx(self, y as i32, x as i32, &mut pixel) };
error![res, "NcVisual.at_yx()", pixel]
}
/// Extracts the next frame from the NcVisual.
///
/// Returns 0 for normal frames, and 1 to indicate EOF.
///
/// *C style function: [ncvisual_decode()][crate::ncvisual_decode].*
pub fn decode(&mut self) -> NcResult<NcIntResult> {
let res = unsafe { crate::ncvisual_decode(self) };
if res == NCRESULT_ERR {
Err(NcError::with_msg(res, "NcVisual.decode()"))
} else {
Ok(res)
}
}
/// Extracts the next frame from the NcVisual, ala [decode][NcVisual#method.decode],
/// but if we have reached the end, rewinds to the first frame.
///
/// *A subsequent [NcVisual.render]() will render the first frame,
/// as if the ncvisual had been closed and reopened.*
///
/// Returns 0 for normal frames and 1 to indicate EOF.
///
/// *C style function: [ncvisual_decode_loop()][crate::ncvisual_decode_loop].*
pub fn decode_loop(&mut self) -> NcResult<NcIntResult> {
let res = unsafe { crate::ncvisual_decode_loop(self) };
if res == NCRESULT_ERR {
Err(NcError::with_msg(res, "NcVisual.decode_loop()"))
} else {
Ok(res)
}
}
/// Gets the size and ratio of NcVisual pixels to output cells along the
/// `y→to_y` and `x→to_x` axes.
///
/// Returns a tuple with (y, x, to_y, to_x)
///
/// An NcVisual of `y` by `x` pixels will require
/// (`y` * `to_y`) by (`x` * `to_x`) cells for full output.
///
/// Errors on invalid blitter in `options`. Scaling is taken into consideration.
///
/// *C style function: [ncvisual_blitter_geom()][crate::ncvisual_blitter_geom].*
pub fn geom(
&self,
nc: &Nc,
options: &NcVisualOptions,
) -> NcResult<(NcDim, NcDim, NcDim, NcDim)> {
let mut y = 0;
let mut x = 0;
let mut to_y = 0;
let mut to_x = 0;
let res = unsafe {
crate::ncvisual_blitter_geom(
nc,
self,
options,
&mut y,
&mut x,
&mut to_y,
&mut to_x,
null_mut(),
)
};
error![
res,
"NcVisual.geom()",
(y as NcDim, x as NcDim, to_y as NcDim, to_x as NcDim)
];
}
/// Gets the default media (not plot) blitter for this environment when using
/// the specified scaling method.
///
/// Currently, this means:
/// - if lacking UTF-8, NCBLIT_1x1.
/// - otherwise, if not NCSCALE_STRETCH, NCBLIT_2x1.
/// - otherwise, if sextants are not known to be good, NCBLIT_2x2.
/// - otherwise NCBLIT_3x2 NCBLIT_2x2 and NCBLIT_3x2 both distort the original
/// aspect ratio, thus NCBLIT_2x1 is used outside of NCSCALE_STRETCH.
///
/// *C style function: [ncvisual_media_defblitter()][crate::ncvisual_media_defblitter].*
pub fn media_defblitter(nc: &Nc, scale: NcScale) -> NcBlitter {
unsafe { crate::ncvisual_media_defblitter(nc, scale) }
}
/// Polyfills at the specified location using `rgba`.
///
/// *C style function: [ncvisual_polyfill_yx()][crate::ncvisual_polyfill_yx].*
pub fn polyfill_yx(&mut self, y: NcDim, x: NcDim, rgba: NcRgba) -> NcResult<()> {
error![
unsafe { crate::ncvisual_polyfill_yx(self, y as i32, x as i32, rgba) },
&format!["NcVisual.polyfill_yx({}, {}, {})", y, x, rgba]
]
}
/// Renders the decoded frame to the specified [`NcPlane`].
///
/// See [`NcVisualOptions`].
///
/// *C style function: [ncvisual_render()][crate::ncvisual_render].*
pub fn render(&mut self, nc: &mut Nc, options: &NcVisualOptions) -> NcResult<&mut NcPlane> {
error_ref_mut![
unsafe { crate::ncvisual_render(nc, self, options) },
"NcVisual.render(Nc, &NcVisualOptions)"
]
}
/// Resizes the visual to `cols` X `rows` pixels.
///
/// This is a lossy transformation, unless the size is unchanged.
///
/// *C style function: [ncvisual_resize()][crate::ncvisual_resize].*
pub fn resize(&mut self, rows: NcDim, cols: NcDim) -> NcResult<()> {
error![
unsafe { crate::ncvisual_resize(self, rows as i32, cols as i32) },
&format!["NcVisual.resize({}, {})", rows, cols]
]
}
/// Resizes the visual to in the image to `rows` X `cols` pixels, without
/// interpolating the color values.
///
/// The original color is retained.
///
/// *C style function:
/// [ncvisual_resize_noninterpolative()][crate::ncvisual_resize_noninterpolative].*
pub fn resize_noninterpolative(&mut self, rows: NcDim, cols: NcDim) -> NcResult<()> {
error![
unsafe { crate::ncvisual_resize_noninterpolative(self, rows as i32, cols as i32) },
&format!["NcVisual.resize_noninterpolative({}, {})", cols, rows]
]
}
/// Rotates the visual `rads` radians.
///
/// Only M_PI/2 and -M_PI/2 are supported at the moment,
/// but this will change. (FIXME)
///
/// *C style function: [ncvisual_rotate()][crate::ncvisual_rotate].*
pub fn rotate(&mut self, rads: f64) -> NcResult<()> {
error![
unsafe { crate::ncvisual_rotate(self, rads) },
&format!["NcVisual.rotate({})", rads]
]
}
/// Sets the specified pixel.
///
/// *C style function: [ncvisual_set_yx()][crate::ncvisual_set_yx].*
pub fn set_yx(&mut self, y: NcDim, x: NcDim, pixel: NcPixel) -> NcResult<()> {
error![
unsafe { crate::ncvisual_set_yx(self, y as i32, x as i32, pixel) },
&format!["NcVisual.set_yx({}, {}, {})", y, x, pixel]
]
}
/// Displays frames.
///
/// *Provide as an argument to ncvisual_stream().*
///
/// If you'd like subtitles to be decoded, provide an ncplane as the curry.
/// If the curry is NULL, subtitles will not be displayed.
///
/// *C style function: [ncvisual_simple_streamer()][crate::ncvisual_simple_streamer].*
pub fn simple_streamer(
&mut self,
options: &mut NcVisualOptions,
time: &NcTime,
curry: Option<&mut NcPlane>,
) -> NcResult<()> {
if let Some(plane) = curry {
error![
unsafe {
crate::ncvisual_simple_streamer(
self,
options,
time,
plane as *mut _ as *mut libc::c_void,
)
},
&format![
"NcVisual.simple_streamer({:?}, {:?}, ncplane)",
options, time
]
]
} else {
error![
unsafe { crate::ncvisual_simple_streamer(self, options, time, null_mut()) },
&format!["NcVisual.simple_streamer({:?}, {:?}, null)", options, time]
]
}
}
// // TODO
//
// /// Streams the entirety of the media, according to its own timing.
// ///
// /// Blocking, obviously.
// ///
// /// If `streamer` is provided it will be called for each frame, and its return
// /// value handled as outlined for streamcb.
// /// If streamer() returns non-zero, the stream is aborted, and that value is
// /// returned. By convention, return a positive number to indicate intentional
// /// abort from within streamer().
// ///
// /// `timescale` allows the frame duration time to be scaled.
// /// For a visual naturally running at 30FPS, a 'timescale' of 0.1 will result
// /// in 300 FPS, and a `timescale` of 10 will result in 3 FPS.
// /// It is an error to supply `timescale` less than or equal to 0.
// ///
// /// *C style function: [ncvisual_streamer()][crate::ncvisual_streamer].*
// //
// // TODO: add streamcb
// // INFO: QUESTION: is curry also optional like in simple_streamer?
// //
// pub fn simple_streamer(
// &mut self,
// nc: &mut Nc,
// timescale: f32,
// //streamer: Option<streamcb>
// options: &NcVisualOptions,
// curry: Option<&mut NcPlane>,
// ) -> NcResult<()> {
// }
/// If a subtitle ought be displayed at this time, returns a heap-allocated
/// copy of the UTF8 text.
///
/// *C style function: [ncvisual_subtitle()][crate::ncvisual_subtitle].*
pub fn subtitle(&self) -> NcResult<&str> {
let res = unsafe { crate::ncvisual_subtitle(self) };
if !res.is_null() {
Ok(rstring![res])
} else {
Err(NcError::with_msg(NCRESULT_ERR, "NcVisual.subtitle()"))
}
}
}
/// # NcDirectF Constructors & destructors
impl NcDirectF {
/// Loads media from disk, but do not yet renders it (presumably because you
/// want to get its geometry via [ncdirectf_geom()][0], or to use the same
/// file with [ncdirectf_render()][1] multiple times).
///
/// You must destroy the result with [ncdirectf_free()][2];
///
/// [0]: crate::NcDirectF#method.ncdirectf_geom
/// [1]: crate::NcDirectF#method.ncdirectf_render
/// [2]: crate::NcDirectF#method.ncdirectf_free
///
/// *C style function: [ncdirectf_from_file()][crate::ncdirectf_from_file].*
pub fn ncdirectf_from_file<'a>(ncd: &mut NcDirect, file: &str) -> NcResult<&'a mut NcDirectF> {
error_ref_mut![
unsafe { crate::ncdirectf_from_file(ncd, cstring![file]) },
&format!("NcDirectF::ncdirectf_from_file(ncd, {})", file)
]
}
/// Frees a [`NcDirectF`] returned from [ncdirectf_from_file()][0].
///
/// [0]: crate::NcDirectF#method.ncdirectf_from_file
///
/// *C style function: [ncdirectf_free()][crate::ncdirectf_free].*
pub fn ncdirectf_free(&mut self) {
unsafe { crate::ncdirectf_free(self) };
}
}
/// # NcDirectF Methods
impl NcDirectF {
/// Same as [`NcDirect.render_frame()`][0], except `frame` must already have
/// been loaded.
///
/// A loaded frame may be rendered in different ways before it is destroyed.
///
/// [0]: NcDirect#method.render_frame
///
/// *C style function: [ncvisual_render()][crate::ncvisual_render].*
pub fn ncdirectf_render(
&mut self,
ncd: &mut NcDirect,
options: &NcVisualOptions,
) -> NcResult<&mut NcPlane> {
error_ref_mut![
unsafe { crate::ncdirectf_render(ncd, self, options) },
"NcVisual.render()"
]
}
/// Having loaded the `frame`, get the geometry of a potential render.
///
/// *C style function: [ncdirectf_geom()][crate::ncdirectf_geom].*
pub fn ncdirectf_geom(
&mut self,
ncd: &mut NcDirect,
options: &NcVisualOptions,
) -> NcResult<NcVGeom> {
let mut geom = NcVGeom::new();
let res = unsafe { crate::ncdirectf_geom(ncd, self, options, &mut geom) };
error![res, "NcDirectF.ncdirectf_geom()", geom];
}
}
/// # NcVGeom Constructors
impl NcVGeom {
/// Returns a new `NcVGeom` with zeroed fields.
pub fn new() -> Self {
Self {
pixy: 0,
pixx: 0,
cdimy: 0,
cdimx: 0,
rpixy: 0,
rpixx: 0,
rcelly: 0,
rcellx: 0,
scaley: 0,
scalex: 0,
maxpixely: 0,
maxpixelx: 0,
blitter: 0,
}
}
}

@ -1,251 +0,0 @@
// functions already exported by bindgen : 26
// -----------------------------------------
// (W) wrap: 22
// (#) test: 0
// -----------------------------------------
//W ncdirectf_free
//W ncdirectf_from_file
// ncdirectf_geom
// ncdirectf_render
//W ncvisual_at_yx
//W ncvisual_decode
//W ncvisual_decode_loop
//W ncvisual_destroy
//W ncvisual_from_bgra
//W ncvisual_from_file
//W ncvisual_from_plane
//W ncvisual_from_rgba
//W ncvisual_from_rgb_packed
//W ncvisual_from_rgb_loose
//W ncvisual_inflate
//W ncvisual_blitter_geom
//W ncvisual_media_defblitter
//W ncvisual_polyfill_yx
// ncvisual_plane_create
//W ncvisual_render
//W ncvisual_resize
//W ncvisual_rotate
//W ncvisual_set_yx
//W ncvisual_simple_streamer
//~ ncvisual_stream
//W ncvisual_subtitle
#[allow(unused_imports)] // for the doc comments
use crate::{NcChannel, NcDim, NcRgb};
mod methods;
/// Indicates how to scale an [`NcVisual`] during rendering.
///
/// - [`NCSCALE_NONE`] will apply no scaling.
/// - [`NCSCALE_SCALE`] scales a visual to the plane's size,
/// maintaining aspect ratio.
/// - [`NCSCALE_STRETCH`] stretches and scales the image in an
/// attempt to fill the entirety of the plane.
/// - [`NCSCALE_NONE_HIRES`] like `NCSCALE_NONE` admitting high-res blitters.
/// - [`NCSCALE_SCALE_HIRES`] like `NCSCALE_SCALE` admitting high-res blitters.
///
/// The `NCSCALE_*` preferences are applied only for the context of
/// [`NcVisual.render`][NcVisual#method.render]. You can think of it as a pipeline:
///
/// ```txt
/// NcVisual::fromfile() → frame → NcVisual.render() → scaling → output frame → blit
/// ```
///
/// where you still have the original frame. Whereas
/// [`NcVisual.resize`][NcVisual#method.resize] and
/// [`NcVisual.resize_noninterpolative`][NcVisual#method.resize_noninterpolative]
/// are changing that original frame.
///
pub type NcScale = crate::bindings::ffi::ncscale_e;
/// Maintains original size.
pub const NCSCALE_NONE: NcScale = crate::bindings::ffi::ncscale_e_NCSCALE_NONE;
/// Maintains aspect ratio.
pub const NCSCALE_SCALE: NcScale = crate::bindings::ffi::ncscale_e_NCSCALE_SCALE;
/// Throws away aspect ratio.
pub const NCSCALE_STRETCH: NcScale = crate::bindings::ffi::ncscale_e_NCSCALE_STRETCH;
/// Maintains original size, admitting high-resolution blitters
/// that don't preserve aspect ratio.
pub const NCSCALE_NONE_HIRES: NcScale = crate::bindings::ffi::ncscale_e_NCSCALE_NONE_HIRES;
/// Maintains aspect ratio, admitting high-resolution blitters
/// that don't preserve aspect ratio.
pub const NCSCALE_SCALE_HIRES: NcScale = crate::bindings::ffi::ncscale_e_NCSCALE_SCALE_HIRES;
/// A visual bit of multimedia.
///
/// It can be constructed from a rgba or bgra buffer.
///
/// The [NcVisualOptions] structure is used only by the following methods:
/// - [.geom][NcVisual#method.geom]
/// - [.render][NcVisual#method.render]
/// - [.simple_streamer][NcVisual#method.simple_streamer]
pub type NcVisual = crate::bindings::ffi::ncvisual;
/// A type alias of [`NcVisual`] (NcDirect ***F**rame*) intended to be used
/// with its `ncdirectf_*` methods, in [`NcDirect`][crate::NcDirect] mode.
pub type NcDirectF = NcVisual;
/// Describes all geometries of an [`NcVisual`] ncvisualboth those which are inherent, and
/// those in a given rendering regime.
///
/// *FIXME this ought be used in the rendered mode API as well;
/// its currently only used by direct mode.*
/// *(See [ncvgeom][1] more more information)*
///
/// This is the return type of the [NcDirectF.ncdirectf_geom()][0] method.
///
/// [0]: NcDirectF#method.ncdirectf_geom
/// [1]: crate::bindings::ffi::ncvgeom
pub type NcVGeom = crate::bindings::ffi::ncvgeom;
/// Options struct for [`NcVisual`]
///
/// If a plane is not provided, one will be created, having the exact size
/// necessary to display the visual (this might be smaller or larger than
/// the rendering area). if NCVISUAL_OPTION_CHILDPLANE is provided, this
/// will be interpreted as the parent.
///
/// A subregion of the visual can be rendered using `begx`, `begy`, `lenx`, and `leny`.
pub type NcVisualOptions = crate::bindings::ffi::ncvisual_options;
// NcRgba
//
/// 32 bits broken into 3x 8bpp RGB channels + 8ppp alpha.
///
/// Unlike with [`NcChannel`], operations involving `NcRgb` ignores the last 4th byte
///
/// ## Diagram
///
/// ```txt
/// AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB
/// ```
/// `type in C: no data type`
///
/// See also: [NcRgb] and [NcChannel] types.
pub type NcRgba = u32;
// // NcBgra
// //
// /// 32 bits broken into 3x 8bpp BGR channels + 8ppp alpha.
// ///
// /// ## Diagram
// ///
// /// ```txt
// /// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
// /// ```
// ///
// /// `type in C: no data type`
// ///
// /// See also: [NcRgba], [NcRgb] and [NcChannel] types.
// pub type NcBgra = u32;
/// Treats as transparent the color specified in the `transcolor` field.
pub const NCVISUAL_OPTION_ADDALPHA: u32 = crate::bindings::ffi::NCVISUAL_OPTION_ADDALPHA;
/// Uses [`NCALPHA_BLEND`][crate::NCALPHA_BLEND] with visual.
pub const NCVISUAL_OPTION_BLEND: u32 = crate::bindings::ffi::NCVISUAL_OPTION_BLEND;
/// allows you to indicate that the n field of ncvisual_options refers not to
/// the plane onto which you'd like to blit, but the parent of a new plane.
///
/// A plane will be created using the other parameters in the ncvisual_options,
/// as a child of this parent. This means things like, say, vertically centering
/// a sprixel relative to the standard plane can be done in one step.
pub const NCVISUAL_OPTION_CHILDPLANE: u32 = crate::bindings::ffi::NCVISUAL_OPTION_CHILDPLANE;
/// Fails rather than gracefully degrade. See [NcBlitter].
pub const NCVISUAL_OPTION_NODEGRADE: u32 = crate::bindings::ffi::NCVISUAL_OPTION_NODEGRADE;
/// Y is an alignment, not absolute.
pub const NCVISUAL_OPTION_VERALIGNED: u32 = crate::bindings::ffi::NCVISUAL_OPTION_VERALIGNED;
/// X is an alignment, not absolute.
pub const NCVISUAL_OPTION_HORALIGNED: u32 = crate::bindings::ffi::NCVISUAL_OPTION_HORALIGNED;
/// Uses non-interpolative scaling.
pub const NCVISUAL_OPTION_NOINTERPOLATE: u32 = crate::bindings::ffi::NCVISUAL_OPTION_NOINTERPOLATE;
/// The blitter mode to use for rasterizing an [`NcVisual`].
///
/// We never blit full blocks, but instead spaces (more efficient) with the
/// background set to the desired foreground.
///
/// ## Modes
///
/// - [`NCBLIT_1x1`]
/// - [`NCBLIT_2x1`]
/// - [`NCBLIT_2x2`]
/// - [`NCBLIT_3x2`]
/// - [`NCBLIT_4x1`]
/// - [`NCBLIT_8x1`]
/// - [`NCBLIT_BRAILLE`]
/// - [`NCBLIT_DEFAULT`]
/// - [`NCBLIT_PIXEL`]
///
/// There is a mechanism of graceful degradation, that works as follows:
/// - without braille support, NCBLIT_BRAILLE decays to NCBLIT_3x2
/// - without bitmap support, NCBLIT_PIXEL decays to NCBLIT_3x2
/// - without sextant support, NCBLIT_3x2 decays to NCBLIT_2x2
/// - without quadrant support, NCBLIT_2x2 decays to NCBLIT_2x1
/// - the only viable blitters in ASCII are NCBLIT_1x1 and NCBLIT_PIXEL
///
/// If you don't want this behaviour you have to use [NCVISUAL_OPTION_NODEGRADE]
///
pub type NcBlitter = crate::bindings::ffi::ncblitter_e;
/// [`NcBlitter`] mode using: space, compatible with ASCII
pub const NCBLIT_1x1: NcBlitter = crate::bindings::ffi::ncblitter_e_NCBLIT_1x1;
/// [`NcBlitter`] mode using: halves + 1x1 (space)
/// ▄▀
pub const NCBLIT_2x1: NcBlitter = crate::bindings::ffi::ncblitter_e_NCBLIT_2x1;
/// [`NcBlitter`] mode using: quadrants + 2x1
/// ▗▐ ▖▀▟▌▙
pub const NCBLIT_2x2: NcBlitter = crate::bindings::ffi::ncblitter_e_NCBLIT_2x2;
/// [`NcBlitter`] mode using: sextants
/// 🬀🬁🬂🬃🬄🬅🬆🬇🬈🬉🬊🬋🬌🬍🬎🬏🬐🬑🬒🬓🬔🬕🬖🬗🬘🬙🬚🬛🬜🬝🬞🬟🬠🬡🬢🬣🬤🬥🬦🬧🬨🬩🬪🬫🬬🬭🬮🬯🬰🬱🬲🬳🬴🬵🬶🬷🬸🬹🬺🬻
pub const NCBLIT_3x2: NcBlitter = crate::bindings::ffi::ncblitter_e_NCBLIT_3x2;
/// [`NcBlitter`] mode using: four vertical levels
/// █▆▄▂
pub const NCBLIT_4x1: NcBlitter = crate::bindings::ffi::ncblitter_e_NCBLIT_4x1;
/// [`NcBlitter`] mode using: eight vertical levels
/// █▇▆▅▄▃▂▁
pub const NCBLIT_8x1: NcBlitter = crate::bindings::ffi::ncblitter_e_NCBLIT_8x1;
/// [`NcBlitter`] mode using: 4 rows, 2 cols (braille)
/// ⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿
pub const NCBLIT_BRAILLE: NcBlitter = crate::bindings::ffi::ncblitter_e_NCBLIT_BRAILLE;
/// [`NcBlitter`] mode where the blitter is automatically chosen
pub const NCBLIT_DEFAULT: NcBlitter = crate::bindings::ffi::ncblitter_e_NCBLIT_DEFAULT;
/// Sixel/Pixel mode
///
/// NCBLIT_PIXEL
///
/// See [Sixel in Wikipedia](https://en.wikipedia.org/wiki/Sixel).
pub const NCBLIT_PIXEL: NcBlitter = crate::bindings::ffi::ncblitter_e_NCBLIT_PIXEL;
/// Contains the pixel geometry information as returned by the
/// NcPlane.[pixelgeom()][crate::NcPlane#method.pixelgeom] method.
///
/// If bitmaps are not supported, the fields `max_bitmap_*` will be 0.
#[derive(Clone, Debug)]
pub struct NcPixelGeometry {
/// Geometry of the display region
pub term_y: NcDim,
pub term_x: NcDim,
pub cell_y: NcDim,
pub cell_x: NcDim,
pub max_bitmap_y: NcDim,
pub max_bitmap_x: NcDim,
}

@ -1,179 +0,0 @@
use core::ptr::null_mut;
use crate::{
cstring, error, error_ref_mut, error_str, ncmenu_create,
widgets::{NcMenu, NcMenuOptions},
NcInput, NcPlane, NcResult,
};
#[allow(unused_imports)]
use crate::widgets::{NcMenuItem, NcMenuSection};
/// # `NcMenu` constructors & destructors
impl NcMenu {
/// Creates an [`NcMenu`] with the specified options.
///
/// Menus are currently bound to an overall [`Notcurses`][crate::Notcurses]
/// object (as opposed to a particular plane), and are implemented as
/// [`NcPlane`]s kept atop other NcPlanes.
///
/// *C style function: [ncmenu_create()][crate::ncmenu_create].*
pub fn new<'a>(plane: &mut NcPlane, options: NcMenuOptions) -> NcResult<&'a mut Self> {
error_ref_mut![unsafe { ncmenu_create(plane, &options) }, "Creating NcMenu"]
}
/// Destroys an `NcMenu` created with [`new`][NcMenu#method.new].
///
/// *C style function: [ncmenu_destroy()][crate::ncmenu_destroy].*
pub fn destroy(&mut self) -> NcResult<()> {
error![unsafe { crate::ncmenu_destroy(self) }]
}
}
/// # `NcMenu` methods
impl NcMenu {
/// Disables or enables an [`NcMenuItem`].
///
/// *C style function: [ncmenu_item_set_status()][crate::ncmenu_item_set_status].*
pub fn item_set_status(&mut self, section: &str, item: &str, enabled: bool) -> NcResult<()> {
error![
unsafe {
crate::ncmenu_item_set_status(self, cstring![section], cstring![item], enabled)
},
&format!(
".item_set_status({:?}, {:?}, {:?}, {})",
self, section, item, enabled
)
]
}
/// Returns the [`NcMenuItem`] description
/// corresponding to the mouse `click`.
///
/// The NcMenuItem must be on an actively unrolled section, and the click
/// must be in the area of a valid item.
///
/// If `ninput` is provided, and the selected item has a shortcut,
/// it will be filled in with that shortcut.
///
/// *C style function: [ncmenu_mouse_selected()][crate::ncmenu_mouse_selected].*
pub fn mouse_selected(
&self,
click: NcInput,
shortcut: Option<&mut NcInput>,
) -> NcResult<String> {
let ninput;
if let Some(i) = shortcut {
ninput = i as *mut _;
} else {
ninput = null_mut();
}
error_str![
unsafe { crate::ncmenu_mouse_selected(self, &click, ninput) },
"Getting NcMenuItem description"
]
}
/// Moves to the next item within the currently unrolled section.
///
/// If no section is unrolled, the first section will be unrolled.
///
/// *C style function: [ncmenu_nextitem()][crate::ncmenu_nextitem].*
pub fn nextitem(&mut self) -> NcResult<()> {
error![unsafe { crate::ncmenu_nextitem(self) }]
}
/// Unrolls the next section (relative to current unrolled).
///
/// If no section is unrolled, the first section will be unrolled.
///
/// *C style function: [ncmenu_nextsection()][crate::ncmenu_nextsection].*
pub fn nextsection(&mut self) -> NcResult<()> {
error![unsafe { crate::ncmenu_nextsection(self) }]
}
/// Offers the `input` to this `NcMenu`.
///
/// If it's relevant, this function returns true,
/// and the input ought not be processed further.
/// If it's irrelevant to the menu, false is returned.
///
/// Relevant inputs include:
/// - mouse movement over a hidden menu
/// - a mouse click on a menu section (the section is unrolled)
/// - a mouse click outside of an unrolled menu (the menu is rolled up)
/// - left or right on an unrolled menu (navigates among sections)
/// - up or down on an unrolled menu (navigates among items)
/// - escape on an unrolled menu (the menu is rolled up)
///
/// *C style function: [ncmenu_offer_input()][crate::ncmenu_offer_input].*
pub fn offer_input(&mut self, input: NcInput) -> bool {
unsafe { crate::ncmenu_offer_input(self, &input) }
}
/// Returns the [`NcPlane`] backing this `NcMenu`.
///
/// *C style function: [ncmenu_plane()][crate::ncmenu_plane].*
pub fn plane(&mut self) -> NcResult<&NcPlane> {
error_ref_mut![
unsafe { crate::ncmenu_plane(self) },
"Getting the backing NcPlane"
]
}
/// Moves to the previous item within the currently unrolled section.
///
/// If no section is unrolled, the first section will be unrolled.
///
/// *C style function: [ncmenu_previtem()][crate::ncmenu_previtem].*
pub fn previtem(&mut self) -> NcResult<()> {
error![unsafe { crate::ncmenu_previtem(self) }]
}
/// Unrolls the previous section (relative to current unrolled).
///
/// If no section is unrolled, the first section will be unrolled.
///
/// *C style function: [ncmenu_prevsection()][crate::ncmenu_prevsection].*
pub fn prevsection(&mut self) -> NcResult<()> {
error![unsafe { crate::ncmenu_prevsection(self) }]
}
/// Rolls up any unrolled [`NcMenuSection`]
/// and hides this `NcMenu` if using hiding.
///
/// *C style function: [ncmenu_rollup()][crate::ncmenu_rollup].*
pub fn rollup(&mut self) -> NcResult<()> {
error![unsafe { crate::ncmenu_rollup(self) }]
}
/// Returns the selected item description, if there's an unrolled section.
///
/// If `shortcut` is provided, and the selected item has a shortcut,
/// it will be filled in with that shortcut--this can allow faster matching.
///
/// *C style function: [ncmenu_selected()][crate::ncmenu_selected].*
pub fn selected(&mut self, shortcut: Option<&mut NcInput>) -> Option<String> {
let ninput;
if let Some(i) = shortcut {
ninput = i as *mut _;
} else {
ninput = null_mut();
}
let res = unsafe { crate::ncmenu_selected(self, ninput) };
if !res.is_null() {
Some(unsafe { (&*res).to_string() })
} else {
None
}
}
/// Unrolls the specified [`NcMenuSection`],
/// making the menu visible if it was invisible
/// and rolling up any `NcMenuSection` that is already unrolled.
///
/// *C style function: [ncmenu_unroll()][crate::ncmenu_unroll].*
pub fn unroll(&mut self, sectionindex: u32) -> NcResult<()> {
error![unsafe { crate::ncmenu_unroll(self, sectionindex as i32) }]
}
}

@ -1,69 +0,0 @@
//! `NcMenu*` methods and associated functions.
use super::{NcMenuItem, NcMenuSection};
use crate::{cstring_mut, NcInput};
use core::ptr::null_mut;
#[allow(unused_imports)]
use crate::widgets::NcMenu;
mod menu;
mod options;
pub use menu::*;
pub use options::*;
/// # `NcMenuItem` Constructors
impl NcMenuItem {
/// New NcMenuItem for [`NcMenu`].
pub fn new(desc: &str, shortcut: NcInput) -> Self {
Self {
// utf-8 menu item, NULL for horizontal separator
desc: cstring_mut![desc],
// ´NcInput´ shortcut, all should be distinct
shortcut,
}
}
/// New empty NcMenuItem for [`NcMenu`].
pub fn new_empty() -> Self {
Self {
desc: null_mut(),
shortcut: NcInput::new_empty(),
}
}
}
/// # `NcMenuSection` Constructors
///
// Must contain at least 1 NcMenuItem.
impl NcMenuSection {
/// New NcMenuSection for [`NcMenu`].
pub fn new(name: &str, items: &mut [NcMenuItem], shortcut: NcInput) -> Self {
Self {
// utf-8 name string
name: cstring_mut![name],
// array of itemcount `NcMenuItem`s
items: items.as_mut_ptr(),
//
itemcount: items.len() as i32,
// shortcut, will be underlined if present in name
shortcut,
}
}
/// New NcMenuSection separator for [`NcMenu`].
///
pub fn new_separator() -> Self {
Self {
name: null_mut(),
items: null_mut(),
itemcount: 0,
shortcut: NcInput::new_empty(),
}
}
}

@ -1,76 +0,0 @@
use crate::{
widgets::{NcMenuOptions, NcMenuSection},
NcChannels,
};
#[allow(unused_imports)]
use crate::widgets::NcMenu;
/// # `NcMenuOptions` constructors
impl NcMenuOptions {
/// New NcMenuOptions for [`NcMenu`].
///
/// `sections` must contain at least 1 [`NcMenuSection`].
pub fn new(sections: &mut [NcMenuSection]) -> Self {
Self::with_all_args(sections, 0, 0, 0)
}
/// New NcMenuOptions for [`NcMenu`], with all args.
///
/// `sections` must contain at least 1 [`NcMenuSection`].
pub fn with_all_args(
sections: &mut [NcMenuSection],
style_header: NcChannels,
style_sections: NcChannels,
flags: u64,
) -> Self {
assert![!sections.is_empty()];
Self {
// array of 'sectioncount' `MenuSection`s
sections: sections.as_mut_ptr(),
//
sectioncount: sections.len() as i32,
// styling for header
headerchannels: style_header,
// styling for sections
sectionchannels: style_sections,
// flag word of NCMENU_OPTION_*
flags,
}
}
}
/// # `NcMenuOptions` methods
impl NcMenuOptions {
/// Returns the styling for the header.
///
/// *(No equivalent C style function)*
pub const fn header_channels(&self) -> NcChannels {
self.headerchannels
}
/// Returns a mutable reference of the styling for the sections.
///
/// *(No equivalent C style function)*
pub fn header_channels_mut(&mut self) -> &mut NcChannels {
&mut self.headerchannels
}
/// Returns the styling for the sections.
///
/// *(No equivalent C style function)*
pub const fn section_channels(&self) -> NcChannels {
self.sectionchannels
}
/// Returns a mutable reference of the styling for the sections.
///
/// *(No equivalent C style function)*
pub fn section_channels_mut(&mut self) -> &mut NcChannels {
&mut self.sectionchannels
}
}

@ -1,58 +0,0 @@
//! `NcMenu` widget
// functions already exported by bindgen : 13
// ------------------------------------------
// (#) test: 0
// (W) wrap: 13
// ------------------------------------------
//W ncmenu_create
//W ncmenu_destroy
//W ncmenu_item_set_status
//W ncmenu_mouse_selected
//W ncmenu_nextitem
//W ncmenu_nextsection
//W ncmenu_offer_input
//W ncmenu_plane
//W ncmenu_previtem
//W ncmenu_prevsection
//W ncmenu_rollup
//W ncmenu_selected
//W ncmenu_unroll
mod methods;
/// menus on the top or bottom rows
///
/// A [Notcurses][crate::Notcurses] instance supports menu bars on the top or
/// bottom row of the true screen.
///
/// An NcMenu is composed of [NcMenuSection]s, which are in turn composed of
/// [NcMenuItem]s.
///
/// Either no sections are visible, and the menu is rolled up, or exactly one
/// section is unrolled.
///
/// - [rollup()][NcMenu#method.rollup]
/// places an `NcMenu` in the rolled up state.
/// - [unroll()][NcMenu#method.unroll]
/// rolls up any unrolled section and unrolls the specified one.
/// - [destroy()][NcMenu#method.destroy]
/// removes a menu bar, and frees all associated resources.
///
/// `type in C: ncmenu (struct)`
pub type NcMenu = crate::bindings::ffi::ncmenu;
/// Options struct for [`NcMenu`].
pub type NcMenuOptions = crate::bindings::ffi::ncmenu_options;
/// Item for [`NcMenu`].
pub type NcMenuItem = crate::bindings::ffi::ncmenu_item;
/// Section for [`NcMenu`].
pub type NcMenuSection = crate::bindings::ffi::ncmenu_section;
/// [NcMenuOptions] flag: Bottom row (as opposed to top row).
pub const NCMENU_OPTION_BOTTOM: u64 = crate::bindings::ffi::NCMENU_OPTION_BOTTOM as u64;
/// [NcMenuOptions] flag: Hide the menu when not unrolled
pub const NCMENU_OPTION_HIDING: u64 = crate::bindings::ffi::NCMENU_OPTION_HIDING as u64;

@ -1,19 +0,0 @@
//! All the notcurses widgets.
mod menu;
mod multiselector;
mod plot;
mod progbar;
mod reader;
mod reel;
mod selector;
mod tree;
pub use menu::*;
pub use multiselector::*;
pub use plot::*;
pub use progbar::*;
pub use reader::*;
pub use reel::*;
pub use selector::*;
pub use tree::*;

@ -1,10 +0,0 @@
//! `NcMultiSelector` widget.
/// high-level widget for selecting items from a set
pub type NcMultiSelector = crate::bindings::ffi::ncmultiselector;
/// an item for [`NcMultiSelector`]
pub type NcMultiSelectorItem = crate::bindings::ffi::ncmselector_item;
/// Options structure for [`NcMultiSelector`]
pub type NcMultiSelectorOptions = crate::bindings::ffi::ncmultiselector_options;

@ -1,27 +0,0 @@
//! `NcPlot[F|U]64` widget.
/// A histogram, bound to an [`NcPlane`][crate::NcPlane]
/// (uses non-negative `f64`s)
pub type NcPlotF64 = crate::bindings::ffi::ncdplot;
/// A histogram, bound to an [`NcPlane`][crate::NcPlane] (uses `u64`s)
pub type NcPlotU64 = crate::bindings::ffi::ncuplot;
/// Options struct for
/// [`NcPlotF64`] or [`NcPlotU64`]
pub type NcPlotOptions = crate::bindings::ffi::ncplot_options;
/// Use domain detection only for max
pub const NCPLOT_OPTION_DETECTMAXONLY: u32 = crate::bindings::ffi::NCPLOT_OPTION_DETECTMAXONLY;
/// Exponential dependent axis
pub const NCPLOT_OPTION_EXPONENTIALD: u32 = crate::bindings::ffi::NCPLOT_OPTION_EXPONENTIALD;
/// Show labels for dependent axis
pub const NCPLOT_OPTION_LABELTICKSD: u32 = crate::bindings::ffi::NCPLOT_OPTION_LABELTICKSD;
/// Use domain detection only for max
pub const NCPLOT_OPTION_NODEGRADE: u32 = crate::bindings::ffi::NCPLOT_OPTION_NODEGRADE;
/// Independent axis is vertical
pub const NCPLOT_OPTION_VERTICALI: u32 = crate::bindings::ffi::NCPLOT_OPTION_VERTICALI;

@ -1,68 +0,0 @@
//! `NcProgBar` & `NcProgBarOptions` methods and associated functions.
use super::{NcProgBar, NcProgBarOptions};
use crate::{error, NcPlane, NcResult};
/// # `NcProgBarOptions` Methods
impl NcProgBarOptions {
/// New NcProgBarOptions for [NcProgBar].
pub fn new() -> Self {
Self {
ulchannel: 0,
urchannel: 0,
blchannel: 0,
brchannel: 0,
flags: 0,
}
}
}
/// # `NcProgBar` Methods
impl NcProgBar {
/// New NcProgBar.
///
/// Takes ownership of the `plane`, which will be destroyed by
/// [destroy][NcProgBar#method.destroy](). The progress bar is initially at 0%.
pub fn new<'a>(plane: &mut NcPlane) -> &'a mut Self {
Self::with_options(plane, &NcProgBarOptions::new())
}
/// New NcProgBar. Expects an [NcProgBarOptions] struct.
///
/// *C style function: [ncprogbar_create()][crate::ncprogbar_create].*
pub fn with_options<'a>(plane: &mut NcPlane, options: &NcProgBarOptions) -> &'a mut Self {
unsafe { &mut *crate::ncprogbar_create(plane, options) }
}
/// Destroy the progress bar and its underlying ncplane.
///
/// *C style function: [ncprogbar_destroy()][crate::ncprogbar_destroy].*
pub fn destroy(&mut self) {
unsafe {
crate::ncprogbar_destroy(self);
}
}
/// Return a reference to the ncprogbar's underlying ncplane.
///
/// *C style function: [ncprogbar_plane()][crate::ncprogbar_plane].*
pub fn plane(&mut self) -> &mut NcPlane {
unsafe { &mut *crate::ncprogbar_plane(self) }
}
/// Get the progress bar's completion, an [f64] on [0, 1].
///
/// *C style function: [ncprogbar_progress()][crate::ncprogbar_progress].*
pub fn progress(&self) -> f64 {
unsafe { crate::ncprogbar_progress(self) }
}
/// Sets the progress bar's completion, an 0 <= [f64] <= 1.
///
/// Returns [NCRESULT_ERR][crate::NCRESULT_ERR] if progress is < 0 || > 1.
///
/// *C style function: [ncprogbar_set_progress()][crate::ncprogbar_set_progress].*
pub fn set_progress(&mut self, progress: f64) -> NcResult<()> {
error![unsafe { crate::ncprogbar_set_progress(self, progress) }]
}
}

@ -1,43 +0,0 @@
//! `NcProgbar` widget.
// functions already exported by bindgen : 5
// -----------------------------------------
// (#) test: 0
// (W) wrap: 5 / 0
// -----------------------------------------
//W ncprogbar_create,
//W ncprogbar_destroy,
//W ncprogbar_plane,
//W ncprogbar_progress,
//W ncprogbar_set_progress,
mod methods;
/// Progress bars. They proceed linearly in any of four directions.
///
/// The entirety of the plane will be used -- any border should be provided by
/// the caller on another plane.
///
/// The plane will not be erased; text preloaded into the plane will be consumed
/// by the progress indicator.
///
/// The bar is redrawn for each provided progress report (a double between 0
/// and 1), and can regress with lower values.
///
/// The procession will take place along the longer dimension at the time of each
/// redraw, with the horizontal length scaled by 2 for purposes of comparison.
/// I.e. for a plane of 20 rows and 50 columns, the progress will be to the
/// right (50 > 40), or left with [NCPROGBAR_OPTION_RETROGRADE].
///
/// `type in C: ncprogbar (struct)`
///
pub type NcProgBar = crate::bindings::ffi::ncprogbar;
/// Options struct for [`NcProgBar`]
///
/// `type in C: ncprogbar_options (struct)`
///
pub type NcProgBarOptions = crate::bindings::ffi::ncprogbar_options;
/// proceed left/down
pub const NCPROGBAR_OPTION_RETROGRADE: u32 = crate::bindings::ffi::NCPROGBAR_OPTION_RETROGRADE;

@ -1,35 +0,0 @@
//! `NcReader*` methods and associated functions.
use super::{NcReader, NcReaderOptions};
use crate::{error_ref_mut, ncreader_create, NcPlane, NcResult};
/// # `NcReaderOptions` Constructors
impl NcReaderOptions {
/// `NcReaderOptions` simple constructor
pub const fn new() -> Self {
Self {
// channels used for input
tchannels: 0,
// attributes used for input
tattrword: 0,
// bitfield of NCREADER_OPTION_*
flags: 0,
}
}
}
/// # `NcReader` Constructors
impl NcReader {
/// `NcReader` simple constructor
pub fn new<'a>(plane: &mut NcPlane) -> NcResult<&'a mut Self> {
Self::with_options(plane, NcReaderOptions::new())
}
/// `NcReader` constructor with options
pub fn with_options<'a>(
plane: &mut NcPlane,
options: NcReaderOptions,
) -> NcResult<&'a mut Self> {
error_ref_mut![unsafe { ncreader_create(plane, &options) }]
}
}

@ -1,48 +0,0 @@
//! `NcReader` widget.
// functions already exported by bindgen : 11
// ------------------------------------------
// ncreader_clear
// ncreader_contents
// ncreader_create
// ncreader_destroy
// ncreader_move_down
// ncreader_move_left
// ncreader_move_right
// ncreader_move_up
// ncreader_offer_input
// ncreader_plane
// ncreader_write_egc
mod methods;
/// Provides a freeform input in a (possibly multiline) region
///
/// Supports optional readline keybindings (opt out using
/// NCREADER_OPTION_NOCMDKEYS flag)
///
/// Takes ownership of its [`NcPlane`][crate::NcPlane], destroying it on any
/// error (`ncreader_destroy`() otherwise destroys the ncplane).
///
/// `type in C: ncreader (struct)`
///
pub type NcReader = crate::bindings::ffi::ncreader;
/// Options struct for [`NcReader`]
///
/// `type in C: ncreader_options (struct)`
///
pub type NcReaderOptions = crate::bindings::ffi::ncreader_options;
/// Make the terminal cursor visible across the lifetime of the ncreader, and
/// have the ncreader manage the cursor's placement.
pub const NCREADER_OPTION_CURSOR: u32 = crate::bindings::ffi::NCREADER_OPTION_CURSOR;
/// Enable horizontal scrolling. Virtual lines can then grow arbitrarily long.
pub const NCREADER_OPTION_HORSCROLL: u32 = crate::bindings::ffi::NCREADER_OPTION_HORSCROLL;
/// Disable all editing shortcuts. By default, emacs-style keys are available.
pub const NCREADER_OPTION_NOCMDKEYS: u32 = crate::bindings::ffi::NCREADER_OPTION_NOCMDKEYS;
/// Enable vertical scrolling. You can then use arbitrarily many virtual lines.
pub const NCREADER_OPTION_VERSCROLL: u32 = crate::bindings::ffi::NCREADER_OPTION_VERSCROLL;

@ -1,32 +0,0 @@
//! `NcReel` widget.
/// A wheel with [`NcTablet`]s on the outside.
///
/// An `NcReel` is projected onto the 2d rendering area, showing some portion of
/// the `NcReel`, and zero or more `NcTablet`s.
///
/// An `NcReel` is a [`Notcurses`][crate::Notcurses] region devoted to
/// displaying zero or more line-oriented, contained [`NcTablet`]s
/// between which the user may navigate.
///
/// If at least one `NcTablet`s exists, there is a "focused tablet".
/// As much of the focused tablet as is possible is always displayed.
///
/// If there is space left over, other tablets are included in the display.
/// Tablets can come and go at any time, and can grow or shrink at any time.
pub type NcReel = crate::bindings::ffi::ncreel;
/// Options struct for [`NcReel`]
pub type NcReelOptions = crate::bindings::ffi::ncreel_options;
/// Visual tablet for [`NcReel`]
pub type NcTablet = crate::bindings::ffi::nctablet;
/// is navigation circular (does moving down from the last tablet move to the
/// first, and vice versa)? only meaningful when infinitescroll is true. if
/// infinitescroll is false, this must be false.
pub const NCREEL_OPTION_CIRCULAR: u32 = crate::bindings::ffi::NCREEL_OPTION_CIRCULAR;
/// is scrolling infinite (can one move down or up forever, or is an end
/// reached?). if true, 'circular' specifies how to handle the special case of
/// an incompletely-filled reel.
pub const NCREEL_OPTION_INFINITESCROLL: u32 = crate::bindings::ffi::NCREEL_OPTION_INFINITESCROLL;

@ -1,10 +0,0 @@
//! `NcSelector` widget.
/// high-level widget for selecting one item from a set
pub type NcSelector = crate::bindings::ffi::ncselector;
/// an item for [`NcSelector`]
pub type NcSelectorItem = crate::bindings::ffi::ncselector_item;
/// Options structur for [`NcSelector`]
pub type NcSelectorOptions = crate::bindings::ffi::ncselector_options;

@ -1,32 +0,0 @@
//! `NcTree*` methods and associated functions.
mod options;
mod tree;
pub use options::*;
pub use tree::*;
use core::ptr::null_mut;
use std::ffi::{c_void, CString};
use super::NcTreeItem;
/// # `NcTreeItem` constructor
impl NcTreeItem {
/// Creates an [NcTreeItem].
pub fn new(curry: &str, subs: Option<&mut [NcTreeItem]>, subcount: usize) -> Self {
if let Some(subs) = subs {
Self {
curry: CString::new(curry).unwrap().into_raw() as *mut _ as *mut c_void,
subs: subs.as_mut_ptr(),
subcount: subcount as u32,
}
} else {
Self {
curry: CString::new(curry).unwrap().into_raw() as *mut _ as *mut c_void,
subs: null_mut(),
subcount: subcount as u32,
}
}
}
}

@ -1,42 +0,0 @@
use crate::{
widgets::{NcTreeItem, NcTreeItemCbUnsafe, NcTreeOptions},
NcDim,
};
#[allow(unused_imports)]
use crate::widgets::NcTree;
/// # `NcTreeOptions` constructors
impl NcTreeOptions {
/// New NcTreeOptions for [`NcTree`].
pub fn new(items: &[NcTreeItem], indentcols: NcDim) -> Self {
Self::with_all_args(items, items.len(), None, indentcols, 0)
}
/// New NcTreeOptions for [`NcTree`], with all args.
pub fn with_all_args(
// top-level nctree_item array
items: &[NcTreeItem],
// size of |items|
count: usize,
// item callback function
// TODO: use NcTreeItemCb and convert to NcTreeItemCbUnsafe
nctreecb: Option<NcTreeItemCbUnsafe>,
// columns to indent per level of hierarchy
indentcols: NcDim,
// bitfield of `NCTREE_OPTION_*` (there's none for now)
flags: u64,
) -> Self {
Self {
items: items as *const _ as *const NcTreeItem,
count: count as u32,
nctreecb,
indentcols: indentcols as i32,
flags,
}
}
}

@ -1,122 +0,0 @@
use crate::{
error, error_ref_mut, nctree_create,
widgets::{NcTree, NcTreeItem, NcTreeOptions},
NcError, NcInput, NcPlane, NcResult, NCRESULT_ERR,
};
/// # `NcTree` constructors & destructors
impl NcTree {
/// Creates an [NcTree] with the specified options.
///
/// *C style function: [nctree_create()][crate::nctree_create].*
pub fn new<'a>(plane: &mut NcPlane, options: NcTreeOptions) -> NcResult<&'a mut Self> {
error_ref_mut![unsafe { nctree_create(plane, &options) }, "Creating NcTree"]
}
/// Destroys an NcTree created with [new()][NcTree#method.new].
///
/// *C style function: [nctree_destroy()][crate::nctree_destroy].*
pub fn destroy(&mut self) {
unsafe { crate::nctree_destroy(self) };
}
}
/// # `NcTree` methods
impl NcTree {
// NOTE: not implemented yet in C API
//
// /// Goes to the item specified by the array |spec|, terminated by UINT_MAX.
// ///
// /// If the spec is invalid, returns an error and the depth of the first
// /// invalid spec is written to *|failspec|.
// ///
// /// Otherwise, the true depth is written to *|failspec|,
// /// and the curry is returned (|failspec| is necessary because the
// /// curry could itself be NULL).
// ///
// /// *C style function: [nctree_goto()][crate::nctree_goto].*
// pub fn goto(&mut self, spec: ... , failspec: ...) -> NcResult<&mut NcTreeItem> {
// let res = unsafe { crate::nctree_goto(self) };
// if !res.is_null() {
// Ok(unsafe { &mut *(res as *mut NcTreeItem) })
// } else {
// Err(NcError::with_msg(NCRESULT_ERR, "NcTree.goto()"))
// }
// }
/// Returns the focused item, if any items are present.
///
/// This is not a copy; be careful to use it only for the duration of a
/// critical section.
///
/// *C style function: [nctree_focused()][crate::nctree_focused].*
pub fn focused(&mut self) -> NcResult<&mut NcTreeItem> {
let res = unsafe { crate::nctree_focused(self) };
if !res.is_null() {
Ok(unsafe { &mut *(res as *mut NcTreeItem) })
} else {
Err(NcError::with_msg(NCRESULT_ERR, "NcTree.focused()"))
}
}
/// Changes the focus to the next item, and returns it.
///
/// *C style function: [nctree_next()][crate::nctree_next].*
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> NcResult<&mut NcTreeItem> {
let res = unsafe { crate::nctree_next(self) };
if !res.is_null() {
Ok(unsafe { &mut *(res as *mut NcTreeItem) })
} else {
Err(NcError::with_msg(NCRESULT_ERR, "NcTree.next()"))
}
}
/// Changes the focus to the previous item, and returns it.
///
/// *C style function: [nctree_prev()][crate::nctree_prev].*
pub fn prev(&mut self) -> NcResult<&mut NcTreeItem> {
let res = unsafe { crate::nctree_prev(self) };
if !res.is_null() {
Ok(unsafe { &mut *(res as *mut NcTreeItem) })
} else {
Err(NcError::with_msg(NCRESULT_ERR, "NcTree.prev()"))
}
}
/// Offers the `input` to this NcTree.
///
/// If it's relevant, this function returns true,
/// and the input ought not be processed further.
/// If it's irrelevant to the tree, false is returned.
///
/// Relevant inputs include:
///
/// - a mouse click on an item (focuses item)
/// - a mouse scrollwheel event (srolls tree)
/// - up, down, pgup, or pgdown (navigates among items)
///
/// *C style function: [nctree_offer_input()][crate::nctree_offer_input].*
pub fn offer_input(&mut self, input: NcInput) -> bool {
unsafe { crate::nctree_offer_input(self, &input) }
}
/// Returns the [NcPlane] backing this NcTree.
///
/// *C style function: [nctree_plane()][crate::nctree_plane].*
pub fn plane(&mut self) -> NcResult<&NcPlane> {
error_ref_mut![unsafe { crate::nctree_plane(self) }, "NcTree.plane()"]
}
/// Redraws the NcTree in its entirety.
///
/// The tree will be cleared, and items will be laid out, using the focused
/// item as a fulcrum.
///
/// Item-drawing callbacks will be invoked for each visible item.
///
/// *C style function: [nctree_redraw()][crate::nctree_redraw].*
pub fn redraw(&mut self) -> NcResult<()> {
error![unsafe { crate::nctree_redraw(self) }, "NcTree.redraw()"]
}
}

@ -1,89 +0,0 @@
//! `NcTree` widget
// functions already exported by bindgen : 13
// ------------------------------------------
// (#) test: 0
// (W) wrap: 13
// ------------------------------------------
//W nctree_create,
//W nctree_destroy,
//W nctree_focused,
//~ nctree_goto,
//W nctree_next,
//W nctree_offer_input,
//W nctree_plane,
//W nctree_prev,
//W nctree_redraw,
use cty::c_int;
use std::ffi::c_void;
use crate::NcPlane;
mod methods;
/// High-level hierarchical line-based data.
///
/// `NcTree`s organize static hierarchical items, and allow them to be browsed.
///
/// An NcTree cannot be empty, count must be non-zero.
///
/// - Each item can have arbitrary subitems.
/// - Items can be collapsed and expanded.
/// - The display supports scrolling and searching.
/// - Items cannot be added or removed, however; they must be provided in their
/// entirety at creation time.
///
/// NOTE: `NcTree` shares many properties with `NcReel`. Unlike the latter,
/// `NcTree`s support arbitrary hierarchical levels, but they do not allow
/// elements to come and go across the lifetime of the widget.
///
/// `type in C: nctree (struct)`
pub type NcTree = crate::bindings::ffi::nctree;
/// Item for [`NcTree`].
///
/// each item has a curry, and zero or more subitems.
pub type NcTreeItem = crate::bindings::ffi::nctree_item;
/// Options struct for [`NcTree`].
pub type NcTreeOptions = crate::bindings::ffi::nctree_options;
// e.g.:
//
// ```c
// int treecb(struct ncplane* n, void* curry, int pos){
// ncplane_printf_yx(n, 0, 0, "item: %s pos: %d",
// static_cast<const char*>(curry), pos);
// return 0;
// }
// ```
/// An [NcTreeItem] callback function (unsafe).
pub type NcTreeItemCbUnsafe = unsafe extern "C" fn(*mut NcPlane, *mut c_void, c_int) -> c_int;
/// An [NcTreeItem] callback function.
pub type NcTreeItemCb = fn(&mut NcPlane, &str, i32);
// WIP TODO: create callback type and conversion functions
//
// /// Converts [NcTreeItemCbUnsafe] to [NcTreeItemCb].
// pub fn nctreeitemcb_to_rust(resizecb: Option<NcTreeItemCbUnsafe>) -> Option<NcTreeItemCb> {
// if let Some(cb) = resizecb {
// return Some(unsafe { core::mem::transmute(cb) });
// } else {
// None
// }
// }
//
// /// Converts [NcTreeItemCb] to [NcTreeItemCbUnsafe].
// ///
// // waiting for https://github.com/rust-lang/rust/issues/53605
// // to make this function const, and then NcPlaneOptions constructors.
// pub fn nctreeitemcb_to_c(resizecb: Option<NcTreeItemCb>) -> Option<NcTreeItemCbUnsafe> {
// if let Some(cb) = resizecb {
// return Some(unsafe { core::mem::transmute(cb) });
// } else {
// None
// }
// }

@ -1,11 +0,0 @@
#!/usr/bin/env bash
#
# handy script that shows the last changes made by Nick in the rust bindings
RUST_DIR="$(git rev-parse --show-toplevel)/rust"
# …in /src & /examples
for file in $(find "$RUST_DIR/src/" "$RUST_DIR/examples" -name '*.rs'); do
git blame -fn $file 2>&1 | grep "(nick black" | grep -v "no such path";
done

@ -1,41 +0,0 @@
PENDING changes
## from changes-20210321-20210406.txt
- all tabbed & tab widget functions
## from changes-20210406-20210410.txt
missing methods:
- [ ] ncdirect_stream
## from changes-20120518-20210603.txt
missing methods:
- [ ] nccell_width
- [ ] ncdirect_styles (method)
- [ ] ncdirect_supported_styles (method)
- [ ] ncplane_erase_region
- [ ] notcurses_cursor_yx
## from changes-20210603-20210704.txt …
missing imports & methods:
- [ ] ncpile_render_to_buffer
- [ ] ncpile_render_to_file
- [ ] nccells_ascii_box
- [ ] nccells_heavy_box
- [ ] nccells_light_box
## from changes-20210731-20210826.txt
- [ ] notcurses_hostname
- [ ] notcurses_accountname
- [ ] notcurses_enter_alternate_screen
- [ ] notcurses_leave_alternate_screen
- [ ] notcurses_get
- [ ] ncdirect_get
- [ ] ncvisual_subtitle_plane
- [ ] ncvisual_from_palidx
- [ ] ncplane_scrollup
- [ ] ncplane_scrollup_child
- [ ] ncplane_cursor_move_rel
- [ ] ncplane_boundlist /// Gets the head of the list of planes bound to 'n'.

@ -1,65 +0,0 @@
#/usr/bin/env bash
#
# compares the changes betwee two output folders
PATH1=$1
PATH2=$2
if [[ -z $PATH1 ]]; then
echo "It's necessary to provide two paths to compare. 0 paths provided"
exit 1
fi
if [[ ! -d $PATH1 ]]; then
echo "The first path doesn't exist."
exit 1
fi
if [[ -z $PATH2 ]]; then
echo "It's necessary to provide two paths to compare. Only 1 path provided."
exit 1
fi
if [[ ! -d $PATH2 ]]; then
echo "The second path doesn't exist."
exit 1
fi
# this line is to activate diff syntax highlighting
echo -e "0d0\n"
echo -e "Differences between files:\n=========================="
#DIFFLIST=$(diff -qr "$PATH1" "$PATH2" | grep ^Files | cut -d' ' -f 2,4)
DIFFLIST=$(diff -qr "$PATH1" "$PATH2" | grep ^Files | cut -d' ' -f 2,4 | grep -v STATS)
echo "$DIFFLIST"
echo -e "\nbroken down:\n============"
OLDIFS=$IFS
IFS=$'\n'
for d in $DIFFLIST; do
d1=$(echo $d | cut -d' ' -f1)
d2=$(echo $d | cut -d' ' -f2)
echo -e "\ndiff $d1 $d2:"
diff $d1 $d2
done
echo -e "\nOnly in one path:\n================="
UNIQUELIST=$(diff -qr "$PATH1" "$PATH2" | grep ^Only)
echo "$UNIQUELIST"
echo -e "\ndisplay contents:\n================="
for u in $UNIQUELIST; do
u1=$(echo $u | cut -d' ' -f3| tr ':' '/' )
u2=$(echo $u | cut -d' ' -f4)
path="${u1}${u2}"
echo -e "\ncat $path:\n-------------------"
cat $path
done
IFS=$OLDIFS

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save