From 01e4f7de5af09937b1cdf6ebb2e0135cd9e0f8e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?joseLu=C3=ADs?= Date: Fri, 4 Dec 2020 02:25:49 +0100 Subject: [PATCH] rust: big refactor - move tests to their own submodules - move functions reimplementations to reimplemented submodule. - remove types submodules and move them to their parent. - add more NcPlane & Notcurses methods - rename NcChar back to NcEgc, and NcCharBackstop tp NcEgcBackstop - add ncpile_top & ncpile_bottom functions. - fix Notcurses stdplane(_mut) methods - make cell_load_char not return anything since it was always 1. --- rust/src/bindings.rs | 2 + rust/src/cells/methods.rs | 87 ++ rust/src/cells/mod.rs | 866 ++++++-------- rust/src/cells/reimplemented.rs | 434 +++++++ rust/src/cells/test/methods.rs | 15 + rust/src/cells/test/mod.rs | 7 + .../cells/{tests.rs => test/reimplemented.rs} | 14 +- rust/src/cells/types.rs | 327 ----- rust/src/cells/wrapped.rs | 47 - rust/src/channel/mod.rs | 558 ++++----- rust/src/channel/reimplemented.rs | 309 +++++ rust/src/channel/test/methods.rs | 10 + rust/src/channel/test/mod.rs | 7 + .../{tests.rs => test/reimplemented.rs} | 6 +- rust/src/channel/types.rs | 211 ---- rust/src/direct/{wrapped.rs => methods.rs} | 8 +- rust/src/direct/mod.rs | 115 +- rust/src/direct/{tests.rs => test/mod.rs} | 0 rust/src/direct/types.rs | 25 - rust/src/input.rs | 14 +- rust/src/key.rs | 21 +- rust/src/lib.rs | 1 - rust/src/macros.rs | 4 +- rust/src/notcurses/{wrapped.rs => methods.rs} | 32 +- rust/src/notcurses/mod.rs | 314 ++--- rust/src/notcurses/reimplemented.rs | 100 ++ rust/src/notcurses/test/methods.rs | 4 + rust/src/notcurses/test/mod.rs | 7 + .../{tests.rs => test/reimplemented.rs} | 2 +- rust/src/notcurses/types.rs | 110 -- rust/src/palette/mod.rs | 42 + .../{palette.rs => palette/reimplemented.rs} | 31 +- rust/src/pixel.rs | 66 +- rust/src/plane/{wrapped.rs => methods.rs} | 21 +- rust/src/plane/mod.rs | 1051 +++++------------ rust/src/plane/reimplemented.rs | 644 ++++++++++ rust/src/plane/test/methods.rs | 4 + rust/src/plane/test/mod.rs | 7 + .../plane/{tests.rs => test/reimplemented.rs} | 24 +- rust/src/plane/types.rs | 156 --- rust/src/visual.rs | 56 +- rust/src/widgets/menu/methods.rs | 85 ++ rust/src/widgets/menu/mod.rs | 144 +-- rust/src/widgets/menu/types.rs | 32 - rust/src/widgets/mod.rs | 1 - rust/src/widgets/multiselector/mod.rs | 12 +- rust/src/widgets/multiselector/types.rs | 10 - rust/src/widgets/plot/mod.rs | 35 +- rust/src/widgets/plot/types.rs | 27 - rust/src/widgets/reader/methods.rs | 29 + rust/src/widgets/reader/mod.rs | 95 +- rust/src/widgets/reader/types.rs | 32 - rust/src/widgets/reel/mod.rs | 36 +- rust/src/widgets/reel/types.rs | 30 - rust/src/widgets/selector/mod.rs | 13 +- rust/src/widgets/selector/types.rs | 10 - 56 files changed, 3197 insertions(+), 3153 deletions(-) create mode 100644 rust/src/cells/methods.rs create mode 100644 rust/src/cells/reimplemented.rs create mode 100644 rust/src/cells/test/methods.rs create mode 100644 rust/src/cells/test/mod.rs rename rust/src/cells/{tests.rs => test/reimplemented.rs} (95%) delete mode 100644 rust/src/cells/types.rs delete mode 100644 rust/src/cells/wrapped.rs create mode 100644 rust/src/channel/reimplemented.rs create mode 100644 rust/src/channel/test/methods.rs create mode 100644 rust/src/channel/test/mod.rs rename rust/src/channel/{tests.rs => test/reimplemented.rs} (98%) delete mode 100644 rust/src/channel/types.rs rename rust/src/direct/{wrapped.rs => methods.rs} (83%) rename rust/src/direct/{tests.rs => test/mod.rs} (100%) delete mode 100644 rust/src/direct/types.rs rename rust/src/notcurses/{wrapped.rs => methods.rs} (80%) create mode 100644 rust/src/notcurses/reimplemented.rs create mode 100644 rust/src/notcurses/test/methods.rs create mode 100644 rust/src/notcurses/test/mod.rs rename rust/src/notcurses/{tests.rs => test/reimplemented.rs} (98%) delete mode 100644 rust/src/notcurses/types.rs create mode 100644 rust/src/palette/mod.rs rename rust/src/{palette.rs => palette/reimplemented.rs} (55%) rename rust/src/plane/{wrapped.rs => methods.rs} (87%) create mode 100644 rust/src/plane/reimplemented.rs create mode 100644 rust/src/plane/test/methods.rs create mode 100644 rust/src/plane/test/mod.rs rename rust/src/plane/{tests.rs => test/reimplemented.rs} (93%) delete mode 100644 rust/src/plane/types.rs create mode 100644 rust/src/widgets/menu/methods.rs delete mode 100644 rust/src/widgets/menu/types.rs delete mode 100644 rust/src/widgets/multiselector/types.rs delete mode 100644 rust/src/widgets/plot/types.rs create mode 100644 rust/src/widgets/reader/methods.rs delete mode 100644 rust/src/widgets/reader/types.rs delete mode 100644 rust/src/widgets/reel/types.rs delete mode 100644 rust/src/widgets/selector/types.rs diff --git a/rust/src/bindings.rs b/rust/src/bindings.rs index 5b29e4b0b..fcdb241e8 100644 --- a/rust/src/bindings.rs +++ b/rust/src/bindings.rs @@ -304,9 +304,11 @@ pub use bindgen::{ #[doc(inline)] pub use bindgen::{ // functions + ncpile_bottom, ncpile_create, ncpile_rasterize, ncpile_render, + ncpile_top, }; // ncplane --------------------------------------------------------------------- diff --git a/rust/src/cells/methods.rs b/rust/src/cells/methods.rs new file mode 100644 index 000000000..b1cedfda7 --- /dev/null +++ b/rust/src/cells/methods.rs @@ -0,0 +1,87 @@ +//! `NcCell` methods and associated functions. + +pub use crate::{ + cell_load, cstring, NcCell, NcChannelPair, NcEgcBackstop, NcPlane, NcStyleMask, NCRESULT_ERR, +}; + +use crate::{cell_extract, NcEgc}; + +/// # `NcCell` Constructors +impl NcCell { + /// New NcCell, expects a [char], [NcStyleMask] and [NcChannelPair]. + #[inline] + pub const fn with_all(ch: char, stylemask: NcStyleMask, channels: NcChannelPair) -> Self { + NcCell { + gcluster: ch as u32, + gcluster_backstop: 0 as NcEgcBackstop, + reserved: 0, + stylemask, + channels, + } + } + + /// New NcCell, expects a 7-bit [char]. + #[inline] + pub const fn with_7bitchar(ch: char) -> Self { + Self::with_all(ch, 0 as NcStyleMask, 0 as NcChannelPair) + } + + /// New NcCell, expects an [NcPlane] and a utf-8 [char]. + #[inline] + pub fn with_char(plane: &mut NcPlane, ch: char) -> Self { + let mut cell = Self::new(); + let result = unsafe { cell_load(plane, &mut cell, cstring![ch.to_string()]) }; + debug_assert_ne![NCRESULT_ERR, result]; + cell + } + + /// New NcCell, expects an [NcPlane] and a &[str]. + #[inline] + pub fn with_str(plane: &mut NcPlane, string: &str) -> Self { + let mut cell = Self::new(); + let result = unsafe { cell_load(plane, &mut cell, cstring![string]) }; + debug_assert_ne![NCRESULT_ERR, result]; + cell + } + + /// New NcCell, blank. + #[inline] + pub const fn new() -> Self { + Self::with_7bitchar(0 as char) + } +} + +/// # `NcCell` Methods +impl NcCell { + /// Saves the [NcStyleMask] and the [NcChannelPair], and returns the [NcEgc] + /// (the three elements of an NcCell). + pub fn extract( + &mut self, + plane: &mut NcPlane, + styles: &mut NcStyleMask, + channels: &mut NcChannelPair, + ) -> NcEgc { + cell_extract(plane, self, styles, channels) + } + + /// Saves the [NcChannelPair] of the NcCell. + // not in the C API + pub fn channels(&mut self, plane: &mut NcPlane, channels: &mut NcChannelPair) { + let mut _styles = 0; + let _char = cell_extract(plane, self, &mut _styles, channels); + } + + /// Saves the [NcStyleMask] of the NcCell. + // not in the C API + pub fn styles(&mut self, plane: &mut NcPlane, styles: &mut NcStyleMask) { + let mut _channels = 0; + let _char = cell_extract(plane, self, styles, &mut _channels); + } + + /// Returns the [NcEgc] of the NcCell. + // not in the C API + pub fn egc(&mut self, plane: &mut NcPlane) -> NcEgc { + let (mut _styles, mut _channels) = (0, 0); + cell_extract(plane, self, &mut _styles, &mut _channels) + } +} diff --git a/rust/src/cells/mod.rs b/rust/src/cells/mod.rs index 6de28453f..0c86267ec 100644 --- a/rust/src/cells/mod.rs +++ b/rust/src/cells/mod.rs @@ -1,4 +1,4 @@ -//! [NcCell] `cell*_*` static functions reimplementations +//! `NcCell` // functions already exported by bindgen : 6 // ----------------------------------------- @@ -9,498 +9,384 @@ // cells_double_box // cells_rounded_box // -// static inline functions total: 42 -// ------------------------------------------ (implement / remaining) +// functions manually reimplemented: 42 +// ------------------------------------------ // (X) wont: 2 // (+) done: 40 / 0 +// (W) wrap: 1 / 39 // (#) test: 26 / 14 // ------------------------------------------ -//# cell_bchannel -//# cell_bg_alpha -//# cell_bg_default_p -//# cell_bg_palindex -//# cell_bg_palindex_p -//# cell_bg_rgb -//# cell_bg_rgb8 -//+ cellcmp -//+ cell_double_wide_p -//+ cell_extract -//# cell_fchannel -//# cell_fg_alpha -//# cell_fg_default_p -//# cell_fg_palindex -//# cell_fg_palindex_p -//# cell_fg_rgb -//# cell_fg_rgb8 -//+ cell_init -//+ cell_load_char -//+ cell_prime -//# cell_set_bchannel -//# cell_set_bg_alpha -//# cell_set_bg_default -//# cell_set_bg_palindex -//# cell_set_bg_rgb -//# cell_set_bg_rgb8 -//X cell_set_bg_rgb8_clipped // unneeded -//# cell_set_fchannel -//# cell_set_fg_alpha -//# cell_set_fg_default -//# cell_set_fg_palindex -//# cell_set_fg_rgb -//# cell_set_fg_rgb8 -//X cell_set_fg_rgb8_clipped // unneeded -//+ cells_load_box -//+ cell_strdup -//+ cell_styles -//+ cell_styles_off -//+ cell_styles_on -//+ cell_styles_set -//+ cell_wide_left_p -//+ cell_wide_right_p +// # cell_bchannel +// # cell_bg_alpha +// # cell_bg_default_p +// # cell_bg_palindex +// # cell_bg_palindex_p +// # cell_bg_rgb +// # cell_bg_rgb8 +// + cellcmp +// + cell_double_wide_p +//W+ cell_extract +// # cell_fchannel +// # cell_fg_alpha +// # cell_fg_default_p +// # cell_fg_palindex +// # cell_fg_palindex_p +// # cell_fg_rgb +// # cell_fg_rgb8 +// + cell_init +// + cell_load_char +// + cell_prime +// # cell_set_bchannel +// # cell_set_bg_alpha +// # cell_set_bg_default +// # cell_set_bg_palindex +// # cell_set_bg_rgb +// # cell_set_bg_rgb8 +// X cell_set_bg_rgb8_clipped // unneeded +// # cell_set_fchannel +// # cell_set_fg_alpha +// # cell_set_fg_default +// # cell_set_fg_palindex +// # cell_set_fg_rgb +// # cell_set_fg_rgb8 +// X cell_set_fg_rgb8_clipped // unneeded +// + cells_load_box +// + cell_strdup +// + cell_styles +// + cell_styles_off +// + cell_styles_on +// + cell_styles_set +// + cell_wide_left_p +// + cell_wide_right_p #[cfg(test)] -mod tests; - -mod types; -pub use types::{ - NcCell, NcChar, NcCharBackstop, NcStyleMask, NCCELL_ALPHA_BLEND, NCCELL_ALPHA_HIGHCONTRAST, - NCCELL_ALPHA_OPAQUE, NCCELL_ALPHA_TRANSPARENT, NCCELL_BGDEFAULT_MASK, NCCELL_BG_ALPHA_MASK, - NCCELL_BG_PALETTE, NCCELL_BG_RGB_MASK, NCCELL_FGDEFAULT_MASK, NCCELL_FG_ALPHA_MASK, - NCCELL_FG_PALETTE, NCCELL_FG_RGB_MASK, NCCELL_NOBACKGROUND_MASK, NCCELL_WIDEASIAN_MASK, - NCSTYLE_BLINK, NCSTYLE_BOLD, NCSTYLE_DIM, NCSTYLE_INVIS, NCSTYLE_ITALIC, NCSTYLE_MASK, - NCSTYLE_NONE, NCSTYLE_PROTECT, NCSTYLE_REVERSE, NCSTYLE_STANDOUT, NCSTYLE_STRUCK, - NCSTYLE_UNDERLINE, -}; - -mod wrapped; -pub use wrapped::*; - -use libc::strcmp; - -use crate::{ - cell_extended_gcluster, cell_load, cell_release, channels_bchannel, channels_bg_alpha, - channels_bg_default_p, channels_bg_palindex_p, channels_bg_rgb, channels_bg_rgb8, - channels_fchannel, channels_fg_alpha, channels_fg_default_p, channels_fg_palindex_p, - channels_fg_rgb, channels_fg_rgb8, channels_set_bchannel, channels_set_bg_alpha, - channels_set_bg_default, channels_set_bg_rgb, channels_set_bg_rgb8, channels_set_fchannel, - channels_set_fg_alpha, channels_set_fg_default, channels_set_fg_rgb, channels_set_fg_rgb8, - NcAlphaBits, NcChannel, NcChannelPair, NcColor, NcPaletteIndex, NcPlane, NcResult, NcRgb, - NCRESULT_ERR, NCRESULT_OK, -}; - -/// Same as [cell_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'. -/// -#[allow(unused_unsafe)] -pub unsafe fn cell_prime( - plane: &mut NcPlane, - cell: &mut NcCell, - gcluster: NcChar, - style: NcStyleMask, - channels: NcChannelPair, -) -> NcResult { - cell.stylemask = style; - cell.channels = channels; - unsafe { cell_load(plane, cell, gcluster as u32 as *const i8) } -} - -/// Loads up six cells with the [NcChar]s necessary to draw a box. -/// -/// Returns [NCRESULT_OK] on success, [NCRESULT_ERR] on error. -/// -/// On error, any [NcCell]s this function might have loaded before the error -/// are [cell_release]d. There must be at least six [NcChar]s in gcluster. -/// -#[allow(unused_unsafe)] -pub unsafe fn cells_load_box( - plane: &mut NcPlane, - style: NcStyleMask, - channels: NcChannelPair, - ul: &mut NcCell, - ur: &mut NcCell, - ll: &mut NcCell, - lr: &mut NcCell, - hl: &mut NcCell, - vl: &mut NcCell, - gcluster: NcChar, -) -> NcResult { - // mutable copy for pointer arithmetics: - let mut gclu = gcluster as u32 as *const i8; - let mut ulen: NcResult; - - ulen = unsafe { cell_prime(plane, ul, gcluster, style, channels) }; - - if ulen > 0 { - gclu = unsafe { gclu.offset(ulen as isize) }; - ulen = unsafe { cell_prime(plane, ur, gcluster, style, channels) }; - - if ulen > 0 { - gclu = unsafe { gclu.offset(ulen as isize) }; - ulen = unsafe { cell_prime(plane, ll, gcluster, style, channels) }; - - if ulen > 0 { - gclu = unsafe { gclu.offset(ulen as isize) }; - ulen = unsafe { cell_prime(plane, lr, gcluster, style, channels) }; - - if ulen > 0 { - gclu = unsafe { gclu.offset(ulen as isize) }; - ulen = unsafe { cell_prime(plane, hl, gcluster, style, channels) }; - - if ulen > 0 { - let _gclu = unsafe { gclu.offset(ulen as isize) }; - ulen = unsafe { cell_prime(plane, vl, gcluster, style, channels) }; - - if ulen > 0 { - return NCRESULT_OK; - } - unsafe { - cell_release(plane, hl); - } - } - unsafe { - cell_release(plane, lr); - } - } - unsafe { - cell_release(plane, ll); - } - } - unsafe { - cell_release(plane, ur); - } - } - unsafe { - cell_release(plane, ul); - } - } - NCRESULT_ERR -} - -/// Initializes (zeroes out) an [NcCell]. -#[inline] -pub fn cell_init(cell: &mut NcCell) { - *cell = unsafe { core::mem::zeroed() } -} - -/// Sets *just* the specified [NcStyleMask] bits for an [NcCell], -/// whether they're actively supported or not. -#[inline] -pub fn cell_styles_set(cell: &mut NcCell, stylebits: NcStyleMask) { - cell.stylemask = stylebits & NCSTYLE_MASK as u16; -} - -/// Extracts the [NcStyleMask] bits from an [NcCell]. -#[inline] -pub fn cell_styles(cell: &NcCell) -> NcStyleMask { - cell.stylemask -} - -/// Adds the specified [NcStyleMask] bits to an [NcCell]'s existing spec., -/// whether they're actively supported or not. -#[inline] -pub fn cell_styles_on(cell: &mut NcCell, stylebits: NcStyleMask) { - cell.stylemask |= stylebits & NCSTYLE_MASK as u16; -} - -/// Removes the specified [NcStyleMask] bits from an [NcCell]'s existing spec. -#[inline] -pub fn cell_styles_off(cell: &mut NcCell, stylebits: NcStyleMask) { - cell.stylemask &= !(stylebits & NCSTYLE_MASK as u16); -} - -/// Indicates to use the "default color" for the **foreground** [NcChannel] -/// of an [NcCell]. -#[inline] -pub fn cell_set_fg_default(cell: &mut NcCell) { - channels_set_fg_default(&mut cell.channels); -} - -/// Indicates to use the "default color" for the **background** [NcChannel] -/// of an [NcCell]. -#[inline] -pub fn cell_set_bg_default(cell: &mut NcCell) { - channels_set_bg_default(&mut cell.channels); -} - -/// Sets the foreground [NcAlphaBits] of an [NcCell]. -#[inline] -pub fn cell_set_fg_alpha(cell: &mut NcCell, alpha: NcAlphaBits) { - channels_set_fg_alpha(&mut cell.channels, alpha); -} - -/// Sets the background [NcAlphaBits] of an [NcCell]. -#[inline] -pub fn cell_set_bg_alpha(cell: &mut NcCell, alpha: NcAlphaBits) { - channels_set_bg_alpha(&mut cell.channels, alpha); -} - -/// Does the [NcCell] contain an East Asian Wide codepoint? -// NOTE: remove casting when fixed: -// https://github.com/rust-lang/rust-bindgen/issues/1875 -#[inline] -pub fn cell_double_wide_p(cell: &NcCell) -> bool { - (cell.channels & NCCELL_WIDEASIAN_MASK as NcChannelPair) != 0 -} - -/// Is this the right half of a wide character? -#[inline] -pub fn cell_wide_right_p(cell: &NcCell) -> bool { - cell_double_wide_p(cell) && cell.gcluster == 0 -} - -/// Is this the left half of a wide character? -#[inline] -pub fn cell_wide_left_p(cell: &NcCell) -> bool { - cell_double_wide_p(cell) && cell.gcluster != 0 -} - -/// Copies the UTF8-encoded [NcChar] out of the cell, whether simple -/// or complex. -/// -/// The result is not tied to the [NcPlane], and persists -/// across erases and destruction. -#[inline] -pub fn cell_strdup(plane: &NcPlane, cell: &NcCell) -> NcChar { - core::char::from_u32(unsafe { libc::strdup(cell_extended_gcluster(plane, cell)) } as i32 as u32) - .expect("wrong char") - - // unsafer option B (maybe faster, TODO: bench) - // unsafe { - // core::char::from_u32_unchecked(libc::strdup(cell_extended_gcluster(plane, cell)) as i32 as u32) - // } -} - -/// Saves the [NcStyleMask] and [NcChannelPair] and returns the [NcChar] -/// (the three elements of an [NcCell]. -#[inline] -pub fn cell_extract( - plane: &NcPlane, - cell: &NcCell, - stylemask: &mut NcStyleMask, - channels: &mut NcChannelPair, -) -> NcChar { - if *stylemask != 0 { - *stylemask = cell.stylemask; - } - if *channels != 0 { - *channels = cell.channels; - } - cell_strdup(plane, cell) -} - -/// Returns true if the two cells are distinct [NcChar]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 NcChar must be equal. The NcChar must be bit-equal; -// NOTE: FIXME: it would probably be better to test whether they're Unicode-equal -#[inline] -pub fn cellcmp(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( - cell_extended_gcluster(plane1, cell1), - cell_extended_gcluster(plane2, cell2), - ) != 0 - } -} - -/// Loads a 7-bit char into the [NcCell]. -// NOTE: remove casting for NCCELL_WIDEASIAN_MASK when fixed: https://github.com/rust-lang/rust-bindgen/issues/1875 -#[inline] -pub fn cell_load_char(plane: &mut NcPlane, cell: &mut NcCell, ch: NcChar) -> i32 { - unsafe { - cell_release(plane, cell); - } - cell.channels &= !(NCCELL_WIDEASIAN_MASK as NcChannelPair | NCCELL_NOBACKGROUND_MASK); - cell.gcluster = ch as u32; - 1 -} - -/// Extracts the 32-bit background [NcChannel] from an [NcCell]. -#[inline] -pub fn cell_bchannel(cell: &NcCell) -> NcChannel { - channels_bchannel(cell.channels) -} - -/// Extracts the 32-bit foreground [NcChannel] from an [NcCell]. -#[inline] -pub fn cell_fchannel(cell: &NcCell) -> NcChannel { - channels_fchannel(cell.channels) -} - -/// Sets the 32-bit background [NcChannel] of an [NcCell] and returns its new -/// [NcChannelPair]. -#[inline] -pub fn cell_set_bchannel(cell: &mut NcCell, channel: NcChannel) -> NcChannelPair { - channels_set_bchannel(&mut cell.channels, channel) -} - -/// Sets the 32-bit foreground [NcChannel] of an [NcCell] and returns its new -/// [NcChannelPair]. -#[inline] -pub fn cell_set_fchannel(cell: &mut NcCell, channel: NcChannel) -> NcChannelPair { - channels_set_fchannel(&mut cell.channels, channel) -} - -/// Extracts the foreground [NcRgb] 24-bit value from an [NcCell] -/// (shifted to LSBs). -#[inline] -pub fn cell_fg_rgb(cell: &NcCell) -> NcRgb { - channels_fg_rgb(cell.channels) -} - -/// Extracts the background [NcRgb] 24-bit value from an [NcCell] -/// (shifted to LSBs). -#[inline] -pub fn cell_bg_rgb(cell: &NcCell) -> NcRgb { - channels_bg_rgb(cell.channels) -} - -/// Extracts the foreground [NcAlphaBits] from an [NcCell] (shifted to LSBs). -#[inline] -pub fn cell_fg_alpha(cell: &NcCell) -> NcAlphaBits { - channels_fg_alpha(cell.channels) -} - -/// Extracts the background [NcAlphaBits] from an [NcCell] (shifted to LSBs). -#[inline] -pub fn cell_bg_alpha(cell: &NcCell) -> NcAlphaBits { - channels_bg_alpha(cell.channels) -} - -/// Extracts the foreground [NcRgb] 24-bit value from an [NcCell] and saves it -/// split into three [NcColor] 8-bit components. Also returns the corresponding -/// [NcChannel] (which can have some extra bits set). -#[inline] -pub fn cell_fg_rgb8( - cell: &NcCell, - red: &mut NcColor, - green: &mut NcColor, - blue: &mut NcColor, -) -> NcChannel { - channels_fg_rgb8(cell.channels, red, green, blue) -} - -/// Extracts the background [NcRgb] 24-bit value from an [NcCell] and saves it -/// split into three [NcColor] 8-bit components. Also returns the corresponding -/// [NcChannel] (which can have some extra bits set). -#[inline] -pub fn cell_bg_rgb8( - cell: &NcCell, - red: &mut NcColor, - green: &mut NcColor, - blue: &mut NcColor, -) -> NcChannel { - channels_bg_rgb8(cell.channels, red, green, blue) -} - -/// Sets the RGB [NcColor] components for the foreground [NcChannel] of an -/// [NcCell], and marks it as not using the default color. -#[inline] -pub fn cell_set_fg_rgb8(cell: &mut NcCell, red: NcColor, green: NcColor, blue: NcColor) { - channels_set_fg_rgb8(&mut cell.channels, red, green, blue); -} - -/// Sets the 24-bit [NcRgb] value for the foreground [NcChannel] of an -/// [NcCell], and marks it as not using the default color. -#[inline] -pub fn cell_set_fg_rgb(cell: &mut NcCell, rgb: NcRgb) { - channels_set_fg_rgb(&mut cell.channels, rgb); -} - -/// Sets an [NcCell]'s foreground [NcPaletteIndex]. -/// -/// Also sets [NCCELL_FG_PALETTE] and [NCCELL_ALPHA_OPAQUE], -/// and clears out [NCCELL_FGDEFAULT_MASK]. -/// -// NOTE: unlike the original C function, this one can't fail -#[inline] -pub fn cell_set_fg_palindex(cell: &mut NcCell, index: NcPaletteIndex) { - cell.channels |= NCCELL_FGDEFAULT_MASK; - cell.channels |= NCCELL_FG_PALETTE; - cell_set_fg_alpha(cell, NCCELL_ALPHA_OPAQUE); - cell.channels &= 0xff000000ffffffff as NcChannelPair; - cell.channels |= (index as NcChannelPair) << 32; -} - -/// Returns the [NcPaletteIndex] of the foreground [NcChannel] of the -/// [NcCell] -#[inline] -pub fn cell_fg_palindex(cell: &NcCell) -> NcPaletteIndex { - ((cell.channels & 0xff00000000 as NcChannelPair) >> 32) as NcPaletteIndex -} - -/// Sets the [NcColor] 8-bit RGB components of the background [NcChannel] -/// of the [NcCell], and marks it as not using the "default color". -#[inline] -pub fn cell_set_bg_rgb8(cell: &mut NcCell, red: NcColor, green: NcColor, blue: NcColor) { - channels_set_bg_rgb8(&mut cell.channels, red, green, blue); -} - -/// Sets the [NcRgb] 24-bit value for the background [NcChannel] of this -/// [NcCell], and marks it as not using the default color. -#[inline] -pub fn cell_set_bg_rgb(cell: &mut NcCell, rgb: NcRgb) { - channels_set_bg_rgb(&mut cell.channels, rgb); -} - -/// Sets an [NcCell]'s background [NcPaletteIndex]. -/// -/// Also sets [NCCELL_BG_PALETTE] and [NCCELL_ALPHA_OPAQUE], -/// and clears out [NCCELL_BGDEFAULT_MASK]. -/// -// NOTE: unlike the original C function, this one can't fail -#[inline] -pub fn cell_set_bg_palindex(cell: &mut NcCell, index: NcPaletteIndex) { - cell.channels |= NCCELL_BGDEFAULT_MASK as NcChannelPair; - cell.channels |= NCCELL_BG_PALETTE as NcChannelPair; - cell_set_bg_alpha(cell, NCCELL_ALPHA_OPAQUE); - cell.channels &= 0xffffffffff000000; - cell.channels |= index as NcChannelPair; -} - -/// Returns the [NcPaletteIndex] of the background [NcChannel] of the [NcCell] -#[inline] -pub fn cell_bg_palindex(cell: &NcCell) -> NcPaletteIndex { - (cell.channels & 0xff) as NcPaletteIndex -} - -/// Is the foreground [NcChannel] of this [NcCell] using the -/// "default foreground color"? -#[inline] -pub fn cell_fg_default_p(cell: &NcCell) -> bool { - channels_fg_default_p(cell.channels) -} - -/// Is the foreground [NcChannel] of this [NcCell] using an -/// [NcPaletteIndex] [indexed][NcPaletteIndex] [NcPalette][crate::NcPalette] color? -#[inline] -pub fn cell_fg_palindex_p(cell: &NcCell) -> bool { - channels_fg_palindex_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. -#[inline] -pub fn cell_bg_default_p(cell: &NcCell) -> bool { - channels_bg_default_p(cell.channels) -} - -/// Is the background [NcChannel] of this [NcCell] using an -/// [NcPaletteIndex] [indexed][NcPaletteIndex] [NcPalette][crate::NcPalette] color? -#[inline] -pub fn cell_bg_palindex_p(cell: &NcCell) -> bool { - channels_bg_palindex_p(cell.channels) -} +mod test; + +mod methods; +mod reimplemented; +pub use reimplemented::*; + +// NcCell +/// A coordinate on an [`NcPlane`] storing 128 bits of data +/// +/// An `NcCell` corresponds to a single character cell on some [`NcPlane`], +/// which can be occupied by a single [`NcEgc`] grapheme cluster (some root +/// spacing glyph, along with possible combining characters, which might span +/// multiple columns). +/// +/// At any `NcCell`, we can have a theoretically arbitrarily long UTF-8 string, +/// a foreground color, a background color, and an [`NcStyleMask`] 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. NcEgc +/// 00000000 ~~~~~~~~ 11111111 11111111 2. NcEgcBackstop + 3. reserved + 4. NcStyleMask +/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB 5. NcChannelPair +/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB | +/// +/// 1. (32b) Extended Grapheme Cluster, presented either as: +/// +/// 1.1. An NcEgc 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) reserved (ought to be zero) +/// ~~~~~~~~ +/// +/// 4. (16b) NcStyleMask +/// 11111111 11111111 +/// +/// 5. (64b) NcChannelPair +/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB|~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB +/// ``` +/// +/// `type in C: cell (struct)` +/// +/// ## 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 [`NcEgc`] +/// 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 ([`NCCELL_ALPHA_OPAQUE`]) its foreground color is used unchanged. +/// +/// - If its alpha is 10 ([`NCCELL_ALPHA_TRANSPARENT`]) its foreground color is derived +/// entirely from cells underneath it. +/// +/// - If its alpha is 01 ([`NCCELL_ALPHA_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 ([`NCCELL_ALPHA_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. +/// +pub type NcCell = crate::bindings::bindgen::cell; + +/// [`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 NCCELL_ALPHA_BLEND: u32 = crate::bindings::bindgen::CELL_ALPHA_BLEND; + +/// [`NcAlphaBits`] bits indicating +/// [`NcCell`]'s foreground color will be high-contrast (relative to the +/// computed background). Background cannot be highcontrast +pub const NCCELL_ALPHA_HIGHCONTRAST: u32 = crate::bindings::bindgen::CELL_ALPHA_HIGHCONTRAST; + +/// [`NcAlphaBits`] bits indicating +/// [`NcCell`]'s foreground or background color is used unchanged +pub const NCCELL_ALPHA_OPAQUE: u32 = crate::bindings::bindgen::CELL_ALPHA_OPAQUE; + +/// [`NcAlphaBits`] bits indicating +/// [`NcCell`]'s foreground or background color is derived entirely from the +/// `NcCell`s underneath it +pub const NCCELL_ALPHA_TRANSPARENT: u32 = crate::bindings::bindgen::CELL_ALPHA_TRANSPARENT; + +/// If this bit is set, we are *not* using the default background color +/// +/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] +/// +/// NOTE: This can also be used against a single [`NcChannel`] +pub const NCCELL_BGDEFAULT_MASK: u32 = crate::bindings::bindgen::CELL_BGDEFAULT_MASK; + +/// Extract these bits to get the background alpha mask +/// ([`NcAlphaBits`]) +/// +/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] +/// +/// NOTE: This can also be used against a single [`NcChannel`] +pub const NCCELL_BG_ALPHA_MASK: u32 = crate::bindings::bindgen::CELL_BG_ALPHA_MASK; + +/// If this bit *and* [`NCCELL_BGDEFAULT_MASK`] are set, we're using a +/// palette-indexed background color +/// +/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] +/// +/// NOTE: This can also be used against a single [`NcChannel`] +pub const NCCELL_BG_PALETTE: u32 = crate::bindings::bindgen::CELL_BG_PALETTE; + +/// Extract these bits to get the background [`NcRgb`][crate::NcRgb] value +/// +/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] +/// +/// NOTE: This can also be used against a single [`NcChannel`] +pub const NCCELL_BG_RGB_MASK: u32 = crate::bindings::bindgen::CELL_BG_RGB_MASK; + +/// If this bit is set, we are *not* using the default foreground color +/// +/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] +/// +/// NOTE: When working with a single [`NcChannel`] use [`NCCELL_BGDEFAULT_MASK`]; +pub const NCCELL_FGDEFAULT_MASK: u64 = crate::bindings::bindgen::CELL_FGDEFAULT_MASK; + +/// Extract these bits to get the foreground alpha mask +/// ([`NcAlphaBits`]) +/// +/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] +/// +/// NOTE: When working with a single [`NcChannel`] use [`NCCELL_BG_ALPHA_MASK`]; +pub const NCCELL_FG_ALPHA_MASK: u64 = crate::bindings::bindgen::CELL_FG_ALPHA_MASK; + +/// If this bit *and* [`NCCELL_FGDEFAULT_MASK`] are set, we're using a +/// palette-indexed background color +/// +/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] +/// +/// NOTE: When working with a single [`NcChannel`] use [`NCCELL_BG_PALETTE`]; +pub const NCCELL_FG_PALETTE: u64 = crate::bindings::bindgen::CELL_FG_PALETTE; + +/// Extract these bits to get the foreground [`NcRgb`][crate::NcRgb] value +/// +/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] +/// +/// NOTE: When working with a single [`NcChannel`] use [`NCCELL_BG_RGB_MASK`]; +pub const NCCELL_FG_RGB_MASK: u64 = crate::bindings::bindgen::CELL_FG_RGB_MASK; + +/// Indicates the glyph is entirely foreground +/// +/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] +pub const NCCELL_NOBACKGROUND_MASK: u64 = crate::bindings::bindgen::CELL_NOBACKGROUND_MASK; + +/// If this bit is set, 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. +/// +/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] +pub const NCCELL_WIDEASIAN_MASK: u64 = crate::bindings::bindgen::CELL_WIDEASIAN_MASK as u64; + +// NcEgc +// +/// Extended Grapheme Cluster. A 32-bit [`char`]-like type +/// +/// 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) +/// +/// +pub type NcEgc = char; + +// NcEgcBackStop +/// An `u8` always at zero, part of the [`NcCell`] struct +/// +/// ## Diagram +/// +/// ```txt +/// 00000000 +/// ``` +/// +/// `type in C: uint_8t` +/// +pub type NcEgcBackstop = u8; + +// NcStyleMask +/// +/// An `u16` of `NCSTYLE_*` boolean styling attribute flags +/// +/// ## Attributes +/// +/// - [`NCSTYLE_BLINK`] +/// - [`NCSTYLE_BOLD`] +/// - [`NCSTYLE_DIM`] +/// - [`NCSTYLE_INVIS`] +/// - [`NCSTYLE_ITALIC`] +/// - [`NCSTYLE_MASK`] +/// - [`NCSTYLE_NONE`] +/// - [`NCSTYLE_PROTECT`] +/// - [`NCSTYLE_REVERSE`] +/// - [`NCSTYLE_STANDOUT`] +/// - [`NCSTYLE_STRUCK`] +/// - [`NCSTYLE_UNDERLINE`] +/// +/// +/// ## Diagram +/// +/// ```txt +/// 11111111 11111111 +/// ``` +/// +/// `type in C: uint16_t` +/// +pub type NcStyleMask = u16; + +/// +pub const NCSTYLE_BLINK: u16 = crate::bindings::bindgen::NCSTYLE_BLINK as u16; + +/// +pub const NCSTYLE_BOLD: u16 = crate::bindings::bindgen::NCSTYLE_BOLD as u16; + +/// +pub const NCSTYLE_DIM: u16 = crate::bindings::bindgen::NCSTYLE_DIM as u16; + +/// +pub const NCSTYLE_INVIS: u16 = crate::bindings::bindgen::NCSTYLE_INVIS as u16; + +/// +pub const NCSTYLE_ITALIC: u16 = crate::bindings::bindgen::NCSTYLE_ITALIC as u16; + +/// +pub const NCSTYLE_MASK: u16 = crate::bindings::bindgen::NCSTYLE_MASK as u16; + +/// +pub const NCSTYLE_NONE: u16 = crate::bindings::bindgen::NCSTYLE_NONE as u16; + +/// +pub const NCSTYLE_PROTECT: u16 = crate::bindings::bindgen::NCSTYLE_PROTECT as u16; + +/// +pub const NCSTYLE_REVERSE: u16 = crate::bindings::bindgen::NCSTYLE_REVERSE as u16; + +/// +pub const NCSTYLE_STANDOUT: u16 = crate::bindings::bindgen::NCSTYLE_STANDOUT as u16; + +/// +pub const NCSTYLE_STRUCK: u16 = crate::bindings::bindgen::NCSTYLE_STRUCK as u16; + +/// +pub const NCSTYLE_UNDERLINE: u16 = crate::bindings::bindgen::NCSTYLE_UNDERLINE as u16; diff --git a/rust/src/cells/reimplemented.rs b/rust/src/cells/reimplemented.rs new file mode 100644 index 000000000..195c0ee0c --- /dev/null +++ b/rust/src/cells/reimplemented.rs @@ -0,0 +1,434 @@ +//! `cell*_*` reimplemented functions. + +use libc::strcmp; + +use crate::{ + cell_extended_gcluster, cell_load, cell_release, channels_bchannel, channels_bg_alpha, + channels_bg_default_p, channels_bg_palindex_p, channels_bg_rgb, channels_bg_rgb8, + channels_fchannel, channels_fg_alpha, channels_fg_default_p, channels_fg_palindex_p, + channels_fg_rgb, channels_fg_rgb8, channels_set_bchannel, channels_set_bg_alpha, + channels_set_bg_default, channels_set_bg_rgb, channels_set_bg_rgb8, channels_set_fchannel, + channels_set_fg_alpha, channels_set_fg_default, channels_set_fg_rgb, channels_set_fg_rgb8, + NcAlphaBits, NcCell, NcChannel, NcChannelPair, NcColor, NcEgc, NcPaletteIndex, NcPlane, + NcResult, NcRgb, NcStyleMask, NCCELL_ALPHA_OPAQUE, NCCELL_BGDEFAULT_MASK, NCCELL_BG_PALETTE, + NCCELL_FGDEFAULT_MASK, NCCELL_FG_PALETTE, NCCELL_NOBACKGROUND_MASK, NCCELL_WIDEASIAN_MASK, + NCRESULT_ERR, NCRESULT_OK, NCSTYLE_MASK, +}; + +/// Same as [cell_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'. +/// +#[allow(unused_unsafe)] +pub unsafe fn cell_prime( + plane: &mut NcPlane, + cell: &mut NcCell, + gcluster: NcEgc, + style: NcStyleMask, + channels: NcChannelPair, +) -> NcResult { + cell.stylemask = style; + cell.channels = channels; + unsafe { cell_load(plane, cell, gcluster as u32 as *const i8) } +} + +/// Loads up six cells with the [NcEgc]s necessary to draw a box. +/// +/// Returns [NCRESULT_OK] on success, [NCRESULT_ERR] on error. +/// +/// On error, any [NcCell]s this function might have loaded before the error +/// are [cell_release]d. There must be at least six [NcEgc]s in gcluster. +/// +#[allow(unused_unsafe)] +pub unsafe fn cells_load_box( + plane: &mut NcPlane, + style: NcStyleMask, + channels: NcChannelPair, + ul: &mut NcCell, + ur: &mut NcCell, + ll: &mut NcCell, + lr: &mut NcCell, + hl: &mut NcCell, + vl: &mut NcCell, + gcluster: NcEgc, +) -> NcResult { + // mutable copy for pointer arithmetics: + let mut gclu = gcluster as u32 as *const i8; + let mut ulen: NcResult; + + ulen = unsafe { cell_prime(plane, ul, gcluster, style, channels) }; + + if ulen > 0 { + gclu = unsafe { gclu.offset(ulen as isize) }; + ulen = unsafe { cell_prime(plane, ur, gcluster, style, channels) }; + + if ulen > 0 { + gclu = unsafe { gclu.offset(ulen as isize) }; + ulen = unsafe { cell_prime(plane, ll, gcluster, style, channels) }; + + if ulen > 0 { + gclu = unsafe { gclu.offset(ulen as isize) }; + ulen = unsafe { cell_prime(plane, lr, gcluster, style, channels) }; + + if ulen > 0 { + gclu = unsafe { gclu.offset(ulen as isize) }; + ulen = unsafe { cell_prime(plane, hl, gcluster, style, channels) }; + + if ulen > 0 { + let _gclu = unsafe { gclu.offset(ulen as isize) }; + ulen = unsafe { cell_prime(plane, vl, gcluster, style, channels) }; + + if ulen > 0 { + return NCRESULT_OK; + } + unsafe { + cell_release(plane, hl); + } + } + unsafe { + cell_release(plane, lr); + } + } + unsafe { + cell_release(plane, ll); + } + } + unsafe { + cell_release(plane, ur); + } + } + unsafe { + cell_release(plane, ul); + } + } + NCRESULT_ERR +} + +/// Initializes (zeroes out) an [NcCell]. +#[inline] +pub fn cell_init(cell: &mut NcCell) { + *cell = unsafe { core::mem::zeroed() } +} + +/// Sets *just* the specified [NcStyleMask] bits for an [NcCell], +/// whether they're actively supported or not. +#[inline] +pub fn cell_styles_set(cell: &mut NcCell, stylebits: NcStyleMask) { + cell.stylemask = stylebits & NCSTYLE_MASK as u16; +} + +/// Extracts the [NcStyleMask] bits from an [NcCell]. +#[inline] +pub fn cell_styles(cell: &NcCell) -> NcStyleMask { + cell.stylemask +} + +/// Adds the specified [NcStyleMask] bits to an [NcCell]'s existing spec., +/// whether they're actively supported or not. +#[inline] +pub fn cell_styles_on(cell: &mut NcCell, stylebits: NcStyleMask) { + cell.stylemask |= stylebits & NCSTYLE_MASK as u16; +} + +/// Removes the specified [NcStyleMask] bits from an [NcCell]'s existing spec. +#[inline] +pub fn cell_styles_off(cell: &mut NcCell, stylebits: NcStyleMask) { + cell.stylemask &= !(stylebits & NCSTYLE_MASK as u16); +} + +/// Indicates to use the "default color" for the **foreground** [NcChannel] +/// of an [NcCell]. +#[inline] +pub fn cell_set_fg_default(cell: &mut NcCell) { + channels_set_fg_default(&mut cell.channels); +} + +/// Indicates to use the "default color" for the **background** [NcChannel] +/// of an [NcCell]. +#[inline] +pub fn cell_set_bg_default(cell: &mut NcCell) { + channels_set_bg_default(&mut cell.channels); +} + +/// Sets the foreground [NcAlphaBits] of an [NcCell]. +#[inline] +pub fn cell_set_fg_alpha(cell: &mut NcCell, alpha: NcAlphaBits) { + channels_set_fg_alpha(&mut cell.channels, alpha); +} + +/// Sets the background [NcAlphaBits] of an [NcCell]. +#[inline] +pub fn cell_set_bg_alpha(cell: &mut NcCell, alpha: NcAlphaBits) { + channels_set_bg_alpha(&mut cell.channels, alpha); +} + +/// Does the [NcCell] contain an East Asian Wide codepoint? +// NOTE: remove casting when fixed: +// https://github.com/rust-lang/rust-bindgen/issues/1875 +#[inline] +pub fn cell_double_wide_p(cell: &NcCell) -> bool { + (cell.channels & NCCELL_WIDEASIAN_MASK as NcChannelPair) != 0 +} + +/// Is this the right half of a wide character? +#[inline] +pub fn cell_wide_right_p(cell: &NcCell) -> bool { + cell_double_wide_p(cell) && cell.gcluster == 0 +} + +/// Is this the left half of a wide character? +#[inline] +pub fn cell_wide_left_p(cell: &NcCell) -> bool { + cell_double_wide_p(cell) && cell.gcluster != 0 +} + +/// Copies the UTF8-encoded [NcEgc] out of the cell, whether simple +/// or complex. +/// +/// The result is not tied to the [NcPlane], and persists +/// across erases and destruction. +#[inline] +pub fn cell_strdup(plane: &NcPlane, cell: &NcCell) -> NcEgc { + core::char::from_u32(unsafe { libc::strdup(cell_extended_gcluster(plane, cell)) } as i32 as u32) + .expect("wrong char") + + // unsafer option B (maybe faster, TODO: bench) + // unsafe { + // core::char::from_u32_unchecked(libc::strdup(cell_extended_gcluster(plane, cell)) as i32 as u32) + // } +} + +/// Saves the [NcStyleMask] and the [NcChannelPair], and returns the [NcEgc] +/// (the three elements of an [NcCell]). +#[inline] +pub fn cell_extract( + plane: &NcPlane, + cell: &NcCell, + stylemask: &mut NcStyleMask, + channels: &mut NcChannelPair, +) -> NcEgc { + if *stylemask != 0 { + *stylemask = cell.stylemask; + } + if *channels != 0 { + *channels = cell.channels; + } + cell_strdup(plane, cell) +} + +/// Returns true if the two cells are distinct [NcEgc]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 NcEgc must be equal. The NcEgc must be bit-equal; +// NOTE: FIXME: it would probably be better to test whether they're Unicode-equal +#[inline] +pub fn cellcmp(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( + cell_extended_gcluster(plane1, cell1), + cell_extended_gcluster(plane2, cell2), + ) != 0 + } +} + +/// Loads a 7-bit char into the [NcCell]. +// NOTE: Unlike the original C function this doesn't return anything. +// REMINDER: remove casting for NCCELL_WIDEASIAN_MASK when fixed: https://github.com/rust-lang/rust-bindgen/issues/1875 +#[inline] +pub fn cell_load_char(plane: &mut NcPlane, cell: &mut NcCell, ch: NcEgc) /* -> i32 */ +{ + unsafe { + cell_release(plane, cell); + } + cell.channels &= !(NCCELL_WIDEASIAN_MASK as NcChannelPair | NCCELL_NOBACKGROUND_MASK); + cell.gcluster = ch as u32; +} + +/// Extracts the 32-bit background [NcChannel] from an [NcCell]. +#[inline] +pub fn cell_bchannel(cell: &NcCell) -> NcChannel { + channels_bchannel(cell.channels) +} + +/// Extracts the 32-bit foreground [NcChannel] from an [NcCell]. +#[inline] +pub fn cell_fchannel(cell: &NcCell) -> NcChannel { + channels_fchannel(cell.channels) +} + +/// Sets the 32-bit background [NcChannel] of an [NcCell] and returns its new +/// [NcChannelPair]. +#[inline] +pub fn cell_set_bchannel(cell: &mut NcCell, channel: NcChannel) -> NcChannelPair { + channels_set_bchannel(&mut cell.channels, channel) +} + +/// Sets the 32-bit foreground [NcChannel] of an [NcCell] and returns its new +/// [NcChannelPair]. +#[inline] +pub fn cell_set_fchannel(cell: &mut NcCell, channel: NcChannel) -> NcChannelPair { + channels_set_fchannel(&mut cell.channels, channel) +} + +/// Extracts the foreground [NcRgb] 24-bit value from an [NcCell] +/// (shifted to LSBs). +#[inline] +pub fn cell_fg_rgb(cell: &NcCell) -> NcRgb { + channels_fg_rgb(cell.channels) +} + +/// Extracts the background [NcRgb] 24-bit value from an [NcCell] +/// (shifted to LSBs). +#[inline] +pub fn cell_bg_rgb(cell: &NcCell) -> NcRgb { + channels_bg_rgb(cell.channels) +} + +/// Extracts the foreground [NcAlphaBits] from an [NcCell] (shifted to LSBs). +#[inline] +pub fn cell_fg_alpha(cell: &NcCell) -> NcAlphaBits { + channels_fg_alpha(cell.channels) +} + +/// Extracts the background [NcAlphaBits] from an [NcCell] (shifted to LSBs). +#[inline] +pub fn cell_bg_alpha(cell: &NcCell) -> NcAlphaBits { + channels_bg_alpha(cell.channels) +} + +/// Extracts the foreground [NcRgb] 24-bit value from an [NcCell] and saves it +/// split into three [NcColor] 8-bit components. Also returns the corresponding +/// [NcChannel] (which can have some extra bits set). +#[inline] +pub fn cell_fg_rgb8( + cell: &NcCell, + red: &mut NcColor, + green: &mut NcColor, + blue: &mut NcColor, +) -> NcChannel { + channels_fg_rgb8(cell.channels, red, green, blue) +} + +/// Extracts the background [NcRgb] 24-bit value from an [NcCell] and saves it +/// split into three [NcColor] 8-bit components. Also returns the corresponding +/// [NcChannel] (which can have some extra bits set). +#[inline] +pub fn cell_bg_rgb8( + cell: &NcCell, + red: &mut NcColor, + green: &mut NcColor, + blue: &mut NcColor, +) -> NcChannel { + channels_bg_rgb8(cell.channels, red, green, blue) +} + +/// Sets the RGB [NcColor] components for the foreground [NcChannel] of an +/// [NcCell], and marks it as not using the default color. +#[inline] +pub fn cell_set_fg_rgb8(cell: &mut NcCell, red: NcColor, green: NcColor, blue: NcColor) { + channels_set_fg_rgb8(&mut cell.channels, red, green, blue); +} + +/// Sets the 24-bit [NcRgb] value for the foreground [NcChannel] of an +/// [NcCell], and marks it as not using the default color. +#[inline] +pub fn cell_set_fg_rgb(cell: &mut NcCell, rgb: NcRgb) { + channels_set_fg_rgb(&mut cell.channels, rgb); +} + +/// Sets an [NcCell]'s foreground [NcPaletteIndex]. +/// +/// Also sets [NCCELL_FG_PALETTE] and [NCCELL_ALPHA_OPAQUE], +/// and clears out [NCCELL_FGDEFAULT_MASK]. +/// +// NOTE: unlike the original C function, this one can't fail +#[inline] +pub fn cell_set_fg_palindex(cell: &mut NcCell, index: NcPaletteIndex) { + cell.channels |= NCCELL_FGDEFAULT_MASK; + cell.channels |= NCCELL_FG_PALETTE; + cell_set_fg_alpha(cell, NCCELL_ALPHA_OPAQUE); + cell.channels &= 0xff000000ffffffff as NcChannelPair; + cell.channels |= (index as NcChannelPair) << 32; +} + +/// Returns the [NcPaletteIndex] of the foreground [NcChannel] of the +/// [NcCell] +#[inline] +pub fn cell_fg_palindex(cell: &NcCell) -> NcPaletteIndex { + ((cell.channels & 0xff00000000 as NcChannelPair) >> 32) as NcPaletteIndex +} + +/// Sets the [NcColor] 8-bit RGB components of the background [NcChannel] +/// of the [NcCell], and marks it as not using the "default color". +#[inline] +pub fn cell_set_bg_rgb8(cell: &mut NcCell, red: NcColor, green: NcColor, blue: NcColor) { + channels_set_bg_rgb8(&mut cell.channels, red, green, blue); +} + +/// Sets the [NcRgb] 24-bit value for the background [NcChannel] of this +/// [NcCell], and marks it as not using the default color. +#[inline] +pub fn cell_set_bg_rgb(cell: &mut NcCell, rgb: NcRgb) { + channels_set_bg_rgb(&mut cell.channels, rgb); +} + +/// Sets an [NcCell]'s background [NcPaletteIndex]. +/// +/// Also sets [NCCELL_BG_PALETTE] and [NCCELL_ALPHA_OPAQUE], +/// and clears out [NCCELL_BGDEFAULT_MASK]. +/// +// NOTE: unlike the original C function, this one can't fail +#[inline] +pub fn cell_set_bg_palindex(cell: &mut NcCell, index: NcPaletteIndex) { + cell.channels |= NCCELL_BGDEFAULT_MASK as NcChannelPair; + cell.channels |= NCCELL_BG_PALETTE as NcChannelPair; + cell_set_bg_alpha(cell, NCCELL_ALPHA_OPAQUE); + cell.channels &= 0xffffffffff000000; + cell.channels |= index as NcChannelPair; +} + +/// Returns the [NcPaletteIndex] of the background [NcChannel] of the [NcCell] +#[inline] +pub fn cell_bg_palindex(cell: &NcCell) -> NcPaletteIndex { + (cell.channels & 0xff) as NcPaletteIndex +} + +/// Is the foreground [NcChannel] of this [NcCell] using the +/// "default foreground color"? +#[inline] +pub fn cell_fg_default_p(cell: &NcCell) -> bool { + channels_fg_default_p(cell.channels) +} + +/// Is the foreground [NcChannel] of this [NcCell] using an +/// [NcPaletteIndex] [indexed][NcPaletteIndex] [NcPalette][crate::NcPalette] color? +#[inline] +pub fn cell_fg_palindex_p(cell: &NcCell) -> bool { + channels_fg_palindex_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. +#[inline] +pub fn cell_bg_default_p(cell: &NcCell) -> bool { + channels_bg_default_p(cell.channels) +} + +/// Is the background [NcChannel] of this [NcCell] using an +/// [NcPaletteIndex] [indexed][NcPaletteIndex] [NcPalette][crate::NcPalette] color? +#[inline] +pub fn cell_bg_palindex_p(cell: &NcCell) -> bool { + channels_bg_palindex_p(cell.channels) +} diff --git a/rust/src/cells/test/methods.rs b/rust/src/cells/test/methods.rs new file mode 100644 index 000000000..0b4c7c6e2 --- /dev/null +++ b/rust/src/cells/test/methods.rs @@ -0,0 +1,15 @@ +//! Test `NcCell` methods and associated functions. + +use crate::NcCell; + +use serial_test::serial; + +#[test] +#[serial] +fn constructors() { + let _c1 = NcCell::new(); + + let _c2 = NcCell::with_7bitchar('C'); + + let _c3 = NcCell::with_all('c', 0, 0); +} diff --git a/rust/src/cells/test/mod.rs b/rust/src/cells/test/mod.rs new file mode 100644 index 000000000..b9c681d66 --- /dev/null +++ b/rust/src/cells/test/mod.rs @@ -0,0 +1,7 @@ +//! `NcCell` tests + +#[cfg(test)] +mod methods; + +#[cfg(test)] +mod reimplemented; diff --git a/rust/src/cells/tests.rs b/rust/src/cells/test/reimplemented.rs similarity index 95% rename from rust/src/cells/tests.rs rename to rust/src/cells/test/reimplemented.rs index 911854846..79e9d2d5d 100644 --- a/rust/src/cells/tests.rs +++ b/rust/src/cells/test/reimplemented.rs @@ -1,18 +1,8 @@ -//! [`NcCell`] tests - -use crate::NcCell; +//! Test `cell*_*` reimplemented functions use serial_test::serial; -#[test] -#[serial] -fn constructors() { - let _c1 = NcCell::new(); - - let _c2 = NcCell::with_7bitchar('C'); - - let _c3 = NcCell::with_all('c', 0, 0); -} +use crate::NcCell; #[test] #[serial] diff --git a/rust/src/cells/types.rs b/rust/src/cells/types.rs deleted file mode 100644 index 9430ea18a..000000000 --- a/rust/src/cells/types.rs +++ /dev/null @@ -1,327 +0,0 @@ -#[allow(unused_imports)] // for docblocks -use crate::{NcAlphaBits, NcChannel, NcPlane}; - -// NcCell -/// A coordinate on an [`NcPlane`] storing 128 bits of data -/// -/// An `NcCell` corresponds to a single character cell on some [`NcPlane`], -/// which can be occupied by a single [`NcChar`] grapheme cluster (some root -/// spacing glyph, along with possible combining characters, which might span -/// multiple columns). -/// -/// At any `NcCell`, we can have a theoretically arbitrarily long UTF-8 string, -/// a foreground color, a background color, and an [`NcStyleMask`] 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. NcChar -/// 00000000 ~~~~~~~~ 11111111 11111111 2. NcCharBackstop + 3. reserved + 4. NcStyleMask -/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB 5. NcChannelPair -/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB | -/// -/// 1. (32b) Extended Grapheme Cluster, presented either as: -/// -/// 1.1. An NcChar 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) reserved (ought to be zero) -/// ~~~~~~~~ -/// -/// 4. (16b) NcStyleMask -/// 11111111 11111111 -/// -/// 5. (64b) NcChannelPair -/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB|~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB -/// ``` -/// -/// `type in C: cell (struct)` -/// -/// ## 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 [`NcChar`] -/// 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 ([`NCCELL_ALPHA_OPAQUE`]) its foreground color is used unchanged. -/// -/// - If its alpha is 10 ([`NCCELL_ALPHA_TRANSPARENT`]) its foreground color is derived -/// entirely from cells underneath it. -/// -/// - If its alpha is 01 ([`NCCELL_ALPHA_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 ([`NCCELL_ALPHA_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. -/// -pub type NcCell = crate::bindings::bindgen::cell; - -/// [`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 NCCELL_ALPHA_BLEND: u32 = crate::bindings::bindgen::CELL_ALPHA_BLEND; - -/// [`NcAlphaBits`] bits indicating -/// [`NcCell`]'s foreground color will be high-contrast (relative to the -/// computed background). Background cannot be highcontrast -pub const NCCELL_ALPHA_HIGHCONTRAST: u32 = crate::bindings::bindgen::CELL_ALPHA_HIGHCONTRAST; - -/// [`NcAlphaBits`] bits indicating -/// [`NcCell`]'s foreground or background color is used unchanged -pub const NCCELL_ALPHA_OPAQUE: u32 = crate::bindings::bindgen::CELL_ALPHA_OPAQUE; - -/// [`NcAlphaBits`] bits indicating -/// [`NcCell`]'s foreground or background color is derived entirely from the -/// `NcCell`s underneath it -pub const NCCELL_ALPHA_TRANSPARENT: u32 = crate::bindings::bindgen::CELL_ALPHA_TRANSPARENT; - -/// If this bit is set, we are *not* using the default background color -/// -/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] -/// -/// NOTE: This can also be used against a single [`NcChannel`] -pub const NCCELL_BGDEFAULT_MASK: u32 = crate::bindings::bindgen::CELL_BGDEFAULT_MASK; - -/// Extract these bits to get the background alpha mask -/// ([`NcAlphaBits`]) -/// -/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] -/// -/// NOTE: This can also be used against a single [`NcChannel`] -pub const NCCELL_BG_ALPHA_MASK: u32 = crate::bindings::bindgen::CELL_BG_ALPHA_MASK; - -/// If this bit *and* [`NCCELL_BGDEFAULT_MASK`] are set, we're using a -/// palette-indexed background color -/// -/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] -/// -/// NOTE: This can also be used against a single [`NcChannel`] -pub const NCCELL_BG_PALETTE: u32 = crate::bindings::bindgen::CELL_BG_PALETTE; - -/// Extract these bits to get the background [`NcRgb`][crate::NcRgb] value -/// -/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] -/// -/// NOTE: This can also be used against a single [`NcChannel`] -pub const NCCELL_BG_RGB_MASK: u32 = crate::bindings::bindgen::CELL_BG_RGB_MASK; - -/// If this bit is set, we are *not* using the default foreground color -/// -/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] -/// -/// NOTE: When working with a single [`NcChannel`] use [`NCCELL_BGDEFAULT_MASK`]; -pub const NCCELL_FGDEFAULT_MASK: u64 = crate::bindings::bindgen::CELL_FGDEFAULT_MASK; - -/// Extract these bits to get the foreground alpha mask -/// ([`NcAlphaBits`]) -/// -/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] -/// -/// NOTE: When working with a single [`NcChannel`] use [`NCCELL_BG_ALPHA_MASK`]; -pub const NCCELL_FG_ALPHA_MASK: u64 = crate::bindings::bindgen::CELL_FG_ALPHA_MASK; - -/// If this bit *and* [`NCCELL_FGDEFAULT_MASK`] are set, we're using a -/// palette-indexed background color -/// -/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] -/// -/// NOTE: When working with a single [`NcChannel`] use [`NCCELL_BG_PALETTE`]; -pub const NCCELL_FG_PALETTE: u64 = crate::bindings::bindgen::CELL_FG_PALETTE; - -/// Extract these bits to get the foreground [`NcRgb`][crate::NcRgb] value -/// -/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] -/// -/// NOTE: When working with a single [`NcChannel`] use [`NCCELL_BG_RGB_MASK`]; -pub const NCCELL_FG_RGB_MASK: u64 = crate::bindings::bindgen::CELL_FG_RGB_MASK; - -/// Indicates the glyph is entirely foreground -/// -/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] -pub const NCCELL_NOBACKGROUND_MASK: u64 = crate::bindings::bindgen::CELL_NOBACKGROUND_MASK; - -/// If this bit is set, 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. -/// -/// See the detailed diagram at [`NcChannelPair`][crate::NcChannelPair] -pub const NCCELL_WIDEASIAN_MASK: u64 = crate::bindings::bindgen::CELL_WIDEASIAN_MASK as u64; - -// NcChar -// -/// Extended Grapheme Cluster. A 32-bit [`char`]-like type -/// -/// This 32 bit char, together with the associated plane's associated egcpool, -/// completely define this cell's `NcChar`. Unless the `NcChar` 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 `NcChar` is indicated by the value `0x01iiiiii`. This cannot alias a -/// true supra-ASCII NcChar, 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 `NcChar` 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) -/// -/// -pub type NcChar = char; - -// NcCharBackStop -/// An `u8` always at zero, part of the [`NcCell`] struct -/// -/// ## Diagram -/// -/// ```txt -/// 00000000 -/// ``` -/// -/// `type in C: uint_8t` -/// -pub type NcCharBackstop = u8; - -// NcStyleMask -/// -/// An `u16` of `NCSTYLE_*` boolean styling attribute flags -/// -/// ## Attributes -/// -/// - [`NCSTYLE_BLINK`] -/// - [`NCSTYLE_BOLD`] -/// - [`NCSTYLE_DIM`] -/// - [`NCSTYLE_INVIS`] -/// - [`NCSTYLE_ITALIC`] -/// - [`NCSTYLE_MASK`] -/// - [`NCSTYLE_NONE`] -/// - [`NCSTYLE_PROTECT`] -/// - [`NCSTYLE_REVERSE`] -/// - [`NCSTYLE_STANDOUT`] -/// - [`NCSTYLE_STRUCK`] -/// - [`NCSTYLE_UNDERLINE`] -/// -/// -/// ## Diagram -/// -/// ```txt -/// 11111111 11111111 -/// ``` -/// -/// `type in C: uint16_t` -/// -pub type NcStyleMask = u16; - -/// -pub const NCSTYLE_BLINK: u16 = crate::bindings::bindgen::NCSTYLE_BLINK as u16; - -/// -pub const NCSTYLE_BOLD: u16 = crate::bindings::bindgen::NCSTYLE_BOLD as u16; - -/// -pub const NCSTYLE_DIM: u16 = crate::bindings::bindgen::NCSTYLE_DIM as u16; - -/// -pub const NCSTYLE_INVIS: u16 = crate::bindings::bindgen::NCSTYLE_INVIS as u16; - -/// -pub const NCSTYLE_ITALIC: u16 = crate::bindings::bindgen::NCSTYLE_ITALIC as u16; - -/// -pub const NCSTYLE_MASK: u16 = crate::bindings::bindgen::NCSTYLE_MASK as u16; - -/// -pub const NCSTYLE_NONE: u16 = crate::bindings::bindgen::NCSTYLE_NONE as u16; - -/// -pub const NCSTYLE_PROTECT: u16 = crate::bindings::bindgen::NCSTYLE_PROTECT as u16; - -/// -pub const NCSTYLE_REVERSE: u16 = crate::bindings::bindgen::NCSTYLE_REVERSE as u16; - -/// -pub const NCSTYLE_STANDOUT: u16 = crate::bindings::bindgen::NCSTYLE_STANDOUT as u16; - -/// -pub const NCSTYLE_STRUCK: u16 = crate::bindings::bindgen::NCSTYLE_STRUCK as u16; - -/// -pub const NCSTYLE_UNDERLINE: u16 = crate::bindings::bindgen::NCSTYLE_UNDERLINE as u16; diff --git a/rust/src/cells/wrapped.rs b/rust/src/cells/wrapped.rs deleted file mode 100644 index 796e33978..000000000 --- a/rust/src/cells/wrapped.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Handy [NcCell] constructors - -pub use crate::{NcCell, NcPlane, NcChannelPair, NcCharBackstop, NcStyleMask, cell_load, NCRESULT_ERR, cstring}; - -impl NcCell { - /// New NcCell, expects a [char], [NcStyleMask] and [NcChannelPair]. - #[inline] - pub const fn with_all(ch: char, stylemask: NcStyleMask, channels: NcChannelPair) -> Self { - NcCell { - gcluster: ch as u32, - gcluster_backstop: 0 as NcCharBackstop, - reserved: 0, - stylemask, - channels, - } - } - - /// New NcCell, expects a 7-bit [char]. - /// - /// See also `with_char`. - #[inline] - pub const fn with_7bitchar(ch: char) -> Self { - Self::with_all(ch, 0 as NcStyleMask, 0 as NcChannelPair) - } - - /// New NcCell, expects an [NcPlane] and a utf-8 [char]. - /// - /// See also `with_7bitchar`. - #[inline] - pub fn with_char(plane: &mut NcPlane, ch: char) -> Self { - let mut cell = Self::new(); - let result = unsafe { - cell_load(plane, - &mut cell, - cstring![ch.to_string()], - ) - }; - debug_assert_ne![NCRESULT_ERR, result]; - cell - } - - /// New NcCell, blank. - #[inline] - pub const fn new() -> Self { - Self::with_7bitchar(0 as char) - } -} diff --git a/rust/src/channel/mod.rs b/rust/src/channel/mod.rs index 9de887872..7cd4e9610 100644 --- a/rust/src/channel/mod.rs +++ b/rust/src/channel/mod.rs @@ -1,4 +1,4 @@ -//! [`NcChannel`] & [`NcChannelPair`] `channel*_*` static fn reimplementations +//! `NcChannel*` // ----------------------------------------------------------------------------- // - The channel components are u8 instead of u32. @@ -13,367 +13,227 @@ // - `channels_set_bg_rgb8_clipped()` // ----------------------------------------------------------------------------- // -// functions already exported by bindgen : 0 +// functions manually reimplemented: 39 // ------------------------------------------ -// -// static inline functions total: 39 -// ------------------------------------------ (implement / remaining) // (X) wont: 3 // (+) done: 34 / 2 +// (W) wrap: 0 / 36 // (#) test: 19 / 17 // ------------------------------------------ -//# channel_alpha -//# channel_b -//# channel_default_p -//# channel_g -//# channel_palindex_p -//# channel_r -//# channel_rgb8 -//# channels_bchannel -//+ channels_bg_alpha -//+ channels_bg_default_p -//# channels_bg_palindex_p -//+ channels_bg_rgb -//+ channels_bg_rgb8 -//# channels_combine -//+ channel_set -//# channel_set_alpha -//# channel_set_default -//# channel_set_rgb8 -//X channel_set_rgb_clipped -//# channels_fchannel -//+ channels_fg_alpha -//+ channels_fg_default_p -//# channels_fg_palindex_p -//+ channels_fg_rgb -//+ channels_fg_rgb8 -//# channels_set_bchannel -//+ channels_set_bg_alpha -//+ channels_set_bg_default -//# channels_set_bg_palindex -//+ channels_set_bg_rgb -//+ channels_set_bg_rgb8 -//X channels_set_bg_rgb8_clipped -//# channels_set_fchannel -//+ channels_set_fg_alpha -//+ channels_set_fg_default -//# channels_set_fg_palindex -//+ channels_set_fg_rgb -//+ channels_set_fg_rgb8 -//X channels_set_fg_rgb8_clipped +// # channel_alpha +// # channel_b +// # channel_default_p +// # channel_g +// # channel_palindex_p +// # channel_r +// # channel_rgb8 +// # channels_bchannel +// + channels_bg_alpha +// + channels_bg_default_p +// # channels_bg_palindex_p +// + channels_bg_rgb +// + channels_bg_rgb8 +// # channels_combine +// + channel_set +// # channel_set_alpha +// # channel_set_default +// # channel_set_rgb8 +// X channel_set_rgb_clipped +// # channels_fchannel +// + channels_fg_alpha +// + channels_fg_default_p +// # channels_fg_palindex_p +// + channels_fg_rgb +// + channels_fg_rgb8 +// # channels_set_bchannel +// + channels_set_bg_alpha +// + channels_set_bg_default +// # channels_set_bg_palindex +// + channels_set_bg_rgb +// + channels_set_bg_rgb8 +// X channels_set_bg_rgb8_clipped +// # channels_set_fchannel +// + channels_set_fg_alpha +// + channels_set_fg_default +// # channels_set_fg_palindex +// + channels_set_fg_rgb +// + channels_set_fg_rgb8 +// X channels_set_fg_rgb8_clipped #[cfg(test)] -mod tests; - -mod types; -pub use types::{ - NcAlphaBits, NcBlitSet, NcChannel, NcChannelPair, NcColor, NcFadeCtx, NcPalette, - NcPaletteIndex, NcPixel, NcRgb, NCCHANNEL_ALPHA_MASK, -}; - -use crate::{ - NCCELL_ALPHA_HIGHCONTRAST, NCCELL_ALPHA_OPAQUE, NCCELL_BGDEFAULT_MASK, NCCELL_BG_PALETTE, - NCCELL_BG_RGB_MASK, NCCELL_FGDEFAULT_MASK, NCCELL_FG_PALETTE, -}; - -/// Extracts the [NcColor] 8-bit red component from a 32-bit [NcChannel]. -#[inline] -pub const fn channel_r(channel: NcChannel) -> NcColor { - ((channel & 0xff0000) >> 16) as NcColor -} - -/// Extracts the [NcColor] 8-bit green component from a 32-bit [NcChannel]. -#[inline] -pub const fn channel_g(channel: NcChannel) -> NcColor { - ((channel & 0x00ff00) >> 8) as NcColor -} - -/// Extracts the [NcColor] 8-bit blue component from a 32-bit [NcChannel]. -#[inline] -pub const fn channel_b(channel: NcChannel) -> NcColor { - (channel & 0x0000ff) as NcColor -} - -/// Extracts the three [NcColor] 8-bit RGB components from a 32-bit [NcChannel]. -#[inline] -pub fn channel_rgb8( - channel: NcChannel, - r: &mut NcColor, - g: &mut NcColor, - b: &mut NcColor, -) -> NcChannel { - *r = channel_r(channel); - *g = channel_g(channel); - *b = channel_b(channel); - channel -} - -/// Sets the three [NcColor] 8-bit components of a 32-bit [NcChannel], and marks -/// it as not using the "default color". Retain the other bits unchanged. -#[inline] -pub fn channel_set_rgb8(channel: &mut NcChannel, r: NcColor, g: NcColor, b: NcColor) { - let rgb: NcRgb = (r as NcChannel) << 16 | (g as NcChannel) << 8 | (b as NcChannel); - *channel = (*channel & !NCCELL_BG_RGB_MASK) | NCCELL_BGDEFAULT_MASK | rgb; -} - -/// Sets the [NcRgb] 24-bit RGB value of a 32-bit [NcChannel], and marks it as -/// not using the "default color". Retain the other bits unchanged. -#[inline] -pub fn channel_set(channel: &mut NcChannel, rgb: NcRgb) { - *channel = (*channel & !NCCELL_BG_RGB_MASK) | NCCELL_BGDEFAULT_MASK | (rgb & 0x00ffffff); -} - -/// Extracts the [NcAlphaBits] 2-bit component from a 32-bit [NcChannel]. -#[inline] -pub fn channel_alpha(channel: NcChannel) -> NcAlphaBits { - channel & NCCHANNEL_ALPHA_MASK -} - -/// Sets the [NcAlphaBits] 2-bit component of a 32-bit [NcChannel]. -#[inline] -pub fn channel_set_alpha(channel: &mut NcChannel, alpha: NcAlphaBits) { - let alpha_clean = alpha & NCCHANNEL_ALPHA_MASK; - *channel = alpha_clean | (*channel & !NCCHANNEL_ALPHA_MASK); - - if alpha != NCCELL_ALPHA_OPAQUE { - // indicate that we are *not* using the default background color - *channel |= NCCELL_BGDEFAULT_MASK; - } -} - -/// Is this [NcChannel] using the "default color" rather than RGB/palette-indexed? -#[inline] -pub fn channel_default_p(channel: NcChannel) -> bool { - (channel & NCCELL_BGDEFAULT_MASK) == 0 -} - -/// Is this [NcChannel] using palette-indexed color rather than RGB? -#[inline] -pub fn channel_palindex_p(channel: NcChannel) -> bool { - !(channel_default_p(channel) && (channel & NCCELL_BG_PALETTE) == 0) -} - -/// Marks an [NcChannel] as using its "default color", which also marks it opaque. -#[inline] -pub fn channel_set_default(channel: &mut NcChannel) -> NcChannel { - *channel &= !(NCCELL_BGDEFAULT_MASK | NCCELL_ALPHA_HIGHCONTRAST); - *channel -} - -/// Extracts the 32-bit background [NcChannel] from a [NcChannelPair]. -#[inline] -pub fn channels_bchannel(channels: NcChannelPair) -> NcChannel { - (channels & 0xffffffff_u64) as NcChannel -} - -/// Extracts the 32-bit foreground [NcChannel] from an [NcChannelPair]. -#[inline] -pub fn channels_fchannel(channels: NcChannelPair) -> NcChannel { - channels_bchannel(channels >> 32) -} - -/// Sets the 32-bit background [NcChannel] of an [NcChannelPair]. -#[inline] -pub fn channels_set_bchannel(channels: &mut NcChannelPair, bchannel: NcChannel) -> NcChannelPair { - *channels = (*channels & 0xffffffff00000000_u64) | bchannel as u64; - *channels -} - -/// Sets the 32-bit foreground [NcChannel] of an [NcChannelPair]. -#[inline] -pub fn channels_set_fchannel(channels: &mut NcChannelPair, fchannel: NcChannel) -> NcChannelPair { - *channels = (*channels & 0xffffffff_u64) | (fchannel as u64) << 32; - *channels -} - -/// Combines two [NcChannel]s into a [NcChannelPair]. -#[inline] -pub fn channels_combine(fchannel: NcChannel, bchannel: NcChannel) -> NcChannelPair { - let mut channels: NcChannelPair = 0; - channels_set_fchannel(&mut channels, fchannel); - channels_set_bchannel(&mut channels, bchannel); - channels -} +mod test; -/// Extracts the foreground [NcRgb] 24-bit value from an [NcChannelPair], -/// shifted to LSBs. -#[inline] -pub fn channels_fg_rgb(channels: NcChannelPair) -> NcChannel { - channels_fchannel(channels) & NCCELL_BG_RGB_MASK -} +mod reimplemented; +pub use reimplemented::*; -/// Extracts the background [NcRgb] 24-bit value from an [NcChannelPair], -/// shifted to LSBs. -#[inline] -pub fn channels_bg_rgb(channels: NcChannelPair) -> NcChannel { - channels_bchannel(channels) & NCCELL_BG_RGB_MASK -} - -/// Extracts the foreground [NcAlphabits] from an [NcChannelPair], shifted to LSBs. -#[inline] -pub fn channels_fg_alpha(channels: NcChannelPair) -> NcAlphaBits { - channel_alpha(channels_fchannel(channels)) -} - -/// Extracts the background [NcAlphabits] from an [NcChannelPair], shifted to LSBs. -#[inline] -pub fn channels_bg_alpha(channels: NcChannelPair) -> NcAlphaBits { - channel_alpha(channels_bchannel(channels)) -} - -/// Extracts the foreground [NcRgb] 24-bit value from an [NcChannelPair], and -/// saves it split into three [NcColor] 8-bit components. Also returns the -/// corresponding [NcChannel] (which can have some extra bits set). -#[inline] -pub fn channels_fg_rgb8( - channels: NcChannelPair, - r: &mut NcColor, - g: &mut NcColor, - b: &mut NcColor, -) -> NcChannel { - channel_rgb8(channels_fchannel(channels), r, g, b) -} - -/// Extracts the background [NcRgb] 24-bit value from an [NcChannelPair], and -/// saves it split into three [NcColor] 8-bit components. Also returns the -/// corresponding [NcChannel] (which can have some extra bits set). -#[inline] -pub fn channels_bg_rgb8( - channels: NcChannelPair, - r: &mut NcColor, - g: &mut NcColor, - b: &mut NcColor, -) -> NcChannel { - channel_rgb8(channels_bchannel(channels), r, g, b) -} - -/// Sets the RGB [NcColor] components for the foreground [NcChannel] of an -/// [NcChannelPair] 64-bit variable, and marks it as not using the "default color". -#[inline] -pub fn channels_set_fg_rgb8(channels: &mut NcChannelPair, r: NcColor, g: NcColor, b: NcColor) { - let mut channel = channels_fchannel(*channels); - channel_set_rgb8(&mut channel, r, g, b); - *channels = (channel as u64) << 32 | *channels & 0xffffffff_u64; -} - -/// Sets the [NcRgb] 24-bit value for the foreground [NcChannel] of an -/// [NcChannelPair] 64-bit variable, and marks it as not using the "default color". -#[inline] -pub fn channels_set_fg_rgb(channels: &mut NcChannelPair, rgb: NcRgb) { - let mut channel = channels_fchannel(*channels); - channel_set(&mut channel, rgb); - *channels = (channel as u64) << 32 | *channels & 0xffffffff_u64; -} - -/// Sets the RGB [NcColor] components for the background [NcChannel] of an -/// [NcChannelPair] 64-bit variable, and marks it as not using the "default color". -#[inline] -pub fn channels_set_bg_rgb8(channels: &mut NcChannelPair, r: NcColor, g: NcColor, b: NcColor) { - let mut channel = channels_bchannel(*channels); - channel_set_rgb8(&mut channel, r, g, b); - channels_set_bchannel(channels, channel); -} - -/// Sets the [NcRgb] 24-bit value for the background [NcChannel] of an -/// [NcChannelPair] 64-bit variable, and marks it as not using the "default color". -#[inline] -pub fn channels_set_bg_rgb(channels: &mut NcChannelPair, rgb: NcRgb) { - let mut channel = channels_bchannel(*channels); - channel_set(&mut channel, rgb); - channels_set_bchannel(channels, channel); -} - -/// Sets the [NcAlphaBits] of the foreground [NcChannel] of an [NcChannelPair]. -#[inline] -pub fn channels_set_fg_alpha(channels: &mut NcChannelPair, alpha: NcAlphaBits) { - let mut channel = channels_fchannel(*channels); - channel_set_alpha(&mut channel, alpha); - *channels = (channel as NcChannelPair) << 32 | *channels & 0xffffffff_u64; -} - -/// Sets the [NcAlphaBits] of the background [NcChannel] of an [NcChannelPair]. -#[inline] -pub fn channels_set_bg_alpha(channels: &mut NcChannelPair, alpha: NcAlphaBits) { - let mut alpha_clean = alpha; - if alpha == NCCELL_ALPHA_HIGHCONTRAST { - // forbidden for background alpha, so makes it opaque - alpha_clean = NCCELL_ALPHA_OPAQUE; - } - let mut channel = channels_bchannel(*channels); - channel_set_alpha(&mut channel, alpha_clean); - channels_set_bchannel(channels, channel); -} - -/// Is the foreground of an [NcChannelPair] using the "default foreground color"? -#[inline] -pub fn channels_fg_default_p(channels: NcChannelPair) -> bool { - channel_default_p(channels_fchannel(channels)) -} +// 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 [`NcChannelPair`] +/// +/// ## Diagram +/// +/// ```txt +/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB +/// ``` +/// `type in C: channel (uint32_t)` +/// +pub type NcChannel = u32; -/// Is the foreground of an [NcChannelPair] using an [indexed][NcPaletteIndex] -/// [NcPalette][crate::NcPalette] color? -#[inline] -pub fn channels_fg_palindex_p(channels: NcChannelPair) -> bool { - channel_palindex_p(channels_fchannel(channels)) -} +/// Extract these bits to get a channel's alpha value +pub const NCCHANNEL_ALPHA_MASK: u32 = crate::bindings::bindgen::CHANNEL_ALPHA_MASK; -/// Is the background using the "default background color"? The "default -/// background color" must generally be used to take advantage of -/// terminal-effected transparency. -#[inline] -pub fn channels_bg_default_p(channels: NcChannelPair) -> bool { - channel_default_p(channels_bchannel(channels)) -} +// 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; -/// Is the background of an [NcChannelPair] using an [indexed][NcPaletteIndex] -/// [NcPalette][crate::NcPalette] color? -#[inline] -pub fn channels_bg_palindex_p(channels: NcChannelPair) -> bool { - channel_palindex_p(channels_bchannel(channels)) -} +// NcChannelPair +// +/// 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). +/// 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~ +/// NCCELL_WIDEASIAN_MASK: part of a wide glyph ↓bits view↓ ↓hex mask↓ +/// 1······· ········ ········ ········ ········ ········ ········ ········ = 8······· ········ +/// +/// NCCELL_FGDEFAULT_MASK: foreground is NOT "default color" +/// ·1······ ········ ········ ········ ········ ········ ········ ········ = 4······· ········ +/// +/// NCCELL_FG_ALPHA_MASK: foreground alpha (2bits) +/// ··11···· ········ ········ ········ ········ ········ ········ ········ = 3······· ········ +/// +/// NCCELL_FG_PALETTE: foreground uses palette index +/// ····1··· ········ ········ ········ ········ ········ ········ ········ = ·8······ ········ +/// +/// NCCELL_NOBACKGROUND_MASK: glyph is entirely foreground +/// ·····1·· ········ ········ ········ ········ ········ ········ ········ = ·4······ ········ +/// +/// reserved, must be 0 +/// ······00 ········ ········ ········ ········ ········ ········ ········ = ·3······ ········ +/// +/// NCCELL_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······· +/// +/// NCCELL_BGDEFAULT_MASK: background is NOT "default color" +/// ········ ········ ········ ········ ·1······ ········ ········ ········ = ········ 4······· +/// +/// NCCELL_BG_ALPHA_MASK: background alpha (2 bits) +/// ········ ········ ········ ········ ··11···· ········ ········ ········ = ········ 3······· +/// +/// NCCELL_BG_PALETTE: background uses palette index +/// ········ ········ ········ ········ ····1··· ········ ········ ········ = ········ ·8······ +/// +/// reserved, must be 0 +/// ········ ········ ········ ········ ·····000 ········ ········ ········ = ········ ·7······ +/// +/// NCCELL_BG_RGB_MASK: background in 3x8 RGB (rrggbb) +/// 0········ ········ ········ ········ ········11111111 11111111 11111111 = ········ ··FFFFFF +/// ``` +/// `type in C: channels (uint64_t)` +/// +/// ## `NcCell` Mask Flags +/// +/// - [`NCCELL_BGDEFAULT_MASK`][crate::NCCELL_BGDEFAULT_MASK] +/// - [`NCCELL_BG_ALPHA_MASK`][crate::NCCELL_BG_ALPHA_MASK] +/// - [`NCCELL_BG_PALETTE`][crate::NCCELL_BG_PALETTE] +/// - [`NCCELL_BG_RGB_MASK`][crate::NCCELL_BG_RGB_MASK] +/// - [`NCCELL_FGDEFAULT_MASK`][crate::NCCELL_FGDEFAULT_MASK] +/// - [`NCCELL_FG_ALPHA_MASK`][crate::NCCELL_FG_ALPHA_MASK] +/// - [`NCCELL_FG_PALETTE`][crate::NCCELL_FG_PALETTE] +/// - [`NCCELL_FG_RGB_MASK`][crate::NCCELL_FG_RGB_MASK] +/// - [`NCCELL_NOBACKGROUND_MASK`][crate::NCCELL_NOBACKGROUND_MASK] +/// - [`NCCELL_WIDEASIAN_MASK`][crate::NCCELL_WIDEASIAN_MASK] +/// +pub type NcChannelPair = u64; -/// Sets an [NcCell]'s background [NcPaletteIndex]. -/// -/// Also sets [NCCELL_BG_PALETTE] and [NCCELL_ALPHA_OPAQUE], -/// and clears out [NCCELL_BGDEFAULT_MASK]. -#[inline] -pub fn channels_set_bg_palindex(channels: &mut NcChannelPair, index: NcPaletteIndex) { - *channels |= NCCELL_BGDEFAULT_MASK as NcChannelPair; - *channels |= NCCELL_BG_PALETTE as NcChannelPair; - channels_set_bg_alpha(channels, NCCELL_ALPHA_OPAQUE); - *channels &= 0xffffffffff000000; - *channels |= index as NcChannelPair; -} +// 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` +/// +pub type NcRgb = u32; -/// Sets an [NcCell]'s foreground [NcPaletteIndex]. -/// -/// Also sets [NCCELL_FG_PALETTE] and [NCCELL_ALPHA_OPAQUE], -/// and clears out [NCCELL_FGDEFAULT_MASK]. -#[inline] -pub fn channels_set_fg_palindex(channels: &mut NcChannelPair, index: NcPaletteIndex) { - *channels |= NCCELL_FGDEFAULT_MASK; - *channels |= NCCELL_FG_PALETTE as NcChannelPair; - channels_set_fg_alpha(channels, NCCELL_ALPHA_OPAQUE); - *channels &= 0xff000000ffffffff as NcChannelPair; - *channels |= (index as NcChannelPair) << 32; -} +// NcColor +// +/// 8 bits representing a R/G/B color or alpha channel +/// +/// ## Diagram +/// +/// ```txt +/// CCCCCCCC (1 Byte) +/// ``` +/// +/// `type in C: no data type` +/// +pub type NcColor = u8; -/// Marks the foreground of an [NcChannelPair] as using its "default color", -/// and returns the new [NcChannelPair]. -#[inline] -pub fn channels_set_fg_default(channels: &mut NcChannelPair) -> NcChannelPair { - let mut channel = channels_fchannel(*channels); - channel_set_default(&mut channel); - *channels = (channel as u64) << 32 | *channels & 0xffffffff_u64; - *channels -} +/// Context for a palette fade operation +pub type NcFadeCtx = crate::bindings::bindgen::ncfadectx; -/// Marks the background of an [NcChannelPair] as using its "default color", -/// and returns the new [NcChannelPair]. -#[inline] -pub fn channels_set_bg_default(channels: &mut NcChannelPair) -> NcChannelPair { - let mut channel = channels_bchannel(*channels); - channel_set_default(&mut channel); - channels_set_bchannel(channels, channel); - *channels -} +/// the [NcEgc][crate::NcEgc] which form the various levels of a given geometry. +/// +/// If the geometry is wide, things are arranged with the rightmost side +/// increasing most quickly, i.e. it can be indexed as height arrays of +/// 1 + height glyphs. +/// i.e. The first five braille EGCs are all 0 on the left, +/// [0..4] on the right. +/// +/// `type in C: blitset (struct)` +/// +pub type NcBlitSet = crate::bindings::bindgen::blitset; diff --git a/rust/src/channel/reimplemented.rs b/rust/src/channel/reimplemented.rs new file mode 100644 index 000000000..d6e9032b7 --- /dev/null +++ b/rust/src/channel/reimplemented.rs @@ -0,0 +1,309 @@ +//! `channel*_*` reimplemented functions. + +use crate::{ + NcAlphaBits, NcChannel, NcChannelPair, NcColor, NcPaletteIndex, NcRgb, + NCCELL_ALPHA_HIGHCONTRAST, NCCELL_ALPHA_OPAQUE, NCCELL_BGDEFAULT_MASK, NCCELL_BG_PALETTE, + NCCELL_BG_RGB_MASK, NCCELL_FGDEFAULT_MASK, NCCELL_FG_PALETTE, NCCHANNEL_ALPHA_MASK, +}; + +/// Extracts the [NcColor] 8-bit red component from a 32-bit [NcChannel]. +#[inline] +pub const fn channel_r(channel: NcChannel) -> NcColor { + ((channel & 0xff0000) >> 16) as NcColor +} + +/// Extracts the [NcColor] 8-bit green component from a 32-bit [NcChannel]. +#[inline] +pub const fn channel_g(channel: NcChannel) -> NcColor { + ((channel & 0x00ff00) >> 8) as NcColor +} + +/// Extracts the [NcColor] 8-bit blue component from a 32-bit [NcChannel]. +#[inline] +pub const fn channel_b(channel: NcChannel) -> NcColor { + (channel & 0x0000ff) as NcColor +} + +/// Extracts the three [NcColor] 8-bit RGB components from a 32-bit [NcChannel]. +#[inline] +pub fn channel_rgb8( + channel: NcChannel, + r: &mut NcColor, + g: &mut NcColor, + b: &mut NcColor, +) -> NcChannel { + *r = channel_r(channel); + *g = channel_g(channel); + *b = channel_b(channel); + channel +} + +/// Sets the three [NcColor] 8-bit components of a 32-bit [NcChannel], and marks +/// it as not using the "default color". Retain the other bits unchanged. +#[inline] +pub fn channel_set_rgb8(channel: &mut NcChannel, r: NcColor, g: NcColor, b: NcColor) { + let rgb: NcRgb = (r as NcChannel) << 16 | (g as NcChannel) << 8 | (b as NcChannel); + *channel = (*channel & !NCCELL_BG_RGB_MASK) | NCCELL_BGDEFAULT_MASK | rgb; +} + +/// Sets the [NcRgb] 24-bit RGB value of a 32-bit [NcChannel], and marks it as +/// not using the "default color". Retain the other bits unchanged. +#[inline] +pub fn channel_set(channel: &mut NcChannel, rgb: NcRgb) { + *channel = (*channel & !NCCELL_BG_RGB_MASK) | NCCELL_BGDEFAULT_MASK | (rgb & 0x00ffffff); +} + +/// Extracts the [NcAlphaBits] 2-bit component from a 32-bit [NcChannel]. +#[inline] +pub fn channel_alpha(channel: NcChannel) -> NcAlphaBits { + channel & NCCHANNEL_ALPHA_MASK +} + +/// Sets the [NcAlphaBits] 2-bit component of a 32-bit [NcChannel]. +#[inline] +pub fn channel_set_alpha(channel: &mut NcChannel, alpha: NcAlphaBits) { + let alpha_clean = alpha & NCCHANNEL_ALPHA_MASK; + *channel = alpha_clean | (*channel & !NCCHANNEL_ALPHA_MASK); + + if alpha != NCCELL_ALPHA_OPAQUE { + // indicate that we are *not* using the default background color + *channel |= NCCELL_BGDEFAULT_MASK; + } +} + +/// Is this [NcChannel] using the "default color" rather than RGB/palette-indexed? +#[inline] +pub fn channel_default_p(channel: NcChannel) -> bool { + (channel & NCCELL_BGDEFAULT_MASK) == 0 +} + +/// Is this [NcChannel] using palette-indexed color rather than RGB? +#[inline] +pub fn channel_palindex_p(channel: NcChannel) -> bool { + !(channel_default_p(channel) && (channel & NCCELL_BG_PALETTE) == 0) +} + +/// Marks an [NcChannel] as using its "default color", which also marks it opaque. +#[inline] +pub fn channel_set_default(channel: &mut NcChannel) -> NcChannel { + *channel &= !(NCCELL_BGDEFAULT_MASK | NCCELL_ALPHA_HIGHCONTRAST); + *channel +} + +/// Extracts the 32-bit background [NcChannel] from a [NcChannelPair]. +#[inline] +pub fn channels_bchannel(channels: NcChannelPair) -> NcChannel { + (channels & 0xffffffff_u64) as NcChannel +} + +/// Extracts the 32-bit foreground [NcChannel] from an [NcChannelPair]. +#[inline] +pub fn channels_fchannel(channels: NcChannelPair) -> NcChannel { + channels_bchannel(channels >> 32) +} + +/// Sets the 32-bit background [NcChannel] of an [NcChannelPair]. +#[inline] +pub fn channels_set_bchannel(channels: &mut NcChannelPair, bchannel: NcChannel) -> NcChannelPair { + *channels = (*channels & 0xffffffff00000000_u64) | bchannel as u64; + *channels +} + +/// Sets the 32-bit foreground [NcChannel] of an [NcChannelPair]. +#[inline] +pub fn channels_set_fchannel(channels: &mut NcChannelPair, fchannel: NcChannel) -> NcChannelPair { + *channels = (*channels & 0xffffffff_u64) | (fchannel as u64) << 32; + *channels +} + +/// Combines two [NcChannel]s into a [NcChannelPair]. +#[inline] +pub fn channels_combine(fchannel: NcChannel, bchannel: NcChannel) -> NcChannelPair { + let mut channels: NcChannelPair = 0; + channels_set_fchannel(&mut channels, fchannel); + channels_set_bchannel(&mut channels, bchannel); + channels +} + +/// Extracts the foreground [NcRgb] 24-bit value from an [NcChannelPair], +/// shifted to LSBs. +#[inline] +pub fn channels_fg_rgb(channels: NcChannelPair) -> NcChannel { + channels_fchannel(channels) & NCCELL_BG_RGB_MASK +} + +/// Extracts the background [NcRgb] 24-bit value from an [NcChannelPair], +/// shifted to LSBs. +#[inline] +pub fn channels_bg_rgb(channels: NcChannelPair) -> NcChannel { + channels_bchannel(channels) & NCCELL_BG_RGB_MASK +} + +/// Extracts the foreground [NcAlphabits] from an [NcChannelPair], shifted to LSBs. +#[inline] +pub fn channels_fg_alpha(channels: NcChannelPair) -> NcAlphaBits { + channel_alpha(channels_fchannel(channels)) +} + +/// Extracts the background [NcAlphabits] from an [NcChannelPair], shifted to LSBs. +#[inline] +pub fn channels_bg_alpha(channels: NcChannelPair) -> NcAlphaBits { + channel_alpha(channels_bchannel(channels)) +} + +/// Extracts the foreground [NcRgb] 24-bit value from an [NcChannelPair], and +/// saves it split into three [NcColor] 8-bit components. Also returns the +/// corresponding [NcChannel] (which can have some extra bits set). +#[inline] +pub fn channels_fg_rgb8( + channels: NcChannelPair, + r: &mut NcColor, + g: &mut NcColor, + b: &mut NcColor, +) -> NcChannel { + channel_rgb8(channels_fchannel(channels), r, g, b) +} + +/// Extracts the background [NcRgb] 24-bit value from an [NcChannelPair], and +/// saves it split into three [NcColor] 8-bit components. Also returns the +/// corresponding [NcChannel] (which can have some extra bits set). +#[inline] +pub fn channels_bg_rgb8( + channels: NcChannelPair, + r: &mut NcColor, + g: &mut NcColor, + b: &mut NcColor, +) -> NcChannel { + channel_rgb8(channels_bchannel(channels), r, g, b) +} + +/// Sets the RGB [NcColor] components for the foreground [NcChannel] of an +/// [NcChannelPair] 64-bit variable, and marks it as not using the "default color". +#[inline] +pub fn channels_set_fg_rgb8(channels: &mut NcChannelPair, r: NcColor, g: NcColor, b: NcColor) { + let mut channel = channels_fchannel(*channels); + channel_set_rgb8(&mut channel, r, g, b); + *channels = (channel as u64) << 32 | *channels & 0xffffffff_u64; +} + +/// Sets the [NcRgb] 24-bit value for the foreground [NcChannel] of an +/// [NcChannelPair] 64-bit variable, and marks it as not using the "default color". +#[inline] +pub fn channels_set_fg_rgb(channels: &mut NcChannelPair, rgb: NcRgb) { + let mut channel = channels_fchannel(*channels); + channel_set(&mut channel, rgb); + *channels = (channel as u64) << 32 | *channels & 0xffffffff_u64; +} + +/// Sets the RGB [NcColor] components for the background [NcChannel] of an +/// [NcChannelPair] 64-bit variable, and marks it as not using the "default color". +#[inline] +pub fn channels_set_bg_rgb8(channels: &mut NcChannelPair, r: NcColor, g: NcColor, b: NcColor) { + let mut channel = channels_bchannel(*channels); + channel_set_rgb8(&mut channel, r, g, b); + channels_set_bchannel(channels, channel); +} + +/// Sets the [NcRgb] 24-bit value for the background [NcChannel] of an +/// [NcChannelPair] 64-bit variable, and marks it as not using the "default color". +#[inline] +pub fn channels_set_bg_rgb(channels: &mut NcChannelPair, rgb: NcRgb) { + let mut channel = channels_bchannel(*channels); + channel_set(&mut channel, rgb); + channels_set_bchannel(channels, channel); +} + +/// Sets the [NcAlphaBits] of the foreground [NcChannel] of an [NcChannelPair]. +#[inline] +pub fn channels_set_fg_alpha(channels: &mut NcChannelPair, alpha: NcAlphaBits) { + let mut channel = channels_fchannel(*channels); + channel_set_alpha(&mut channel, alpha); + *channels = (channel as NcChannelPair) << 32 | *channels & 0xffffffff_u64; +} + +/// Sets the [NcAlphaBits] of the background [NcChannel] of an [NcChannelPair]. +#[inline] +pub fn channels_set_bg_alpha(channels: &mut NcChannelPair, alpha: NcAlphaBits) { + let mut alpha_clean = alpha; + if alpha == NCCELL_ALPHA_HIGHCONTRAST { + // forbidden for background alpha, so makes it opaque + alpha_clean = NCCELL_ALPHA_OPAQUE; + } + let mut channel = channels_bchannel(*channels); + channel_set_alpha(&mut channel, alpha_clean); + channels_set_bchannel(channels, channel); +} + +/// Is the foreground of an [NcChannelPair] using the "default foreground color"? +#[inline] +pub fn channels_fg_default_p(channels: NcChannelPair) -> bool { + channel_default_p(channels_fchannel(channels)) +} + +/// Is the foreground of an [NcChannelPair] using an [indexed][NcPaletteIndex] +/// [NcPalette][crate::NcPalette] color? +#[inline] +pub fn channels_fg_palindex_p(channels: NcChannelPair) -> bool { + channel_palindex_p(channels_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. +#[inline] +pub fn channels_bg_default_p(channels: NcChannelPair) -> bool { + channel_default_p(channels_bchannel(channels)) +} + +/// Is the background of an [NcChannelPair] using an [indexed][NcPaletteIndex] +/// [NcPalette][crate::NcPalette] color? +#[inline] +pub fn channels_bg_palindex_p(channels: NcChannelPair) -> bool { + channel_palindex_p(channels_bchannel(channels)) +} + +/// Sets an [NcCell]'s background [NcPaletteIndex]. +/// +/// Also sets [NCCELL_BG_PALETTE] and [NCCELL_ALPHA_OPAQUE], +/// and clears out [NCCELL_BGDEFAULT_MASK]. +#[inline] +pub fn channels_set_bg_palindex(channels: &mut NcChannelPair, index: NcPaletteIndex) { + *channels |= NCCELL_BGDEFAULT_MASK as NcChannelPair; + *channels |= NCCELL_BG_PALETTE as NcChannelPair; + channels_set_bg_alpha(channels, NCCELL_ALPHA_OPAQUE); + *channels &= 0xffffffffff000000; + *channels |= index as NcChannelPair; +} + +/// Sets an [NcCell]'s foreground [NcPaletteIndex]. +/// +/// Also sets [NCCELL_FG_PALETTE] and [NCCELL_ALPHA_OPAQUE], +/// and clears out [NCCELL_FGDEFAULT_MASK]. +#[inline] +pub fn channels_set_fg_palindex(channels: &mut NcChannelPair, index: NcPaletteIndex) { + *channels |= NCCELL_FGDEFAULT_MASK; + *channels |= NCCELL_FG_PALETTE as NcChannelPair; + channels_set_fg_alpha(channels, NCCELL_ALPHA_OPAQUE); + *channels &= 0xff000000ffffffff as NcChannelPair; + *channels |= (index as NcChannelPair) << 32; +} + +/// Marks the foreground of an [NcChannelPair] as using its "default color", +/// and returns the new [NcChannelPair]. +#[inline] +pub fn channels_set_fg_default(channels: &mut NcChannelPair) -> NcChannelPair { + let mut channel = channels_fchannel(*channels); + channel_set_default(&mut channel); + *channels = (channel as u64) << 32 | *channels & 0xffffffff_u64; + *channels +} + +/// Marks the background of an [NcChannelPair] as using its "default color", +/// and returns the new [NcChannelPair]. +#[inline] +pub fn channels_set_bg_default(channels: &mut NcChannelPair) -> NcChannelPair { + let mut channel = channels_bchannel(*channels); + channel_set_default(&mut channel); + channels_set_bchannel(channels, channel); + *channels +} diff --git a/rust/src/channel/test/methods.rs b/rust/src/channel/test/methods.rs new file mode 100644 index 000000000..4e8653ab1 --- /dev/null +++ b/rust/src/channel/test/methods.rs @@ -0,0 +1,10 @@ +//! Test `NcChannel*` methods and associated functions. + +// use crate::{NcChannel, NcChannelPair}; +// +// use serial_test::serial; +// +// #[test] +// #[serial] +// fn () { +// } diff --git a/rust/src/channel/test/mod.rs b/rust/src/channel/test/mod.rs new file mode 100644 index 000000000..99466243e --- /dev/null +++ b/rust/src/channel/test/mod.rs @@ -0,0 +1,7 @@ +//! `NcChannel*` tests. + +#[cfg(test)] +mod methods; + +#[cfg(test)] +mod reimplemented; diff --git a/rust/src/channel/tests.rs b/rust/src/channel/test/reimplemented.rs similarity index 98% rename from rust/src/channel/tests.rs rename to rust/src/channel/test/reimplemented.rs index d9de9a3a0..837c08f28 100644 --- a/rust/src/channel/tests.rs +++ b/rust/src/channel/test/reimplemented.rs @@ -1,12 +1,12 @@ -//! [`NcChannel`] & [`NcChannelPair`] tests +//! Test `channel*_*` reimplemented functions. + +use serial_test::serial; use crate::{ NcChannel, NcChannelPair, NCCELL_ALPHA_BLEND, NCCELL_ALPHA_HIGHCONTRAST, NCCELL_ALPHA_OPAQUE, NCCELL_ALPHA_TRANSPARENT, }; -use serial_test::serial; - #[test] #[serial] fn channel_r() { diff --git a/rust/src/channel/types.rs b/rust/src/channel/types.rs deleted file mode 100644 index 1b78e8592..000000000 --- a/rust/src/channel/types.rs +++ /dev/null @@ -1,211 +0,0 @@ -#[allow(unused_imports)] // for docblocks -use crate::NcChar; - -// 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 [`NcChannelPair`] -/// -/// ## Diagram -/// -/// ```txt -/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB -/// ``` -/// `type in C: channel (uint32_t)` -/// -pub type NcChannel = u32; - -/// Extract these bits to get a channel's alpha value -pub const NCCHANNEL_ALPHA_MASK: u32 = crate::bindings::bindgen::CHANNEL_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; - -// NcChannelPair -// -/// 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). -/// 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~ -/// NCCELL_WIDEASIAN_MASK: part of a wide glyph ↓bits view↓ ↓hex mask↓ -/// 1······· ········ ········ ········ ········ ········ ········ ········ = 8······· ········ -/// -/// NCCELL_FGDEFAULT_MASK: foreground is NOT "default color" -/// ·1······ ········ ········ ········ ········ ········ ········ ········ = 4······· ········ -/// -/// NCCELL_FG_ALPHA_MASK: foreground alpha (2bits) -/// ··11···· ········ ········ ········ ········ ········ ········ ········ = 3······· ········ -/// -/// NCCELL_FG_PALETTE: foreground uses palette index -/// ····1··· ········ ········ ········ ········ ········ ········ ········ = ·8······ ········ -/// -/// NCCELL_NOBACKGROUND_MASK: glyph is entirely foreground -/// ·····1·· ········ ········ ········ ········ ········ ········ ········ = ·4······ ········ -/// -/// reserved, must be 0 -/// ······00 ········ ········ ········ ········ ········ ········ ········ = ·3······ ········ -/// -/// NCCELL_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······· -/// -/// NCCELL_BGDEFAULT_MASK: background is NOT "default color" -/// ········ ········ ········ ········ ·1······ ········ ········ ········ = ········ 4······· -/// -/// NCCELL_BG_ALPHA_MASK: background alpha (2 bits) -/// ········ ········ ········ ········ ··11···· ········ ········ ········ = ········ 3······· -/// -/// NCCELL_BG_PALETTE: background uses palette index -/// ········ ········ ········ ········ ····1··· ········ ········ ········ = ········ ·8······ -/// -/// reserved, must be 0 -/// ········ ········ ········ ········ ·····000 ········ ········ ········ = ········ ·7······ -/// -/// NCCELL_BG_RGB_MASK: background in 3x8 RGB (rrggbb) -/// 0········ ········ ········ ········ ········11111111 11111111 11111111 = ········ ··FFFFFF -/// ``` -/// `type in C: channels (uint64_t)` -/// -/// ## `NcCell` Mask Flags -/// -/// - [`NCCELL_BGDEFAULT_MASK`][crate::NCCELL_BGDEFAULT_MASK] -/// - [`NCCELL_BG_ALPHA_MASK`][crate::NCCELL_BG_ALPHA_MASK] -/// - [`NCCELL_BG_PALETTE`][crate::NCCELL_BG_PALETTE] -/// - [`NCCELL_BG_RGB_MASK`][crate::NCCELL_BG_RGB_MASK] -/// - [`NCCELL_FGDEFAULT_MASK`][crate::NCCELL_FGDEFAULT_MASK] -/// - [`NCCELL_FG_ALPHA_MASK`][crate::NCCELL_FG_ALPHA_MASK] -/// - [`NCCELL_FG_PALETTE`][crate::NCCELL_FG_PALETTE] -/// - [`NCCELL_FG_RGB_MASK`][crate::NCCELL_FG_RGB_MASK] -/// - [`NCCELL_NOBACKGROUND_MASK`][crate::NCCELL_NOBACKGROUND_MASK] -/// - [`NCCELL_WIDEASIAN_MASK`][crate::NCCELL_WIDEASIAN_MASK] -/// -pub type NcChannelPair = u64; - -// 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` -/// -pub type NcRgb = u32; - -// NcColor -// -/// 8 bits representing a R/G/B color or alpha channel -/// -/// ## Diagram -/// -/// ```txt -/// CCCCCCCC (1 Byte) -/// ``` -/// -/// `type in C: no data type` -/// -pub type NcColor = u8; - -// NcPixel (RGBA) -/// 32 bits broken into RGB + 8-bit alpha -/// -/// 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 -/// -/// ## Diagram -/// -/// ```txt -/// AAAAAAAA GGGGGGGG BBBBBBBB RRRRRRRR -/// ``` -/// `type in C: ncpixel (uint32_t)` -/// -// NOTE: the order of the colors is different than in NcChannel. -pub type NcPixel = u32; - -/// NcPalette structure consisting of an array of 256 [`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: ncpalette256 (struct)` -/// -pub type NcPalette = crate::bindings::bindgen::palette256; - -/// 8-bit value used for indexing into a [`NcPalette`] -/// -pub type NcPaletteIndex = u8; - -/// Context for a palette fade operation -pub type NcFadeCtx = crate::bindings::bindgen::ncfadectx; - -/// the [`NcChar`] which form the various levels -/// of a given geometry. -/// -/// If the geometry is wide, things are arranged with the rightmost side -/// increasing most quickly, i.e. it can be indexed as height arrays of -/// 1 + height glyphs. -/// i.e. The first five braille EGCs are all 0 on the left, -/// [0..4] on the right. -/// -/// `type in C: blitset (struct)` -/// -pub type NcBlitSet = crate::bindings::bindgen::blitset; diff --git a/rust/src/direct/wrapped.rs b/rust/src/direct/methods.rs similarity index 83% rename from rust/src/direct/wrapped.rs rename to rust/src/direct/methods.rs index 49fe48705..e1f9767c3 100644 --- a/rust/src/direct/wrapped.rs +++ b/rust/src/direct/methods.rs @@ -1,3 +1,5 @@ +//! `NcDirect` methods and associated functions. + use crate::{ncdirect_init, NcDirect, NcDirectFlags}; use core::ptr::{null, null_mut}; @@ -26,9 +28,9 @@ impl NcDirect { } } -// Explicitly implementing both `Drop` and `Copy` trait on a type is currently -// disallowed (rustc --explain E0184) -// https://github.com/rust-lang/rust/issues/20126 +// NOTE: Explicitly implementing both `Drop` and `Copy` trait on a type is +// currently disallowed (rustc --explain E0184) +// See: https://github.com/rust-lang/rust/issues/20126 // // impl Drop for NcDirect { // fn drop(&mut self) { diff --git a/rust/src/direct/mod.rs b/rust/src/direct/mod.rs index 527e82025..76c6233e7 100644 --- a/rust/src/direct/mod.rs +++ b/rust/src/direct/mod.rs @@ -1,53 +1,74 @@ +//! `NcDirect` + // functions already exported by bindgen : 38 -// ------------------------------------------ (done / remaining) -// (#) unit tests: 0 / 38 // ------------------------------------------ -// ncdirect_bg_default -// ncdirect_bg_palindex -// ncdirect_bg_rgb -// ncdirect_box -// ncdirect_canopen_images -// ncdirect_canutf8 -// ncdirect_clear -// 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_dim_x -// ncdirect_dim_y -// ncdirect_double_box -// ncdirect_fg_default -// ncdirect_fg_palindex -// ncdirect_fg_rgb -// ncdirect_flush -// ncdirect_getc -// ncdirect_hline_interp -// ncdirect_init // wrapped at _new() & _with_flags() -// ncdirect_inputready_fd -// ncdirect_palette_size -// ncdirect_printf_aligned -// ncdirect_putstr -// ncdirect_render_image -// ncdirect_rounded_box -// ncdirect_stop -// ncdirect_styles_off -// ncdirect_styles_on -// ncdirect_styles_set -// ncdirect_vline_interp +// (W) wrap: 1 / 37 +// (#) test: 0 / 38 +// ------------------------------------------ +// ncdirect_bg_default +// ncdirect_bg_palindex +// ncdirect_bg_rgb +// ncdirect_box +// ncdirect_canopen_images +// ncdirect_canutf8 +// ncdirect_clear +// 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_dim_x +// ncdirect_dim_y +// ncdirect_double_box +// ncdirect_fg_default +// ncdirect_fg_palindex +// ncdirect_fg_rgb +// ncdirect_flush +// ncdirect_getc +// ncdirect_hline_interp +//W ncdirect_init +// ncdirect_inputready_fd +// ncdirect_palette_size +// ncdirect_printf_aligned +// ncdirect_putstr +// ncdirect_render_image +// ncdirect_rounded_box +// ncdirect_stop +// ncdirect_styles_off +// ncdirect_styles_on +// ncdirect_styles_set +// ncdirect_vline_interp #[cfg(test)] -mod tests; +mod test; + +mod methods; + +/// Minimal notcurses instances for styling text +pub type NcDirect = crate::bindings::bindgen::ncdirect; + +/// Flags (options) for [`NcDirect`] +pub type NcDirectFlags = u64; -mod types; -pub use types::{ - NcDirect, NcDirectFlags, NCDIRECT_OPTION_INHIBIT_CBREAK, NCDIRECT_OPTION_INHIBIT_SETLOCALE, -}; +/// Flag that avoids placing the terminal into cbreak mode +/// (disabling echo and line buffering) +/// +pub const NCDIRECT_OPTION_INHIBIT_CBREAK: NcDirectFlags = + crate::bindings::bindgen::NCDIRECT_OPTION_INHIBIT_CBREAK as NcDirectFlags; -mod wrapped; -pub use wrapped::*; +/// 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::bindgen::NCDIRECT_OPTION_INHIBIT_SETLOCALE as NcDirectFlags; diff --git a/rust/src/direct/tests.rs b/rust/src/direct/test/mod.rs similarity index 100% rename from rust/src/direct/tests.rs rename to rust/src/direct/test/mod.rs diff --git a/rust/src/direct/types.rs b/rust/src/direct/types.rs deleted file mode 100644 index 99cfc218c..000000000 --- a/rust/src/direct/types.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Types related with `NcDirect` - -/// Minimal notcurses instances for styling text -pub type NcDirect = crate::bindings::bindgen::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::bindgen::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::bindgen::NCDIRECT_OPTION_INHIBIT_SETLOCALE as NcDirectFlags; diff --git a/rust/src/input.rs b/rust/src/input.rs index 81be83475..21cbb0776 100644 --- a/rust/src/input.rs +++ b/rust/src/input.rs @@ -1,12 +1,11 @@ -// functions already exported by bindgen : 0 -// ----------------------------------------- -// -// static inline functions total: 1 -// ------------------------------------------ (done / remaining) +//! `NcInput` + +// functions manually reimplemented: 1 +// ------------------------------------------ // (+) done: 1 / 0 // (#) test: 0 / 1 // ------------------------------------------ -//+ ncinput_equal_p +// + ncinput_equal_p /// Reads and decodes input events /// @@ -16,7 +15,7 @@ /// To exit, generate EOF (usually Ctrl+‘d’). pub type NcInput = crate::bindings::bindgen::ncinput; -/// Compare two ncinput structs for data equality by doing a field-by-field +/// 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. @@ -31,6 +30,7 @@ pub fn ncinput_equal_p(n1: NcInput, n2: NcInput) -> bool { true } +/// New `NcInput`. impl NcInput { pub fn new() -> NcInput { NcInput { diff --git a/rust/src/key.rs b/rust/src/key.rs index 66a34029e..66101f6e9 100644 --- a/rust/src/key.rs +++ b/rust/src/key.rs @@ -1,13 +1,10 @@ -// functions already exported by bindgen : 0 +// functions manually reimplemented: 2 // ------------------------------------------ -// -// static inline functions total: 2 -// ------------------------------------------ (done / remaining) // (+) done: 2 / 0 // (#) test: 0 / 2 // ------------------------------------------ -//+ nckey_mouse_p -//+ nckey_supppuab_p +// + nckey_mouse_p +// + nckey_supppuab_p use crate::{NCKEY_BUTTON1, NCKEY_RELEASE}; @@ -26,15 +23,3 @@ pub fn nckey_supppuab_p(w: u32) -> bool { pub fn nckey_mouse_p(r: u32) -> bool { r >= NCKEY_BUTTON1 && r <= NCKEY_RELEASE } - -#[cfg(test)] -mod test { - // use super::nc; - // use serial_test::serial; - /* - #[test] - #[serial] - fn () { - } - */ -} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 3486d437a..c6da6d301 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -17,7 +17,6 @@ #![allow(non_upper_case_globals, non_camel_case_types, non_snake_case)] #![allow(clippy::too_many_arguments)] - mod bindings; #[doc(inline)] pub use bindings::*; diff --git a/rust/src/macros.rs b/rust/src/macros.rs index 9d86c4415..0faeb2736 100644 --- a/rust/src/macros.rs +++ b/rust/src/macros.rs @@ -1,5 +1,7 @@ //! Macros +// General Utility Macros ------------------------------------------------------ + /// Sleeps for $ms milliseconds #[macro_export] macro_rules! sleep { @@ -13,5 +15,5 @@ macro_rules! sleep { macro_rules! cstring { ($s:expr) => { std::ffi::CString::new($s).unwrap().as_ptr(); - } + }; } diff --git a/rust/src/notcurses/wrapped.rs b/rust/src/notcurses/methods.rs similarity index 80% rename from rust/src/notcurses/wrapped.rs rename to rust/src/notcurses/methods.rs index 8a56c15cc..6fc55ae34 100644 --- a/rust/src/notcurses/wrapped.rs +++ b/rust/src/notcurses/methods.rs @@ -1,4 +1,4 @@ -//! Handy [`Notcurses`] and [`NotcursesOptions`] constructors +//! `Notcurses*` methods and associated functions. use core::ptr::{null, null_mut}; @@ -7,7 +7,8 @@ use crate::{ NCOPTION_SUPPRESS_BANNERS, }; use crate::{ - notcurses_stdplane, NcPlane, notcurses_stop, NcResult, notcurses_render, + notcurses_render, notcurses_stdplane, notcurses_stdplane_const, notcurses_stop, NcPlane, + NcResult, }; /// # `NotcursesOptions` Constructors @@ -113,21 +114,34 @@ impl Notcurses { /// # `Notcurses` methods impl Notcurses { + // reference, ... I need an NcPlane from this... + // pub fn stdplane_mut2(&mut self) -> *mut NcPlane { + // unsafe { notcurses_stdplane(self) } + // } - /// - pub fn stdplane_mut(&mut self) -> NcPlane { - unsafe { *notcurses_stdplane(self) } - //notcurses_stdplane_const //??? + /// 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. + pub fn stdplane_mut<'a>(&mut self) -> &'a mut NcPlane { + unsafe { &mut *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. + pub fn stdplane<'a>(&self) -> &'a NcPlane { + unsafe { &*notcurses_stdplane_const(self) } } - /// + /// pub fn stop(&mut self) -> NcResult { unsafe { notcurses_stop(self) } } - /// + /// pub fn render(&mut self) -> NcResult { unsafe { notcurses_render(self) } } - } diff --git a/rust/src/notcurses/mod.rs b/rust/src/notcurses/mod.rs index c3e67c956..5971cd02a 100644 --- a/rust/src/notcurses/mod.rs +++ b/rust/src/notcurses/mod.rs @@ -1,159 +1,173 @@ +//! `Notcurses` + // functions already exported by bindgen : 39 -// ----------------------------------------- (done / remaining) +// ------------------------------------------ // (#) unit tests: 10 / 29 // ------------------------------------------ -// notcurses_at_yx -// notcurses_bottom -//# notcurses_canchangecolor -//# notcurses_canfade -//# notcurses_canopen_images -//# notcurses_canopen_videos -//# notcurses_cansixel -//# notcurses_cantruecolor -//# notcurses_canutf8 -// notcurses_cursor_disable -// notcurses_cursor_enable -//# notcurses_debug -//# notcurses_drop_planes -// notcurses_getc -//# notcurses_init -// notcurses_inputready_fd -// notcurses_lex_blitter -// notcurses_lex_margins -// notcurses_lex_scalemode -// 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 +// notcurses_at_yx +// notcurses_bottom +// # notcurses_canchangecolor +// # notcurses_canfade +// # notcurses_canopen_images +// # notcurses_canopen_videos +// # notcurses_cansixel +// # notcurses_cantruecolor +// # notcurses_canutf8 +// notcurses_cursor_disable +// notcurses_cursor_enable +// # notcurses_debug +// # notcurses_drop_planes +// notcurses_getc +// # notcurses_init +// notcurses_inputready_fd +// notcurses_lex_blitter +// notcurses_lex_margins +// notcurses_lex_scalemode +// 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 // -// static inline functions total: 6 -// ----------------------------------------- (done / remaining) +// functions manually reimplemented: 6 +// ----------------------------------------- // (+) implement : 6 / 0 // (#) unit tests: 0 / 6 // ----------------------------------------- -//# notcurses_align -//+ notcurses_getc_blocking -//+ notcurses_getc_nblock -//+ notcurses_stddim_yx -//+ notcurses_stddim_yx_const -//+ notcurses_term_dim_yx +// # notcurses_align +// + notcurses_getc_blocking +// + notcurses_getc_nblock +// + notcurses_stddim_yx +// + notcurses_stddim_yx_const +// + notcurses_term_dim_yx #[cfg(test)] -mod tests; - -mod types; -pub use types::{ - NcLogLevel, Notcurses, NotcursesOptions, NCLOGLEVEL_DEBUG, NCLOGLEVEL_ERROR, NCLOGLEVEL_FATAL, - NCLOGLEVEL_INFO, NCLOGLEVEL_PANIC, NCLOGLEVEL_SILENT, NCLOGLEVEL_TRACE, NCLOGLEVEL_VERBOSE, - NCLOGLEVEL_WARNING, NCOPTION_INHIBIT_SETLOCALE, NCOPTION_NO_ALTERNATE_SCREEN, - NCOPTION_NO_FONT_CHANGES, NCOPTION_NO_QUIT_SIGHANDLERS, NCOPTION_NO_WINCH_SIGHANDLER, - NCOPTION_SUPPRESS_BANNERS, NCOPTION_VERIFY_SIXEL, -}; - -mod wrapped; -pub use wrapped::*; - -use core::ptr::null; - -use crate::{ - // NOTE: can't use libc::sigset_t with notcurses_getc(() - bindings::{sigemptyset, sigfillset, sigset_t}, - ncplane_dim_yx, - notcurses_getc, - notcurses_stdplane, - notcurses_stdplane_const, - NcAlign, - NcInput, - NcPlane, - NcTime, - NCALIGN_CENTER, - NCALIGN_LEFT, -}; - -/// return the offset into 'availcols' at which 'cols' ought be output given the requirements of 'align' -#[inline] -pub fn notcurses_align(availcols: i32, align: NcAlign, cols: i32) -> i32 { - if align == NCALIGN_LEFT { - return 0; - } - if cols > availcols { - return 0; - } - if align == NCALIGN_CENTER { - return (availcols - cols) / 2; - } - availcols - cols // NCALIGN_RIGHT -} - -/// 'input' may be NULL if the caller is uninterested in event details. -/// If no event is ready, returns 0. -// TODO: use pakr-signals -#[inline] -pub fn notcurses_getc_nblock(nc: &mut Notcurses, input: &mut NcInput) -> char { - unsafe { - let mut sigmask = sigset_t { __val: [0; 16] }; - sigfillset(&mut sigmask); - let ts = NcTime { - tv_sec: 0, - tv_nsec: 0, - }; - core::char::from_u32_unchecked(notcurses_getc(nc, &ts, &mut sigmask, input)) - } -} - -/// 'input' may be NULL if the caller is uninterested in event details. -/// Blocks until an event is processed or a signal is received. -#[inline] -pub fn notcurses_getc_nblocking(nc: &mut Notcurses, input: &mut NcInput) -> char { - unsafe { - let mut sigmask = sigset_t { __val: [0; 16] }; - sigemptyset(&mut sigmask); - core::char::from_u32_unchecked(notcurses_getc(nc, null(), &mut sigmask, input)) - } -} - -/// notcurses_stdplane(), plus free bonus dimensions written to non-NULL y/x! -#[inline] -pub fn notcurses_stddim_yx(nc: &mut Notcurses, y: &mut i32, x: &mut i32) -> NcPlane { - unsafe { - let s = notcurses_stdplane(nc); - ncplane_dim_yx(s, y, x); - *s - } -} - -/// notcurses_stdplane_const(), plus free bonus dimensions written to non-NULL y/x! -#[inline] -pub fn notcurses_stddim_yx_const(nc: &Notcurses, y: &mut i32, x: &mut i32) -> NcPlane { - unsafe { - let s = notcurses_stdplane_const(nc); - ncplane_dim_yx(s, y, x); - *s - } -} - -/// Return our current idea of the terminal dimensions in rows and cols. -#[inline] -pub fn notcurses_term_dim_yx(nc: &Notcurses, rows: &mut u32, cols: &mut u32) { - unsafe { - let mut irows = *rows as i32; - let mut icols = *cols as i32; - ncplane_dim_yx(notcurses_stdplane_const(nc), &mut irows, &mut icols); - } -} +mod test; + +mod methods; +mod reimplemented; +pub use reimplemented::*; + +/// The main struct of the (full mode) TUI library +/// +/// Notcurses builds atop the terminfo abstraction layer to +/// provide reasonably portable vivid character displays. +/// +pub type Notcurses = crate::bindings::bindgen::notcurses; + +/// Options struct for [`Notcurses`] +pub type NotcursesOptions = crate::bindings::bindgen::notcurses_options; + +/// 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::bindgen::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::bindgen::NCOPTION_NO_ALTERNATE_SCREEN 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::bindgen::NCOPTION_NO_FONT_CHANGES as u64; + +/// Do not handle SIG{ING, SEGV, ABRT, QUIT} +/// +/// We typically install a signal handler for SIG{INT, SEGV, ABRT, QUIT} that +/// restores the screen, and then calls the old signal handler. Set to inhibit +/// registration of these signal handlers. +pub const NCOPTION_NO_QUIT_SIGHANDLERS: u64 = + crate::bindings::bindgen::NCOPTION_NO_QUIT_SIGHANDLERS as u64; + +/// Do not handle SIGWINCH +/// +/// We typically install a signal handler for SIGWINCH that generates a resize +/// event in the notcurses_getc() queue. Set to inhibit this handler +pub const NCOPTION_NO_WINCH_SIGHANDLER: u64 = + crate::bindings::bindgen::NCOPTION_NO_WINCH_SIGHANDLER 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::bindgen::NCOPTION_SUPPRESS_BANNERS as u64; + +/// Test for Sixel support +/// +/// Checking for Sixel support requires writing an escape, and then reading an +/// inline reply from the terminal. Since this can interact poorly with actual +/// user input, it's not done unless Sixel will actually be used. Set this flag +/// to unconditionally test for Sixel support in notcurses_init(). +pub const NCOPTION_VERIFY_SIXEL: u64 = crate::bindings::bindgen::NCOPTION_VERIFY_SIXEL as u64; + +// NcLogLevel ------------------------------------------------------------------ + +/// Log level for [`NotcursesOptions`] +/// +/// 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 `NotcursesOptions` +/// `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::bindgen::ncloglevel_e; + +/// this is honestly a bit much +pub const NCLOGLEVEL_DEBUG: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_DEBUG; + +/// we can't keep doin' this, but we can do other things +pub const NCLOGLEVEL_ERROR: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_ERROR; + +/// we're hanging around, but we've had a horrible fault +pub const NCLOGLEVEL_FATAL: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_FATAL; + +/// "detailed information +pub const NCLOGLEVEL_INFO: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_INFO; + +/// print diagnostics immediately related to crashing +pub const NCLOGLEVEL_PANIC: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_PANIC; + +/// default. print nothing once fullscreen service begins +pub const NCLOGLEVEL_SILENT: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_SILENT; + +/// there's probably a better way to do what you want +pub const NCLOGLEVEL_TRACE: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_TRACE; + +/// "detailed information +pub const NCLOGLEVEL_VERBOSE: NcLogLevel = + crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_VERBOSE; + +/// you probably don't want what's happening to happen +pub const NCLOGLEVEL_WARNING: NcLogLevel = + crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_WARNING; diff --git a/rust/src/notcurses/reimplemented.rs b/rust/src/notcurses/reimplemented.rs new file mode 100644 index 000000000..6e4a05713 --- /dev/null +++ b/rust/src/notcurses/reimplemented.rs @@ -0,0 +1,100 @@ +//! `notcurses_*` reimplemented functions. + +// pub use types::{ +// NcLogLevel, Notcurses, NotcursesOptions, NCLOGLEVEL_DEBUG, NCLOGLEVEL_ERROR, NCLOGLEVEL_FATAL, +// NCLOGLEVEL_INFO, NCLOGLEVEL_PANIC, NCLOGLEVEL_SILENT, NCLOGLEVEL_TRACE, NCLOGLEVEL_VERBOSE, +// NCLOGLEVEL_WARNING, NCOPTION_INHIBIT_SETLOCALE, NCOPTION_NO_ALTERNATE_SCREEN, +// NCOPTION_NO_FONT_CHANGES, NCOPTION_NO_QUIT_SIGHANDLERS, NCOPTION_NO_WINCH_SIGHANDLER, +// NCOPTION_SUPPRESS_BANNERS, NCOPTION_VERIFY_SIXEL, +// }; +// + +use core::ptr::null; + +use crate::{ + // NOTE: can't use libc::sigset_t with notcurses_getc(() + bindings::{sigemptyset, sigfillset, sigset_t}, + ncplane_dim_yx, + notcurses_getc, + notcurses_stdplane, + notcurses_stdplane_const, + NcAlign, + NcInput, + NcPlane, + NcTime, + Notcurses, + NCALIGN_CENTER, + NCALIGN_LEFT, +}; + +/// return the offset into 'availcols' at which 'cols' ought be output given the requirements of 'align' +#[inline] +pub fn notcurses_align(availcols: i32, align: NcAlign, cols: i32) -> i32 { + if align == NCALIGN_LEFT { + return 0; + } + if cols > availcols { + return 0; + } + if align == NCALIGN_CENTER { + return (availcols - cols) / 2; + } + availcols - cols // NCALIGN_RIGHT +} + +/// 'input' may be NULL if the caller is uninterested in event details. +/// If no event is ready, returns 0. +// TODO: use pakr-signals +#[inline] +pub fn notcurses_getc_nblock(nc: &mut Notcurses, input: &mut NcInput) -> char { + unsafe { + let mut sigmask = sigset_t { __val: [0; 16] }; + sigfillset(&mut sigmask); + let ts = NcTime { + tv_sec: 0, + tv_nsec: 0, + }; + core::char::from_u32_unchecked(notcurses_getc(nc, &ts, &mut sigmask, input)) + } +} + +/// 'input' may be NULL if the caller is uninterested in event details. +/// Blocks until an event is processed or a signal is received. +#[inline] +pub fn notcurses_getc_nblocking(nc: &mut Notcurses, input: &mut NcInput) -> char { + unsafe { + let mut sigmask = sigset_t { __val: [0; 16] }; + sigemptyset(&mut sigmask); + core::char::from_u32_unchecked(notcurses_getc(nc, null(), &mut sigmask, input)) + } +} + +/// notcurses_stdplane(), plus free bonus dimensions written to non-NULL y/x! +#[inline] +pub fn notcurses_stddim_yx(nc: &mut Notcurses, y: &mut i32, x: &mut i32) -> NcPlane { + unsafe { + let s = notcurses_stdplane(nc); + ncplane_dim_yx(s, y, x); + *s + } +} + +/// notcurses_stdplane_const(), plus free bonus dimensions written to non-NULL y/x! +#[inline] +pub fn notcurses_stddim_yx_const(nc: &Notcurses, y: &mut i32, x: &mut i32) -> NcPlane { + unsafe { + let s = notcurses_stdplane_const(nc); + ncplane_dim_yx(s, y, x); + *s + } +} + +/// Return our current idea of the terminal dimensions in rows and cols. +#[inline] +pub fn notcurses_term_dim_yx(nc: &Notcurses, rows: &mut u32, cols: &mut u32) { + unsafe { + let mut irows = *rows as i32; + let mut icols = *cols as i32; + ncplane_dim_yx(notcurses_stdplane_const(nc), &mut irows, &mut icols); + } +} diff --git a/rust/src/notcurses/test/methods.rs b/rust/src/notcurses/test/methods.rs new file mode 100644 index 000000000..6ee077ed3 --- /dev/null +++ b/rust/src/notcurses/test/methods.rs @@ -0,0 +1,4 @@ +//! Test `Notcurses` methods and associated functions. + +// use crate::Notcurses; +// use serial_test::serial; diff --git a/rust/src/notcurses/test/mod.rs b/rust/src/notcurses/test/mod.rs new file mode 100644 index 000000000..759dc3d48 --- /dev/null +++ b/rust/src/notcurses/test/mod.rs @@ -0,0 +1,7 @@ +//! `Notcurses` tests. + +#[cfg(test)] +mod methods; + +#[cfg(test)] +mod reimplemented; diff --git a/rust/src/notcurses/tests.rs b/rust/src/notcurses/test/reimplemented.rs similarity index 98% rename from rust/src/notcurses/tests.rs rename to rust/src/notcurses/test/reimplemented.rs index 7b7639c61..ced702df4 100644 --- a/rust/src/notcurses/tests.rs +++ b/rust/src/notcurses/test/reimplemented.rs @@ -1,4 +1,4 @@ -//! [`Notcurses`] tests +//! Test `notcurses_*` reimplemented functions. use serial_test::serial; use std::io::Read; diff --git a/rust/src/notcurses/types.rs b/rust/src/notcurses/types.rs deleted file mode 100644 index 25268a266..000000000 --- a/rust/src/notcurses/types.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! Types related with `Notcurses` - -/// The main struct of the (full mode) TUI library -/// -/// Notcurses builds atop the terminfo abstraction layer to -/// provide reasonably portable vivid character displays. -/// -pub type Notcurses = crate::bindings::bindgen::notcurses; - -/// Options struct for [`Notcurses`] -pub type NotcursesOptions = crate::bindings::bindgen::notcurses_options; - -/// 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::bindgen::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::bindgen::NCOPTION_NO_ALTERNATE_SCREEN 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::bindgen::NCOPTION_NO_FONT_CHANGES as u64; - -/// Do not handle SIG{ING, SEGV, ABRT, QUIT} -/// -/// We typically install a signal handler for SIG{INT, SEGV, ABRT, QUIT} that -/// restores the screen, and then calls the old signal handler. Set to inhibit -/// registration of these signal handlers. -pub const NCOPTION_NO_QUIT_SIGHANDLERS: u64 = - crate::bindings::bindgen::NCOPTION_NO_QUIT_SIGHANDLERS as u64; - -/// Do not handle SIGWINCH -/// -/// We typically install a signal handler for SIGWINCH that generates a resize -/// event in the notcurses_getc() queue. Set to inhibit this handler -pub const NCOPTION_NO_WINCH_SIGHANDLER: u64 = - crate::bindings::bindgen::NCOPTION_NO_WINCH_SIGHANDLER 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::bindgen::NCOPTION_SUPPRESS_BANNERS as u64; - -/// Test for Sixel support -/// -/// Checking for Sixel support requires writing an escape, and then reading an -/// inline reply from the terminal. Since this can interact poorly with actual -/// user input, it's not done unless Sixel will actually be used. Set this flag -/// to unconditionally test for Sixel support in notcurses_init(). -pub const NCOPTION_VERIFY_SIXEL: u64 = crate::bindings::bindgen::NCOPTION_VERIFY_SIXEL as u64; - -// NcLogLevel ------------------------------------------------------------------ - -/// Log level for [`NotcursesOptions`] -/// -/// 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 `NotcursesOptions` -/// `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::bindgen::ncloglevel_e; - -/// this is honestly a bit much -pub const NCLOGLEVEL_DEBUG: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_DEBUG; - -/// we can't keep doin' this, but we can do other things -pub const NCLOGLEVEL_ERROR: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_ERROR; - -/// we're hanging around, but we've had a horrible fault -pub const NCLOGLEVEL_FATAL: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_FATAL; - -/// "detailed information -pub const NCLOGLEVEL_INFO: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_INFO; - -/// print diagnostics immediately related to crashing -pub const NCLOGLEVEL_PANIC: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_PANIC; - -/// default. print nothing once fullscreen service begins -pub const NCLOGLEVEL_SILENT: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_SILENT; - -/// there's probably a better way to do what you want -pub const NCLOGLEVEL_TRACE: NcLogLevel = crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_TRACE; - -/// "detailed information -pub const NCLOGLEVEL_VERBOSE: NcLogLevel = - crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_VERBOSE; - -/// you probably don't want what's happening to happen -pub const NCLOGLEVEL_WARNING: NcLogLevel = - crate::bindings::bindgen::ncloglevel_e_NCLOGLEVEL_WARNING; diff --git a/rust/src/palette/mod.rs b/rust/src/palette/mod.rs new file mode 100644 index 000000000..8b3285fe9 --- /dev/null +++ b/rust/src/palette/mod.rs @@ -0,0 +1,42 @@ +//! `NcPalette*` + +// ----------------------------------------------------------------------------- +// Now none of these functions can't fail and therefore don't return errors. +// ----------------------------------------------------------------------------- +// +// functions already exported by bindgen : 3 +// ----------------------------------------- +// (#) unit tests: 0 / 3 +// ----------------------------------------- +// palette256_free +// palette256_new +// palette256_use +// +// functions manually reimplemented: 3 +// ----------------------------------------- +// (+) implement : 3 / 0 +// (#) unit tests: 0 / 3 +// ----------------------------------------- +// + palette256_get_rgb +// + palette256_set +// + palette256_set_rgb + +pub mod reimplemented; +pub use reimplemented::*; + +/// NcPalette structure consisting of an array of 256 [`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: ncpalette256 (struct)` +/// +pub type NcPalette = crate::bindings::bindgen::palette256; + +/// 8-bit value used for indexing into a [`NcPalette`] +/// +pub type NcPaletteIndex = u8; diff --git a/rust/src/palette.rs b/rust/src/palette/reimplemented.rs similarity index 55% rename from rust/src/palette.rs rename to rust/src/palette/reimplemented.rs index 0c6185693..94005e0f9 100644 --- a/rust/src/palette.rs +++ b/rust/src/palette/reimplemented.rs @@ -1,21 +1,4 @@ -// ----------------------------------------------------------------------------- -// Now none of these functions can't fail and therefore don't return errors. -// ----------------------------------------------------------------------------- -// -// functions already exported by bindgen : 3 -// ----------------------------------------- -// palette256_free -// palette256_new -// palette256_use -// -// static inline functions total: 3 -// ----------------------------------------- (done / remaining) -// (+) implement : 3 / 0 -// (#) unit tests: 0 / 3 -// ----------------------------------------- -//+ palette256_get_rgb -//+ palette256_set -//+ palette256_set_rgb +//! `palette256_*` reimplemented functions. use crate::{ channel_rgb8, channel_set, channel_set_rgb8, NcChannel, NcColor, NcPalette, NcPaletteIndex, @@ -51,15 +34,3 @@ pub fn palette256_get_rgb( ) -> NcChannel { channel_rgb8(palette.chans[idx as usize], red, green, blue) } - -#[cfg(test)] -mod test { - // use super::nc; - // use serial_test::serial; - /* - #[test] - #[serial] - fn () { - } - */ -} diff --git a/rust/src/pixel.rs b/rust/src/pixel.rs index aed246d8b..f84707a4e 100644 --- a/rust/src/pixel.rs +++ b/rust/src/pixel.rs @@ -7,34 +7,42 @@ // // - NOTE: None of the functions can't fail anymore and don't have to return an error. // -// -// functions already exported by bindgen : 0 -// ----------------------------------------- -// -// static inline functions total: 10 -// ------------------------------------------ (done / remaining) +// functions manually reimplemented: 10 +// ------------------------------------------ // (+) implement : 10 / 0 // (#) unit tests: 0 / 10 // ------------------------------------------ -//+ ncpixel -//+ ncpixel_a -//+ ncpixel_b -//+ ncpixel_g -//+ ncpixel_r -//+ ncpixel_set_a -//+ ncpixel_set_b -//+ ncpixel_set_g -//+ ncpixel_set_r -//+ ncpixel_set_rgb +// + ncpixel +// + ncpixel_a +// + ncpixel_b +// + ncpixel_g +// + ncpixel_r +// + ncpixel_set_a +// + ncpixel_set_b +// + ncpixel_set_g +// + ncpixel_set_r +// + ncpixel_set_rgb -use crate::{NcColor, NcPixel}; +use crate::NcColor; -// NcPixel Structure: -// -// 0xff000000 8 bit Alpha -// 0x00ff0000 8 bit Green -// 0x0000ff00 8 bit Blue -// 0x000000ff 8 bit Red +// NcPixel (RGBA) +/// 32 bits broken into RGB + 8-bit alpha +/// +/// 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 +/// +/// ## Diagram +/// +/// ```txt +/// AAAAAAAA GGGGGGGG BBBBBBBB RRRRRRRR +/// ``` +/// `type in C: ncpixel (uint32_t)` +/// +// NOTE: the order of the colors is different than in NcChannel. +pub type NcPixel = u32; /// Get an RGB pixel from RGB values pub fn ncpixel(r: NcColor, g: NcColor, b: NcColor) -> NcPixel { @@ -87,15 +95,3 @@ pub fn ncpixel_set_rgb(pixel: &mut NcPixel, red: NcColor, green: NcColor, blue: ncpixel_set_g(pixel, green); ncpixel_set_b(pixel, blue); } - -#[cfg(test)] -mod test { - // use super::nc; - // use serial_test::serial; - /* - #[test] - #[serial] - fn () { - } - */ -} diff --git a/rust/src/plane/wrapped.rs b/rust/src/plane/methods.rs similarity index 87% rename from rust/src/plane/wrapped.rs rename to rust/src/plane/methods.rs index a09a7e7b0..256ea678a 100644 --- a/rust/src/plane/wrapped.rs +++ b/rust/src/plane/methods.rs @@ -1,4 +1,4 @@ -//! Handy [`NcPlane`] and [`NcPlaneOptions`] constructors +//! `NcPlane*` methods and associated functions. use core::ptr::{null, null_mut}; @@ -10,7 +10,8 @@ use crate::{ // for methods use crate::{ - NcCell, NcResult, ncplane_cursor_yx, ncplane_dim_yx, ncplane_erase, ncplane_putc, ncplane_putc_yx, + ncpile_bottom, ncpile_top, ncplane_cursor_yx, ncplane_dim_yx, ncplane_erase, ncplane_putc, + ncplane_putc_yx, NcCell, NcResult, }; /// # `NcPlaneOptions` Constructors @@ -104,6 +105,11 @@ impl NcPlane { /// # `NcPlane` Methods impl NcPlane { + /// Returns the bottommost [NcPlane] of the pile that contains this [NnPlane]. + pub fn bottom<'a>(&mut self) -> &'a mut NcPlane { + unsafe { &mut *ncpile_bottom(self) } + } + /// Returns the current position of the cursor within the [NcPlane]. /// /// Unlike [ncplane_cursor_yx] which uses `i32`, this uses [u32]. @@ -112,7 +118,7 @@ impl NcPlane { // FIXME: CHECK for NULL and return Some() or None. pub fn cursor_yx(&self) -> (u32, u32) { let (mut y, mut x) = (0, 0); - unsafe {ncplane_cursor_yx(self, &mut y, &mut x)}; + unsafe { ncplane_cursor_yx(self, &mut y, &mut x) }; (y as u32, x as u32) } @@ -131,7 +137,7 @@ impl NcPlane { /// Unlike [ncplane_dim_yx] which uses `i32`, this uses [u32]. pub fn dim_yx(&self) -> (u32, u32) { let (mut y, mut x) = (0, 0); - unsafe {ncplane_dim_yx(self, &mut y, &mut x)}; + unsafe { ncplane_dim_yx(self, &mut y, &mut x) }; (y as u32, x as u32) } @@ -158,9 +164,14 @@ impl NcPlane { pub fn putc_yx(&mut self, y: i32, x: i32, cell: &NcCell) -> NcResult { unsafe { ncplane_putc_yx(self, y, x, cell) } } - + /// pub fn putc(&mut self, cell: &NcCell) -> NcResult { ncplane_putc(self, cell) } + + /// Returns the topmost [NcPlane] of the pile that contains this [NnPlane]. + pub fn top<'a>(&mut self) -> &'a mut NcPlane { + unsafe { &mut *ncpile_top(self) } + } } diff --git a/rust/src/plane/mod.rs b/rust/src/plane/mod.rs index 3d43c6a17..b9a41b4b9 100644 --- a/rust/src/plane/mod.rs +++ b/rust/src/plane/mod.rs @@ -1,819 +1,324 @@ -//! [`NcPlane`] ncplane_* static functions reimplementations +//! `NcPlane` -// functions already exported by bindgen : 103 -// ------------------------------------------ (implement / remaining) -// (#) test: 13 / 90 +// functions already exported by bindgen : 105 // ------------------------------------------ -//# ncpile_create -// ncpile_rasterize -// ncpile_render -// -// ncplane_above -// ncplane_at_cursor -// ncplane_at_yx -// ncplane_base -// ncplane_below -// ncplane_box -// ncplane_center_abs -//# ncplane_channels -// ncplane_contents -// ncplane_create -//# ncplane_cursor_move_yx -//# ncplane_cursor_yx -// ncplane_destroy -//# ncplane_dim_yx -// ncplane_dup -//# ncplane_erase -// ncplane_fadein -// ncplane_fadein_iteration -// ncplane_fadeout -// ncplane_fadeout_iteration -// ncplane_format -// ncplane_gradient -// 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_new -//# ncplane_notcurses -//# ncplane_notcurses_const -// ncplane_off_styles -// ncplane_on_styles -// ncplane_parent -// ncplane_parent_const -// ncplane_polyfill_yx -// ncplane_pulse -// ncplane_putchar_stained -// ncplane_putc_yx -// 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_resizecb -// ncplane_resize_realign -// ncplane_rgba -// ncplane_rotate_ccw -// ncplane_rotate_cw -// ncplane_set_base -// ncplane_set_base_cell -//# ncplane_set_bchannel -// 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_channels -//# ncplane_set_fchannel -// 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 +// (#) 13 / 92 unit tests +// (W) 1 wrapped as a method or function +// ------------------------------------------ +// ncpile_bottom +// # ncpile_create +// ncpile_rasterize +// ncpile_render +// ncpile_top +// ncplane_above +// ncplane_at_cursor +// ncplane_at_yx +// ncplane_base +// ncplane_below +// ncplane_box +// ncplane_center_abs +// # ncplane_channels +// ncplane_contents +// ncplane_create +// # ncplane_cursor_move_yx +//W# ncplane_cursor_yx +// ncplane_destroy +//W# ncplane_dim_yx +// ncplane_dup +// # ncplane_erase +// ncplane_fadein +// ncplane_fadein_iteration +// ncplane_fadeout +// ncplane_fadeout_iteration +// ncplane_format +// ncplane_gradient +// 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_new +// # ncplane_notcurses +// # ncplane_notcurses_const +// ncplane_off_styles +// ncplane_on_styles +// ncplane_parent +// ncplane_parent_const +// ncplane_polyfill_yx +// ncplane_pulse +// ncplane_putchar_stained +// ncplane_putc_yx +// 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_resizecb +// ncplane_resize_realign +// ncplane_rgba +// ncplane_rotate_ccw +// ncplane_rotate_cw +// ncplane_set_base +// ncplane_set_base_cell +// # ncplane_set_bchannel +// 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_channels +// # ncplane_set_fchannel +// 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 // -// static inline functions total: 42 -// ------------------------------------------ (implement / remaining) +// functions manually reimplemented: 42 +// ------------------------------------------ // (X) wont: 8 // (+) done: 34 / 0 // (#) test: 5 / 29 // ------------------------------------------ -//+ ncplane_align -//+ ncplane_at_cursor_cell -//+ ncplane_at_yx_cell -//+ ncplane_bchannel -//+ ncplane_bg_alpha -//# ncplane_bg_default_p -//+ ncplane_bg_rgb -//+ ncplane_bg_rgb8 -//+ ncplane_box_sized -//# ncplane_dim_x -//# ncplane_dim_y -//+ ncplane_double_box -//+ ncplane_double_box_sized -//+ ncplane_fchannel -//+ ncplane_fg_alpha -//# ncplane_fg_default_p -//+ ncplane_fg_rgb -//+ ncplane_fg_rgb8 -//+ ncplane_gradient_sized // u64|u32 https://github.com/dankamongmen/notcurses/issues/920 -//+ ncplane_hline -//+ ncplane_perimeter -//+ ncplane_perimeter_double -//+ ncplane_perimeter_rounded -//+ ncplane_putc -//+ ncplane_putchar -//+ ncplane_putchar_yx -//+ ncplane_putegc -//+ ncplane_putnstr -//+ ncplane_putstr -//X ncplane_putwc // I don't think these will be needed from Rust. See: -//X ncplane_putwc_stained -//X ncplane_putwc_yx // https://locka99.gitbooks.io/a-guide-to-porting-c-to-rust/content/features_of_rust/strings.html -//X ncplane_putwegc // -//X ncplane_putwegc_yx // -//X ncplane_putwstr // -//X ncplane_putwstr_aligned // -//X ncplane_putwstr_yx // -//# ncplane_resize_simple -//+ ncplane_rounded_box -//+ ncplane_rounded_box_sized -//+ ncplane_vline -//+ ncplane_vprintf +// + ncplane_align +// + ncplane_at_cursor_cell +// + ncplane_at_yx_cell +// + ncplane_bchannel +// + ncplane_bg_alpha +// # ncplane_bg_default_p +// + ncplane_bg_rgb +// + ncplane_bg_rgb8 +// + ncplane_box_sized +//W# ncplane_dim_x +//W# ncplane_dim_y +// + ncplane_double_box +// + ncplane_double_box_sized +// + ncplane_fchannel +// + ncplane_fg_alpha +// # ncplane_fg_default_p +// + ncplane_fg_rgb +// + ncplane_fg_rgb8 +// + ncplane_gradient_sized // u64|u32 https://github.com/dankamongmen/notcurses/issues/920 +// + ncplane_hline +// + ncplane_perimeter +// + ncplane_perimeter_double +// + ncplane_perimeter_rounded +// + ncplane_putc +// + ncplane_putchar +// + ncplane_putchar_yx +// + ncplane_putegc +// + ncplane_putnstr +// + ncplane_putstr +// X ncplane_putwc // I don't think these will be needed from Rust. See: +// X ncplane_putwc_stained +// X ncplane_putwc_yx // https://locka99.gitbooks.io/a-guide-to-porting-c-to-rust/content/features_of_rust/strings.html +// X ncplane_putwegc // +// X ncplane_putwegc_yx // +// X ncplane_putwstr // +// X ncplane_putwstr_aligned // +// X ncplane_putwstr_yx // +// # ncplane_resize_simple +// + ncplane_rounded_box +// + ncplane_rounded_box_sized +// + ncplane_vline +// + ncplane_vprintf // // NOTE: TODO: Still remains all the ncplane_printf* functions/macros (at the end) #[cfg(test)] -mod tests; - -mod types; -pub use types::{ - NCBLIT_1x1, NCBLIT_2x1, NCBLIT_2x2, NCBLIT_3x2, NCBLIT_4x1, NCBLIT_8x1, NcAlign, NcBlitter, - NcFdPlane, NcFdPlaneOptions, NcPlane, NcPlaneOptions, NcScale, NcVisual, NcVisualOptions, - NCALIGN_CENTER, NCALIGN_LEFT, NCALIGN_RIGHT, NCALIGN_UNALIGNED, NCBLIT_BRAILLE, NCBLIT_DEFAULT, - NCBLIT_SIXEL, NCPLANE_OPTION_HORALIGNED, NCSCALE_NONE, NCSCALE_SCALE, NCSCALE_STRETCH, - NCVISUAL_OPTION_BLEND, NCVISUAL_OPTION_NODEGRADE, -}; - -mod wrapped; -pub use wrapped::*; - -use core::{ffi::c_void, ptr::null_mut}; -use libc::free; -use std::ffi::CString; - -use crate::{ - bindgen::__va_list_tag, cell_load, cell_release, cells_double_box, cells_rounded_box, - channels_bchannel, channels_bg_alpha, channels_bg_default_p, channels_bg_rgb, channels_bg_rgb8, - channels_fchannel, channels_fg_alpha, channels_fg_default_p, channels_fg_rgb, channels_fg_rgb8, - ncplane_at_cursor, ncplane_at_yx, ncplane_box, ncplane_channels, ncplane_cursor_move_yx, - ncplane_cursor_yx, ncplane_dim_yx, ncplane_gradient, ncplane_hline_interp, ncplane_putc_yx, - ncplane_putegc_yx, ncplane_putnstr_yx, ncplane_putstr_yx, ncplane_resize, ncplane_styles, - ncplane_vline_interp, ncplane_vprintf_yx, notcurses_align, NcAlphaBits, NcCell, NcChannel, - NcChannelPair, NcColor, NcResult, NcStyleMask, NCRESULT_ERR, NCRESULT_OK, -}; - -// Static Functions ------------------------------------------------------------ - -/// Return the column at which 'cols' columns ought start in order to be aligned -/// according to 'align' within ncplane 'n'. Returns INT_MAX on invalid 'align'. -/// Undefined behavior on negative 'cols'. -// -// NOTE: [leave cols as i32](https://github.com/dankamongmen/notcurses/issues/904) -#[inline] -pub fn ncplane_align(plane: &NcPlane, align: NcAlign, cols: i32) -> i32 { - notcurses_align(ncplane_dim_x(plane), align, cols) -} - -/// Retrieve the current contents of the cell under the cursor into 'cell'. -/// This cell is invalidated if the associated plane is destroyed. -#[inline] -pub fn ncplane_at_cursor_cell(plane: &mut NcPlane, cell: &mut NcCell) -> NcResult { - let mut egc = unsafe { ncplane_at_cursor(plane, &mut cell.stylemask, &mut cell.channels) }; - if egc.is_null() { - return NCRESULT_ERR; - } - let result: NcResult = unsafe { cell_load(plane, cell, egc) }; - if result != NCRESULT_OK { - unsafe { - free(&mut egc as *mut _ as *mut c_void); - } - } - result -} +mod test; -/// Retrieve the current contents of the specified cell into 'cell'. -/// This cell is invalidated if the associated plane is destroyed. -#[inline] -pub fn ncplane_at_yx_cell(plane: &mut NcPlane, y: i32, x: i32, cell: &mut NcCell) -> NcResult { - let mut egc = unsafe { ncplane_at_yx(plane, y, x, &mut cell.stylemask, &mut cell.channels) }; - if egc.is_null() { - return NCRESULT_ERR; - } - let channels = cell.channels; // need to preserve wide flag - let result: NcResult = unsafe { cell_load(plane, cell, egc) }; - cell.channels = channels; - unsafe { - free(&mut egc as *mut _ as *mut c_void); - } - result -} - -/// Draw a box with its upper-left corner at the current cursor position, having -/// dimensions 'ylen'x'xlen'. See ncplane_box() for more information. The -/// minimum box size is 2x2, and it cannot be drawn off-screen. -#[inline] -pub fn ncplane_box_sized( - plane: &mut NcPlane, - ul: &NcCell, - ur: &NcCell, - ll: &NcCell, - lr: &NcCell, - hline: &NcCell, - vline: &NcCell, - ylen: i32, - xlen: i32, - ctlword: u32, -) -> NcResult { - let (mut y, mut x) = (0, 0); - unsafe { - ncplane_cursor_yx(plane, &mut y, &mut x); - ncplane_box( - plane, - ul, - ur, - ll, - lr, - hline, - vline, - y + ylen - 1, - x + xlen - 1, - ctlword, - ) - } -} +mod methods; +mod reimplemented; +pub use reimplemented::*; +// NcPlane +/// Fundamental drawing surface. /// -#[inline] -pub fn ncplane_dim_x(plane: &NcPlane) -> i32 { - unsafe { - let mut x = 0; - ncplane_dim_yx(plane, null_mut(), &mut x); - x - } -} - +/// Unites a: +/// - CellMatrix +/// - EgcPool /// -#[inline] -pub fn ncplane_dim_y(plane: &NcPlane) -> i32 { - unsafe { - let mut y = 0; - ncplane_dim_yx(plane, &mut y, null_mut()); - y - } -} - +/// `type in C: ncplane (struct)` /// -#[inline] -pub fn ncplane_double_box( - plane: &mut NcPlane, - stylemask: NcStyleMask, - channels: NcChannelPair, - ystop: i32, - xstop: i32, - ctlword: u32, -) -> NcResult { - #[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 = cells_double_box( - plane, - stylemask as u32, - channels, - &mut ul, - &mut ur, - &mut ll, - &mut lr, - &mut hl, - &mut vl, - ); - if ret == NCRESULT_OK { - ret = ncplane_box(plane, &ul, &ur, &ll, &lr, &hl, &vl, ystop, xstop, ctlword); - } - - cell_release(plane, &mut ul); - cell_release(plane, &mut ur); - cell_release(plane, &mut ll); - cell_release(plane, &mut lr); - cell_release(plane, &mut hl); - cell_release(plane, &mut vl); - } - ret -} - /// -#[inline] -pub fn ncplane_double_box_sized( - plane: &mut NcPlane, - stylemask: NcStyleMask, - channels: NcChannelPair, - ylen: i32, - xlen: i32, - ctlword: u32, -) -> NcResult { - let (mut y, mut x) = (0, 0); - unsafe { - ncplane_cursor_yx(plane, &mut y, &mut x); - } - ncplane_double_box( - plane, - stylemask, - channels, - y + ylen - 1, - x + xlen - 1, - ctlword, - ) -} - -/// On error, return the negative number of cells drawn. -#[inline] -pub fn ncplane_hline(plane: &mut NcPlane, cell: &NcCell, len: i32) -> i32 { - unsafe { ncplane_hline_interp(plane, cell, len, cell.channels, cell.channels) } -} - +/// ## Piles /// -#[inline] -pub fn ncplane_perimeter( - plane: &mut NcPlane, - ul: &NcCell, - ur: &NcCell, - ll: &NcCell, - lr: &NcCell, - hline: &NcCell, - vline: &NcCell, - ctlword: u32, -) -> NcResult { - unsafe { - ncplane_cursor_move_yx(plane, 0, 0); - let (mut dimy, mut dimx) = (0, 0); - ncplane_dim_yx(plane, &mut dimy, &mut dimx); - ncplane_box_sized(plane, ul, ur, ll, lr, hline, vline, dimy, dimx, ctlword) - } -} - +/// A single notcurses context is made up of one or more piles. /// -#[inline] -pub fn ncplane_perimeter_double( - plane: &mut NcPlane, - stylemask: NcStyleMask, - channels: NcChannelPair, - ctlword: u32, -) -> NcResult { - if unsafe { ncplane_cursor_move_yx(plane, 0, 0) } != NCRESULT_OK { - return NCRESULT_ERR; - } - let (mut dimy, mut dimx) = (0, 0); - unsafe { - 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 { - cells_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, dimx, ctlword); - unsafe { - cell_release(plane, &mut ul); - cell_release(plane, &mut ur); - cell_release(plane, &mut ll); - cell_release(plane, &mut lr); - cell_release(plane, &mut hl); - cell_release(plane, &mut vl); - } - ret -} - +/// A pile is a set of one or more ncplanes, including the partial orderings +/// made up of their binding and z-axis pointers. /// -#[inline] -pub fn ncplane_perimeter_rounded( - plane: &mut NcPlane, - stylemask: NcStyleMask, - channels: NcChannelPair, - ctlword: u32, -) -> NcResult { - if unsafe { ncplane_cursor_move_yx(plane, 0, 0) } != NCRESULT_OK { - return NCRESULT_ERR; - } - let (mut dimy, mut dimx) = (0, 0); - unsafe { - 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 { - cells_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, dimx, ctlword); - unsafe { - cell_release(plane, &mut ul); - cell_release(plane, &mut ur); - cell_release(plane, &mut ll); - cell_release(plane, &mut lr); - cell_release(plane, &mut hl); - cell_release(plane, &mut vl); - } - ret -} - -/// Call ncplane_putc_yx() for the current cursor location. -#[inline] -pub fn ncplane_putc(plane: &mut NcPlane, cell: &NcCell) -> NcResult { - unsafe { ncplane_putc_yx(plane, -1, -1, cell) } -} - -/// Call ncplane_putchar_yx() at the current cursor location. -#[inline] -pub fn ncplane_putchar(plane: &mut NcPlane, c: char) -> NcResult { - ncplane_putchar_yx(plane, -1, -1, c) -} - -/// Replace the EGC underneath us, but retain the styling. The current styling -/// of the plane will not be changed. +/// A pile has a top and bottom ncplane (this might be a single plane), +/// and one or more root planes (planes which are bound to themselves). /// -/// Replace the cell at the specified coordinates with the provided 7-bit char -/// 'c'. Advance the cursor by 1. On success, returns 1. On failure, returns -1. -/// This works whether the underlying char is signed or unsigned. -#[inline] -// TODO: test char is < 8bit (currently 32bit) -pub fn ncplane_putchar_yx(plane: &mut NcPlane, y: i32, x: i32, c: char) -> NcResult { - unsafe { - let ce = NcCell::with_all(c, ncplane_styles(plane), ncplane_channels(plane)); - ncplane_putc_yx(plane, y, x, &ce) - } -} - -/// Call ncplane_putegc() at the current cursor location. -#[inline] -pub fn ncplane_putegc(plane: &mut NcPlane, gcluster: i8, sbytes: &mut i32) -> NcResult { - unsafe { ncplane_putegc_yx(plane, -1, -1, &gcluster, sbytes) } -} - +/// Multiple threads can concurrently operate on distinct piles, even changing +/// one while rendering another. /// -#[inline] -pub fn ncplane_putstr(plane: &mut NcPlane, string: &str) -> NcResult { - unsafe { - ncplane_putstr_yx( - plane, - -1, - -1, - CString::new(string.as_bytes()).expect("Bad string").as_ptr(), - ) - } -} - +/// Each plane is part of one and only one pile. By default, a plane is part of +/// the same pile containing that plane to which it is bound. /// -#[inline] -pub fn ncplane_putnstr(plane: &mut NcPlane, size: u64, gclustarr: &[u8]) -> NcResult { - unsafe { - ncplane_putnstr_yx( - plane, - -1, - -1, - size, - CString::new(gclustarr).expect("Bad string").as_ptr(), - ) - } -} - -/// Resize the plane, retaining what data we can (everything, unless we're -/// shrinking in some dimension). Keep the origin where it is. -#[inline] -pub fn ncplane_resize_simple(plane: &mut NcPlane, ylen: i32, xlen: i32) -> NcResult { - let (mut oldy, mut oldx) = (0, 0); - unsafe { - ncplane_dim_yx(plane, &mut oldy, &mut oldx); - } - let keepleny = { - if oldy > ylen { - ylen - } else { - oldy - } - }; - let keeplenx = { - if oldx > xlen { - xlen - } else { - oldx - } - }; - unsafe { ncplane_resize(plane, 0, 0, keepleny, keeplenx, 0, 0, ylen, xlen) } -} - +/// If ncpile_create is used in the place of ncplane_create, the returned plane +/// becomes the root plane, top, and bottom of a new pile. As a root plane, +/// it is bound to itself. /// -/// On error, return the negative number of cells drawn. -#[inline] -pub fn ncplane_vline(plane: &mut NcPlane, cell: &NcCell, len: i32) -> i32 { - unsafe { ncplane_vline_interp(plane, cell, len, cell.channels, cell.channels) } -} - +/// A new pile can also be created by reparenting a plane to itself, +/// though if the plane is already a root plane, this is a no-op. /// -#[inline] -pub fn ncplane_vprintf(plane: &mut NcPlane, format: &str, ap: &mut __va_list_tag) -> NcResult { - unsafe { - ncplane_vprintf_yx( - plane, - -1, - -1, - CString::new(format).expect("Bad string").as_ptr(), - ap, - ) - } -} - -/// Draw a gradient with its upper-left corner at the current cursor position, -/// having dimensions 'ylen'x'xlen'. See ncplane_gradient for more information. -/// static inline int -// XXX receive cells as u32? https://github.com/dankamongmen/notcurses/issues/920 -#[inline] -pub fn ncplane_gradient_sized( - plane: &mut NcPlane, - egc: &[u8], - stylemask: NcStyleMask, - ul: u64, - ur: u64, - ll: u64, - lr: u64, - ylen: i32, - xlen: i32, -) -> NcResult { - if ylen < 1 || xlen < 1 { - return NCRESULT_ERR; - } - let (mut y, mut x) = (0, 0); - unsafe { - ncplane_cursor_yx(plane, &mut y, &mut x); - ncplane_gradient( - plane, - CString::new(egc).expect("Bad EGC").as_ptr(), - stylemask as u32, - ul, - ur, - ll, - lr, - y + ylen - 1, - x + xlen - 1, - ) - } -} - -/// Extract the 32-bit working foreground channel from an ncplane. -#[inline] -pub fn ncplane_fchannel(plane: &NcPlane) -> NcChannel { - channels_fchannel(unsafe { ncplane_channels(plane) }) -} +/// When a plane is moved to a different pile (whether new or preexisting), +/// any planes which were bound to it are rebound to its previous parent. +/// If the plane was a root plane of some pile, any bound planes become root +/// planes. The new plane is placed immediately atop its new parent on its new +/// pile's z-axis. When ncplane_reparent_family() is used, all planes bound to +/// the reparented plane are moved along with it. Their relative z-order is maintained. +/// +pub type NcPlane = crate::bindings::bindgen::ncplane; -/// Extract the 32-bit working background channel from an ncplane. -#[inline] -pub fn ncplane_bchannel(plane: &NcPlane) -> NcChannel { - channels_bchannel(unsafe { ncplane_channels(plane) }) -} +/// Options struct for [`NcPlane`] +pub type NcPlaneOptions = crate::bindings::bindgen::ncplane_options; -/// Extract 24 bits of working foreground RGB from an ncplane, shifted to LSBs. -#[inline] -pub fn ncplane_fg_rgb(plane: &NcPlane) -> NcChannel { - channels_fg_rgb(unsafe { ncplane_channels(plane) }) -} +/// Horizontal alignment relative to the parent plane. Set alignment in 'x'. +pub const NCPLANE_OPTION_HORALIGNED: u64 = + crate::bindings::bindgen::NCPLANE_OPTION_HORALIGNED as u64; -/// Extract 24 bits of working background RGB from an ncplane, shifted to LSBs. -#[inline] -pub fn ncplane_bg_rgb(plane: &NcPlane) -> NcChannel { - channels_bg_rgb(unsafe { ncplane_channels(plane) }) -} +/// I/O wrapper to dump file descriptor to [`NcPlane`] +/// +/// `type in C: ncfdplane (struct)` +pub type NcFdPlane = crate::bindings::bindgen::ncfdplane; -/// Extract 2 bits of foreground alpha from 'struct ncplane', shifted to LSBs. -#[inline] -pub fn ncplane_fg_alpha(plane: &NcPlane) -> NcAlphaBits { - channels_fg_alpha(unsafe { ncplane_channels(plane) }) -} +/// Options struct for [`NcFdPlane`] +/// +/// `type in C: ncplane_options (struct)` +pub type NcFdPlaneOptions = crate::bindings::bindgen::ncfdplane_options; -/// Extract 2 bits of background alpha from 'struct ncplane', shifted to LSBs. -#[inline] -pub fn ncplane_bg_alpha(plane: &NcPlane) -> NcAlphaBits { - channels_bg_alpha(unsafe { ncplane_channels(plane) }) -} +/// Alignment within a plane or terminal. +/// Left/right-justified, or centered. +pub type NcAlign = crate::bindings::bindgen::ncalign_e; -/// Is the plane's foreground using the "default foreground color"? -#[inline] -pub fn ncplane_fg_default_p(plane: &NcPlane) -> bool { - channels_fg_default_p(unsafe { ncplane_channels(plane) }) -} +/// Left alignment within an [`NcPlane`] or terminal. +pub const NCALIGN_LEFT: NcAlign = crate::bindings::bindgen::ncalign_e_NCALIGN_LEFT; -/// Is the plane's background using the "default background color"? -#[inline] -pub fn ncplane_bg_default_p(plane: &NcPlane) -> bool { - channels_bg_default_p(unsafe { ncplane_channels(plane) }) -} +/// Right alignment within an [`NcPlane`] or terminal. +pub const NCALIGN_RIGHT: NcAlign = crate::bindings::bindgen::ncalign_e_NCALIGN_RIGHT; -/// Extract 24 bits of foreground RGB from a plane, split into components. -#[inline] -pub fn ncplane_fg_rgb8( - plane: &NcPlane, - red: &mut NcColor, - green: &mut NcColor, - blue: &mut NcColor, -) -> NcChannel { - channels_fg_rgb8(unsafe { ncplane_channels(plane) }, red, green, blue) -} +/// Center alignment within an [`NcPlane`] or terminal. +pub const NCALIGN_CENTER: NcAlign = crate::bindings::bindgen::ncalign_e_NCALIGN_CENTER; -/// Extract 24 bits of background RGB from a plane, split into components. -#[inline] -pub fn ncplane_bg_rgb8( - plane: &NcPlane, - red: &mut NcColor, - green: &mut NcColor, - blue: &mut NcColor, -) -> NcChannel { - channels_bg_rgb8(unsafe { ncplane_channels(plane) }, red, green, blue) -} +/// Do not align an [`NcPlane`] or terminal. +pub const NCALIGN_UNALIGNED: NcAlign = crate::bindings::bindgen::ncalign_e_NCALIGN_UNALIGNED; +/// Blitter Mode (`NCBLIT_*`) /// -#[inline] -pub fn ncplane_rounded_box( - plane: &mut NcPlane, - stylemask: NcStyleMask, - channels: NcChannelPair, - ystop: i32, - xstop: i32, - ctlword: u32, -) -> NcResult { - #[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(); +/// 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_SIXEL`] +/// +pub type NcBlitter = crate::bindings::bindgen::ncblitter_e; - unsafe { - ret = cells_rounded_box( - plane, - stylemask as u32, - channels, - &mut ul, - &mut ur, - &mut ll, - &mut lr, - &mut hl, - &mut vl, - ); - if ret == NCRESULT_OK { - ret = ncplane_box(plane, &ul, &ur, &ll, &lr, &hl, &vl, ystop, xstop, ctlword); - } - cell_release(plane, &mut ul); - cell_release(plane, &mut ur); - cell_release(plane, &mut ll); - cell_release(plane, &mut lr); - cell_release(plane, &mut hl); - cell_release(plane, &mut vl); - } - ret -} +/// [`NcBlitter`] mode using: space, compatible with ASCII +pub const NCBLIT_1x1: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_1x1; -/// -#[inline] -pub fn ncplane_rounded_box_sized( - plane: &mut NcPlane, - stylemask: NcStyleMask, - channels: NcChannelPair, - ylen: i32, - xlen: i32, - ctlword: u32, -) -> NcResult { - let (mut y, mut x) = (0, 0); - unsafe { - ncplane_cursor_yx(plane, &mut y, &mut x); - } - ncplane_rounded_box( - plane, - stylemask, - channels, - y + ylen - 1, - x + xlen - 1, - ctlword, - ) -} +/// [`NcBlitter`] mode using: halves + 1x1 (space) +/// ▄▀ +pub const NCBLIT_2x1: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_2x1; -// static inline int -// ncplane_printf(struct ncplane* n, const char* format, ...) -// __attribute__ ((format (printf, 2, 3))); +/// [`NcBlitter`] mode using: quadrants + 2x1 +/// ▗▐ ▖▀▟▌▙ +pub const NCBLIT_2x2: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_2x2; -// static inline int -// ncplane_printf(struct ncplane* n, const char* format, ...){ -// va_list va; -// va_start(va, format); -// int ret = ncplane_vprintf(n, format, va); -// va_end(va); -// return ret; -// } +/// [`NcBlitter`] mode using: sextants +/// 🬀🬁🬂🬃🬄🬅🬆🬇🬈🬉🬊🬋🬌🬍🬎🬏🬐🬑🬒🬓🬔🬕🬖🬗🬘🬙🬚🬛🬜🬝🬞🬟🬠🬡🬢🬣🬤🬥🬦🬧🬨🬩🬪🬫🬬🬭🬮🬯🬰🬱🬲🬳🬴🬵🬶🬷🬸🬹🬺🬻 +pub const NCBLIT_3x2: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_3x2; -// static inline int -// ncplane_printf_yx(struct ncplane* n, int y, int x, const char* format, ...) -// __attribute__ ((format (printf, 4, 5))); +/// [`NcBlitter`] mode using: four vertical levels +/// █▆▄▂ +pub const NCBLIT_4x1: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_4x1; -// static inline int -// ncplane_printf_yx(struct ncplane* n, int y, int x, const char* format, ...){ -// va_list va; -// va_start(va, format); -// int ret = ncplane_vprintf_yx(n, y, x, format, va); -// va_end(va); -// return ret; -// } +/// [`NcBlitter`] mode using: eight vertical levels +/// █▇▆▅▄▃▂▁ +pub const NCBLIT_8x1: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_8x1; -// static inline int -// ncplane_printf_aligned(struct ncplane* n, int y, ncalign_e align, -// const char* format, ...) -// __attribute__ ((format (printf, 4, 5))); +/// [`NcBlitter`] mode using: 4 rows, 2 cols (braille) +/// ⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿ +pub const NCBLIT_BRAILLE: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_BRAILLE; -// static inline int -// ncplane_printf_aligned(struct ncplane* n, int y, ncalign_e align, const char* format, ...){ -// va_list va; -// va_start(va, format); -// int ret = ncplane_vprintf_aligned(n, y, align, format, va); -// va_end(va); -// return ret; -// } +/// [`NcBlitter`] mode where the blitter is automatically chosen +pub const NCBLIT_DEFAULT: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_DEFAULT; -// static inline int -// ncplane_printf_stained(struct ncplane* n, const char* format, ...) -// __attribute__ ((format (printf, 2, 3))); +/// [`NcBlitter`] mode (not yet implemented) +pub const NCBLIT_SIXEL: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_SIXEL; -// static inline int -// ncplane_printf_stained(struct ncplane* n, const char* format, ...){ -// va_list va; -// va_start(va, format); -// int ret = ncplane_vprintf_stained(n, format, va); -// va_end(va); -// return ret; -// } +/// 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. +/// +pub type NcScale = crate::bindings::bindgen::ncscale_e; +/// Maintain original size +pub const NCSCALE_NONE: NcScale = crate::bindings::bindgen::ncscale_e_NCSCALE_NONE; +/// Maintain aspect ratio +pub const NCSCALE_SCALE: NcScale = crate::bindings::bindgen::ncscale_e_NCSCALE_SCALE; +/// Throw away aspect ratio +pub const NCSCALE_STRETCH: NcScale = crate::bindings::bindgen::ncscale_e_NCSCALE_STRETCH; + +/// A visual bit of multimedia opened with LibAV|OIIO +pub type NcVisual = crate::bindings::bindgen::ncvisual; +/// Options struct for [`NcVisual`] +pub type NcVisualOptions = crate::bindings::bindgen::ncvisual_options; + +/// Use [`NCCELL_ALPHA_BLEND`] with visual +pub const NCVISUAL_OPTION_BLEND: u32 = crate::bindings::bindgen::NCVISUAL_OPTION_BLEND; + +/// Fail rather than degrade +pub const NCVISUAL_OPTION_NODEGRADE: u32 = crate::bindings::bindgen::NCVISUAL_OPTION_NODEGRADE; diff --git a/rust/src/plane/reimplemented.rs b/rust/src/plane/reimplemented.rs new file mode 100644 index 000000000..593f66aa0 --- /dev/null +++ b/rust/src/plane/reimplemented.rs @@ -0,0 +1,644 @@ +//! `ncplane_*` reimplemented functions. + +use core::{ffi::c_void, ptr::null_mut}; +use libc::free; +use std::ffi::CString; + +use crate::{ + bindgen::__va_list_tag, cell_load, cell_release, cells_double_box, cells_rounded_box, + channels_bchannel, channels_bg_alpha, channels_bg_default_p, channels_bg_rgb, channels_bg_rgb8, + channels_fchannel, channels_fg_alpha, channels_fg_default_p, channels_fg_rgb, channels_fg_rgb8, + ncplane_at_cursor, ncplane_at_yx, ncplane_box, ncplane_channels, ncplane_cursor_move_yx, + ncplane_cursor_yx, ncplane_dim_yx, ncplane_gradient, ncplane_hline_interp, ncplane_putc_yx, + ncplane_putegc_yx, ncplane_putnstr_yx, ncplane_putstr_yx, ncplane_resize, ncplane_styles, + ncplane_vline_interp, ncplane_vprintf_yx, notcurses_align, NcAlign, NcAlphaBits, NcCell, + NcChannel, NcChannelPair, NcColor, NcPlane, NcResult, NcStyleMask, NCRESULT_ERR, NCRESULT_OK, +}; + +/// Return the column at which 'cols' columns ought start in order to be aligned +/// according to 'align' within ncplane 'n'. Returns INT_MAX on invalid 'align'. +/// Undefined behavior on negative 'cols'. +// +// NOTE: [leave cols as i32](https://github.com/dankamongmen/notcurses/issues/904) +#[inline] +pub fn ncplane_align(plane: &NcPlane, align: NcAlign, cols: i32) -> i32 { + notcurses_align(ncplane_dim_x(plane), align, cols) +} + +/// Retrieve the current contents of the cell under the cursor into 'cell'. +/// This cell is invalidated if the associated plane is destroyed. +#[inline] +pub fn ncplane_at_cursor_cell(plane: &mut NcPlane, cell: &mut NcCell) -> NcResult { + let mut egc = unsafe { ncplane_at_cursor(plane, &mut cell.stylemask, &mut cell.channels) }; + if egc.is_null() { + return NCRESULT_ERR; + } + let result: NcResult = unsafe { cell_load(plane, cell, egc) }; + if result != NCRESULT_OK { + unsafe { + free(&mut egc as *mut _ as *mut c_void); + } + } + result +} + +/// Retrieve the current contents of the specified cell into 'cell'. +/// This cell is invalidated if the associated plane is destroyed. +#[inline] +pub fn ncplane_at_yx_cell(plane: &mut NcPlane, y: i32, x: i32, cell: &mut NcCell) -> NcResult { + let mut egc = unsafe { ncplane_at_yx(plane, y, x, &mut cell.stylemask, &mut cell.channels) }; + if egc.is_null() { + return NCRESULT_ERR; + } + let channels = cell.channels; // need to preserve wide flag + let result: NcResult = unsafe { cell_load(plane, cell, egc) }; + cell.channels = channels; + unsafe { + free(&mut egc as *mut _ as *mut c_void); + } + result +} + +/// Draw a box with its upper-left corner at the current cursor position, having +/// dimensions 'ylen'x'xlen'. See ncplane_box() for more information. The +/// minimum box size is 2x2, and it cannot be drawn off-screen. +#[inline] +pub fn ncplane_box_sized( + plane: &mut NcPlane, + ul: &NcCell, + ur: &NcCell, + ll: &NcCell, + lr: &NcCell, + hline: &NcCell, + vline: &NcCell, + ylen: i32, + xlen: i32, + ctlword: u32, +) -> NcResult { + let (mut y, mut x) = (0, 0); + unsafe { + ncplane_cursor_yx(plane, &mut y, &mut x); + ncplane_box( + plane, + ul, + ur, + ll, + lr, + hline, + vline, + y + ylen - 1, + x + xlen - 1, + ctlword, + ) + } +} + +/// +#[inline] +pub fn ncplane_dim_x(plane: &NcPlane) -> i32 { + unsafe { + let mut x = 0; + ncplane_dim_yx(plane, null_mut(), &mut x); + x + } +} + +/// +#[inline] +pub fn ncplane_dim_y(plane: &NcPlane) -> i32 { + unsafe { + let mut y = 0; + ncplane_dim_yx(plane, &mut y, null_mut()); + y + } +} + +/// +#[inline] +pub fn ncplane_double_box( + plane: &mut NcPlane, + stylemask: NcStyleMask, + channels: NcChannelPair, + ystop: i32, + xstop: i32, + ctlword: u32, +) -> NcResult { + #[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 = cells_double_box( + plane, + stylemask as u32, + channels, + &mut ul, + &mut ur, + &mut ll, + &mut lr, + &mut hl, + &mut vl, + ); + if ret == NCRESULT_OK { + ret = ncplane_box(plane, &ul, &ur, &ll, &lr, &hl, &vl, ystop, xstop, ctlword); + } + + cell_release(plane, &mut ul); + cell_release(plane, &mut ur); + cell_release(plane, &mut ll); + cell_release(plane, &mut lr); + cell_release(plane, &mut hl); + cell_release(plane, &mut vl); + } + ret +} + +/// +#[inline] +pub fn ncplane_double_box_sized( + plane: &mut NcPlane, + stylemask: NcStyleMask, + channels: NcChannelPair, + ylen: i32, + xlen: i32, + ctlword: u32, +) -> NcResult { + let (mut y, mut x) = (0, 0); + unsafe { + ncplane_cursor_yx(plane, &mut y, &mut x); + } + ncplane_double_box( + plane, + stylemask, + channels, + y + ylen - 1, + x + xlen - 1, + ctlword, + ) +} + +/// On error, return the negative number of cells drawn. +#[inline] +pub fn ncplane_hline(plane: &mut NcPlane, cell: &NcCell, len: i32) -> i32 { + unsafe { ncplane_hline_interp(plane, cell, len, cell.channels, cell.channels) } +} + +/// +#[inline] +pub fn ncplane_perimeter( + plane: &mut NcPlane, + ul: &NcCell, + ur: &NcCell, + ll: &NcCell, + lr: &NcCell, + hline: &NcCell, + vline: &NcCell, + ctlword: u32, +) -> NcResult { + unsafe { + ncplane_cursor_move_yx(plane, 0, 0); + let (mut dimy, mut dimx) = (0, 0); + ncplane_dim_yx(plane, &mut dimy, &mut dimx); + ncplane_box_sized(plane, ul, ur, ll, lr, hline, vline, dimy, dimx, ctlword) + } +} + +/// +#[inline] +pub fn ncplane_perimeter_double( + plane: &mut NcPlane, + stylemask: NcStyleMask, + channels: NcChannelPair, + ctlword: u32, +) -> NcResult { + if unsafe { ncplane_cursor_move_yx(plane, 0, 0) } != NCRESULT_OK { + return NCRESULT_ERR; + } + let (mut dimy, mut dimx) = (0, 0); + unsafe { + 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 { + cells_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, dimx, ctlword); + unsafe { + cell_release(plane, &mut ul); + cell_release(plane, &mut ur); + cell_release(plane, &mut ll); + cell_release(plane, &mut lr); + cell_release(plane, &mut hl); + cell_release(plane, &mut vl); + } + ret +} + +/// +#[inline] +pub fn ncplane_perimeter_rounded( + plane: &mut NcPlane, + stylemask: NcStyleMask, + channels: NcChannelPair, + ctlword: u32, +) -> NcResult { + if unsafe { ncplane_cursor_move_yx(plane, 0, 0) } != NCRESULT_OK { + return NCRESULT_ERR; + } + let (mut dimy, mut dimx) = (0, 0); + unsafe { + 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 { + cells_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, dimx, ctlword); + unsafe { + cell_release(plane, &mut ul); + cell_release(plane, &mut ur); + cell_release(plane, &mut ll); + cell_release(plane, &mut lr); + cell_release(plane, &mut hl); + cell_release(plane, &mut vl); + } + ret +} + +/// Call ncplane_putc_yx() for the current cursor location. +#[inline] +pub fn ncplane_putc(plane: &mut NcPlane, cell: &NcCell) -> NcResult { + unsafe { ncplane_putc_yx(plane, -1, -1, cell) } +} + +/// Call ncplane_putchar_yx() at the current cursor location. +#[inline] +pub fn ncplane_putchar(plane: &mut NcPlane, c: char) -> NcResult { + ncplane_putchar_yx(plane, -1, -1, c) +} + +/// Replace the EGC underneath us, but retain the styling. The current styling +/// of the plane will not be changed. +/// +/// Replace the cell at the specified coordinates with the provided 7-bit char +/// 'c'. Advance the cursor by 1. On success, returns 1. On failure, returns -1. +/// This works whether the underlying char is signed or unsigned. +#[inline] +// TODO: test char is < 8bit (currently 32bit) +pub fn ncplane_putchar_yx(plane: &mut NcPlane, y: i32, x: i32, c: char) -> NcResult { + unsafe { + let ce = NcCell::with_all(c, ncplane_styles(plane), ncplane_channels(plane)); + ncplane_putc_yx(plane, y, x, &ce) + } +} + +/// Call ncplane_putegc() at the current cursor location. +#[inline] +pub fn ncplane_putegc(plane: &mut NcPlane, gcluster: i8, sbytes: &mut i32) -> NcResult { + unsafe { ncplane_putegc_yx(plane, -1, -1, &gcluster, sbytes) } +} + +/// +#[inline] +pub fn ncplane_putstr(plane: &mut NcPlane, string: &str) -> NcResult { + unsafe { + ncplane_putstr_yx( + plane, + -1, + -1, + CString::new(string.as_bytes()) + .expect("Bad string") + .as_ptr(), + ) + } +} + +/// +#[inline] +pub fn ncplane_putnstr(plane: &mut NcPlane, size: u64, gclustarr: &[u8]) -> NcResult { + unsafe { + ncplane_putnstr_yx( + plane, + -1, + -1, + size, + CString::new(gclustarr).expect("Bad string").as_ptr(), + ) + } +} + +/// Resize the plane, retaining what data we can (everything, unless we're +/// shrinking in some dimension). Keep the origin where it is. +#[inline] +pub fn ncplane_resize_simple(plane: &mut NcPlane, ylen: i32, xlen: i32) -> NcResult { + let (mut oldy, mut oldx) = (0, 0); + unsafe { + ncplane_dim_yx(plane, &mut oldy, &mut oldx); + } + let keepleny = { + if oldy > ylen { + ylen + } else { + oldy + } + }; + let keeplenx = { + if oldx > xlen { + xlen + } else { + oldx + } + }; + unsafe { ncplane_resize(plane, 0, 0, keepleny, keeplenx, 0, 0, ylen, xlen) } +} + +/// +/// On error, return the negative number of cells drawn. +#[inline] +pub fn ncplane_vline(plane: &mut NcPlane, cell: &NcCell, len: i32) -> i32 { + unsafe { ncplane_vline_interp(plane, cell, len, cell.channels, cell.channels) } +} + +/// +#[inline] +pub fn ncplane_vprintf(plane: &mut NcPlane, format: &str, ap: &mut __va_list_tag) -> NcResult { + unsafe { + ncplane_vprintf_yx( + plane, + -1, + -1, + CString::new(format).expect("Bad string").as_ptr(), + ap, + ) + } +} + +/// Draw a gradient with its upper-left corner at the current cursor position, +/// having dimensions 'ylen'x'xlen'. See ncplane_gradient for more information. +/// static inline int +// XXX receive cells as u32? https://github.com/dankamongmen/notcurses/issues/920 +#[inline] +pub fn ncplane_gradient_sized( + plane: &mut NcPlane, + egc: &[u8], + stylemask: NcStyleMask, + ul: u64, + ur: u64, + ll: u64, + lr: u64, + ylen: i32, + xlen: i32, +) -> NcResult { + if ylen < 1 || xlen < 1 { + return NCRESULT_ERR; + } + let (mut y, mut x) = (0, 0); + unsafe { + ncplane_cursor_yx(plane, &mut y, &mut x); + ncplane_gradient( + plane, + CString::new(egc).expect("Bad EGC").as_ptr(), + stylemask as u32, + ul, + ur, + ll, + lr, + y + ylen - 1, + x + xlen - 1, + ) + } +} + +/// Extract the 32-bit working foreground channel from an ncplane. +#[inline] +pub fn ncplane_fchannel(plane: &NcPlane) -> NcChannel { + channels_fchannel(unsafe { ncplane_channels(plane) }) +} + +/// Extract the 32-bit working background channel from an ncplane. +#[inline] +pub fn ncplane_bchannel(plane: &NcPlane) -> NcChannel { + channels_bchannel(unsafe { ncplane_channels(plane) }) +} + +/// Extract 24 bits of working foreground RGB from an ncplane, shifted to LSBs. +#[inline] +pub fn ncplane_fg_rgb(plane: &NcPlane) -> NcChannel { + channels_fg_rgb(unsafe { ncplane_channels(plane) }) +} + +/// Extract 24 bits of working background RGB from an ncplane, shifted to LSBs. +#[inline] +pub fn ncplane_bg_rgb(plane: &NcPlane) -> NcChannel { + channels_bg_rgb(unsafe { ncplane_channels(plane) }) +} + +/// Extract 2 bits of foreground alpha from 'struct ncplane', shifted to LSBs. +#[inline] +pub fn ncplane_fg_alpha(plane: &NcPlane) -> NcAlphaBits { + channels_fg_alpha(unsafe { ncplane_channels(plane) }) +} + +/// Extract 2 bits of background alpha from 'struct ncplane', shifted to LSBs. +#[inline] +pub fn ncplane_bg_alpha(plane: &NcPlane) -> NcAlphaBits { + channels_bg_alpha(unsafe { ncplane_channels(plane) }) +} + +/// Is the plane's foreground using the "default foreground color"? +#[inline] +pub fn ncplane_fg_default_p(plane: &NcPlane) -> bool { + channels_fg_default_p(unsafe { ncplane_channels(plane) }) +} + +/// Is the plane's background using the "default background color"? +#[inline] +pub fn ncplane_bg_default_p(plane: &NcPlane) -> bool { + channels_bg_default_p(unsafe { ncplane_channels(plane) }) +} + +/// Extract 24 bits of foreground RGB from a plane, split into components. +#[inline] +pub fn ncplane_fg_rgb8( + plane: &NcPlane, + red: &mut NcColor, + green: &mut NcColor, + blue: &mut NcColor, +) -> NcChannel { + channels_fg_rgb8(unsafe { ncplane_channels(plane) }, red, green, blue) +} + +/// Extract 24 bits of background RGB from a plane, split into components. +#[inline] +pub fn ncplane_bg_rgb8( + plane: &NcPlane, + red: &mut NcColor, + green: &mut NcColor, + blue: &mut NcColor, +) -> NcChannel { + channels_bg_rgb8(unsafe { ncplane_channels(plane) }, red, green, blue) +} + +/// +#[inline] +pub fn ncplane_rounded_box( + plane: &mut NcPlane, + stylemask: NcStyleMask, + channels: NcChannelPair, + ystop: i32, + xstop: i32, + ctlword: u32, +) -> NcResult { + #[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 = cells_rounded_box( + plane, + stylemask as u32, + channels, + &mut ul, + &mut ur, + &mut ll, + &mut lr, + &mut hl, + &mut vl, + ); + if ret == NCRESULT_OK { + ret = ncplane_box(plane, &ul, &ur, &ll, &lr, &hl, &vl, ystop, xstop, ctlword); + } + cell_release(plane, &mut ul); + cell_release(plane, &mut ur); + cell_release(plane, &mut ll); + cell_release(plane, &mut lr); + cell_release(plane, &mut hl); + cell_release(plane, &mut vl); + } + ret +} + +/// +#[inline] +pub fn ncplane_rounded_box_sized( + plane: &mut NcPlane, + stylemask: NcStyleMask, + channels: NcChannelPair, + ylen: i32, + xlen: i32, + ctlword: u32, +) -> NcResult { + let (mut y, mut x) = (0, 0); + unsafe { + ncplane_cursor_yx(plane, &mut y, &mut x); + } + ncplane_rounded_box( + plane, + stylemask, + channels, + y + ylen - 1, + x + xlen - 1, + ctlword, + ) +} + +// static inline int +// ncplane_printf(struct ncplane* n, const char* format, ...) +// __attribute__ ((format (printf, 2, 3))); + +// static inline int +// ncplane_printf(struct ncplane* n, const char* format, ...){ +// va_list va; +// va_start(va, format); +// int ret = ncplane_vprintf(n, format, va); +// va_end(va); +// return ret; +// } + +// static inline int +// ncplane_printf_yx(struct ncplane* n, int y, int x, const char* format, ...) +// __attribute__ ((format (printf, 4, 5))); + +// static inline int +// ncplane_printf_yx(struct ncplane* n, int y, int x, const char* format, ...){ +// va_list va; +// va_start(va, format); +// int ret = ncplane_vprintf_yx(n, y, x, format, va); +// va_end(va); +// return ret; +// } + +// static inline int +// ncplane_printf_aligned(struct ncplane* n, int y, ncalign_e align, +// const char* format, ...) +// __attribute__ ((format (printf, 4, 5))); + +// static inline int +// ncplane_printf_aligned(struct ncplane* n, int y, ncalign_e align, const char* format, ...){ +// va_list va; +// va_start(va, format); +// int ret = ncplane_vprintf_aligned(n, y, align, format, va); +// va_end(va); +// return ret; +// } + +// static inline int +// ncplane_printf_stained(struct ncplane* n, const char* format, ...) +// __attribute__ ((format (printf, 2, 3))); + +// static inline int +// ncplane_printf_stained(struct ncplane* n, const char* format, ...){ +// va_list va; +// va_start(va, format); +// int ret = ncplane_vprintf_stained(n, format, va); +// va_end(va); +// return ret; +// } diff --git a/rust/src/plane/test/methods.rs b/rust/src/plane/test/methods.rs new file mode 100644 index 000000000..d2311dac6 --- /dev/null +++ b/rust/src/plane/test/methods.rs @@ -0,0 +1,4 @@ +//! Test `NcPlane` methods and associated functions. + +// use crate::NcPlane; +// use serial_test::serial; diff --git a/rust/src/plane/test/mod.rs b/rust/src/plane/test/mod.rs new file mode 100644 index 000000000..2f66f6c89 --- /dev/null +++ b/rust/src/plane/test/mod.rs @@ -0,0 +1,7 @@ +//! `NcPlane` tests. + +#[cfg(test)] +mod methods; + +#[cfg(test)] +mod reimplemented; diff --git a/rust/src/plane/tests.rs b/rust/src/plane/test/reimplemented.rs similarity index 93% rename from rust/src/plane/tests.rs rename to rust/src/plane/test/reimplemented.rs index 8a3413c17..1335df821 100644 --- a/rust/src/plane/tests.rs +++ b/rust/src/plane/test/reimplemented.rs @@ -1,4 +1,4 @@ -//! [`NcPlane`] tests +//! Test `ncplane_*` reimplemented functions. use crate::{notcurses_stop, NcPlane, NcPlaneOptions, Notcurses, NCRESULT_OK}; use serial_test::serial; @@ -233,3 +233,25 @@ fn ncplane_erase() { notcurses_stop(nc); } } + +// #[test] +// #[serial] +// fn ncplane_at_cursor() { +// unsafe { +// let nc = Notcurses::new(); +// let plane = NcPlane::new(nc, 0, 0, 20, 20); +// +// notcurses_stop(nc); +// } +// } +// +// #[test] +// #[serial] +// fn ncplane_at_cursor_cell() { +// unsafe { +// let nc = Notcurses::new(); +// let plane = NcPlane::new(nc, 0, 0, 20, 20); +// +// notcurses_stop(nc); +// } +// } diff --git a/rust/src/plane/types.rs b/rust/src/plane/types.rs deleted file mode 100644 index 2f6b7054b..000000000 --- a/rust/src/plane/types.rs +++ /dev/null @@ -1,156 +0,0 @@ -#[allow(unused_imports)] // for docblocks -use crate::NCCELL_ALPHA_BLEND; - -// NcPlane -/// Fundamental drawing surface. -/// -/// Unites a: -/// - CellMatrix -/// - EgcPool -/// -/// `type in C: ncplane (struct)` -/// -/// -/// ## Piles -/// -/// A single notcurses context is made up of one or more piles. -/// -/// A pile is a set of one or more ncplanes, including the partial orderings -/// made up of their binding and z-axis pointers. -/// -/// A pile has a top and bottom ncplane (this might be a single plane), -/// and one or more root planes (planes which are bound to themselves). -/// -/// Multiple threads can concurrently operate on distinct piles, even changing -/// one while rendering another. -/// -/// Each plane is part of one and only one pile. By default, a plane is part of -/// the same pile containing that plane to which it is bound. -/// -/// If ncpile_create is used in the place of ncplane_create, the returned plane -/// 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 a plane to itself, -/// though if the plane is already a root plane, this is a no-op. -/// -/// When a plane is moved to a different pile (whether new or preexisting), -/// any planes which were bound to it are rebound to its previous parent. -/// If the plane was a root plane of some pile, any bound planes become root -/// planes. The new plane is placed immediately atop its new parent on its new -/// pile's z-axis. When ncplane_reparent_family() is used, all planes bound to -/// the reparented plane are moved along with it. Their relative z-order is maintained. -/// -pub type NcPlane = crate::bindings::bindgen::ncplane; - -/// Options struct for [`NcPlane`] -pub type NcPlaneOptions = crate::bindings::bindgen::ncplane_options; - -/// Horizontal alignment relative to the parent plane. Set alignment in 'x'. -pub const NCPLANE_OPTION_HORALIGNED: u64 = - crate::bindings::bindgen::NCPLANE_OPTION_HORALIGNED as u64; - -/// I/O wrapper to dump file descriptor to [`NcPlane`] -/// -/// `type in C: ncfdplane (struct)` -pub type NcFdPlane = crate::bindings::bindgen::ncfdplane; - -/// Options struct for [`NcFdPlane`] -/// -/// `type in C: ncplane_options (struct)` -pub type NcFdPlaneOptions = crate::bindings::bindgen::ncfdplane_options; - -/// Alignment within a plane or terminal. -/// Left/right-justified, or centered. -pub type NcAlign = crate::bindings::bindgen::ncalign_e; - -/// Left alignment within an [`NcPlane`] or terminal. -pub const NCALIGN_LEFT: NcAlign = crate::bindings::bindgen::ncalign_e_NCALIGN_LEFT; - -/// Right alignment within an [`NcPlane`] or terminal. -pub const NCALIGN_RIGHT: NcAlign = crate::bindings::bindgen::ncalign_e_NCALIGN_RIGHT; - -/// Center alignment within an [`NcPlane`] or terminal. -pub const NCALIGN_CENTER: NcAlign = crate::bindings::bindgen::ncalign_e_NCALIGN_CENTER; - -/// Do not align an [`NcPlane`] or terminal. -pub const NCALIGN_UNALIGNED: NcAlign = crate::bindings::bindgen::ncalign_e_NCALIGN_UNALIGNED; - -/// Blitter Mode (`NCBLIT_*`) -/// -/// 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_SIXEL`] -/// -pub type NcBlitter = crate::bindings::bindgen::ncblitter_e; - -/// [`NcBlitter`] mode using: space, compatible with ASCII -pub const NCBLIT_1x1: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_1x1; - -/// [`NcBlitter`] mode using: halves + 1x1 (space) -/// ▄▀ -pub const NCBLIT_2x1: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_2x1; - -/// [`NcBlitter`] mode using: quadrants + 2x1 -/// ▗▐ ▖▀▟▌▙ -pub const NCBLIT_2x2: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_2x2; - -/// [`NcBlitter`] mode using: sextants -/// 🬀🬁🬂🬃🬄🬅🬆🬇🬈🬉🬊🬋🬌🬍🬎🬏🬐🬑🬒🬓🬔🬕🬖🬗🬘🬙🬚🬛🬜🬝🬞🬟🬠🬡🬢🬣🬤🬥🬦🬧🬨🬩🬪🬫🬬🬭🬮🬯🬰🬱🬲🬳🬴🬵🬶🬷🬸🬹🬺🬻 -pub const NCBLIT_3x2: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_3x2; - -/// [`NcBlitter`] mode using: four vertical levels -/// █▆▄▂ -pub const NCBLIT_4x1: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_4x1; - -/// [`NcBlitter`] mode using: eight vertical levels -/// █▇▆▅▄▃▂▁ -pub const NCBLIT_8x1: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_8x1; - -/// [`NcBlitter`] mode using: 4 rows, 2 cols (braille) -/// ⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿ -pub const NCBLIT_BRAILLE: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_BRAILLE; - -/// [`NcBlitter`] mode where the blitter is automatically chosen -pub const NCBLIT_DEFAULT: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_DEFAULT; - -/// [`NcBlitter`] mode (not yet implemented) -pub const NCBLIT_SIXEL: NcBlitter = crate::bindings::bindgen::ncblitter_e_NCBLIT_SIXEL; - -/// 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. -/// -pub type NcScale = crate::bindings::bindgen::ncscale_e; -/// Maintain original size -pub const NCSCALE_NONE: NcScale = crate::bindings::bindgen::ncscale_e_NCSCALE_NONE; -/// Maintain aspect ratio -pub const NCSCALE_SCALE: NcScale = crate::bindings::bindgen::ncscale_e_NCSCALE_SCALE; -/// Throw away aspect ratio -pub const NCSCALE_STRETCH: NcScale = crate::bindings::bindgen::ncscale_e_NCSCALE_STRETCH; - -/// A visual bit of multimedia opened with LibAV|OIIO -pub type NcVisual = crate::bindings::bindgen::ncvisual; -/// Options struct for [`NcVisual`] -pub type NcVisualOptions = crate::bindings::bindgen::ncvisual_options; - -/// Use [`NCCELL_ALPHA_BLEND`] with visual -pub const NCVISUAL_OPTION_BLEND: u32 = crate::bindings::bindgen::NCVISUAL_OPTION_BLEND; - -/// Fail rather than degrade -pub const NCVISUAL_OPTION_NODEGRADE: u32 = crate::bindings::bindgen::NCVISUAL_OPTION_NODEGRADE; diff --git a/rust/src/visual.rs b/rust/src/visual.rs index d0bb844e5..e35f534b2 100644 --- a/rust/src/visual.rs +++ b/rust/src/visual.rs @@ -1,29 +1,33 @@ +//! `ncvisual` + // functions already exported by bindgen : 17 // ----------------------------------------- -// ncvisual_at_yx -// ncvisual_decode -// ncvisual_decode_loop -// ncvisual_destroy -// ncvisual_from_bgra -// ncvisual_from_file -// ncvisual_from_plane -// ncvisual_from_rgba -// ncvisual_geom -// ncvisual_polyfill_yx -// ncvisual_render -// ncvisual_resize -// ncvisual_rotate -// ncvisual_set_yx -// ncvisual_simple_streamer -// ncvisual_stream -// ncvisual_subtitle +// (#) test: 0 / 17 +// ----------------------------------------- +// ncvisual_at_yx +// ncvisual_decode +// ncvisual_decode_loop +// ncvisual_destroy +// ncvisual_from_bgra +// ncvisual_from_file +// ncvisual_from_plane +// ncvisual_from_rgba +// ncvisual_geom +// ncvisual_polyfill_yx +// ncvisual_render +// ncvisual_resize +// ncvisual_rotate +// ncvisual_set_yx +// ncvisual_simple_streamer +// ncvisual_stream +// ncvisual_subtitle // -// static inline functions total: 1 -// ------------------------------------------ (done / remaining) +// functions manually reimplemented: 1 +// ------------------------------------------ // (+) done: 1 / 0 // (#) test: 0 / 1 // ------------------------------------------ -// ncvisual_default_blitter +// + ncvisual_default_blitter use crate::{NCBLIT_1x1, NCBLIT_2x1, NCBLIT_2x2, NcBlitter, NcScale, NCSCALE_STRETCH}; @@ -41,15 +45,3 @@ pub fn ncvisual_default_blitter(utf8: bool, scale: NcScale) -> NcBlitter { } NCBLIT_1x1 } - -#[cfg(test)] -mod test { - // use super::nc; - // use serial_test::serial; - /* - #[test] - #[serial] - fn () { - } - */ -} diff --git a/rust/src/widgets/menu/methods.rs b/rust/src/widgets/menu/methods.rs new file mode 100644 index 000000000..f7ad3121a --- /dev/null +++ b/rust/src/widgets/menu/methods.rs @@ -0,0 +1,85 @@ +//! `NcMenu*` methods and associated functions. + +use std::ffi::CString; + +use crate::{ + ncmenu_create, NcChannelPair, NcInput, NcMenu, NcMenuItem, NcMenuOptions, NcMenuSection, + NcPlane, +}; + +impl NcMenu { + /// `NcMenu` simple constructor + pub unsafe fn new<'a>(plane: &mut NcPlane) -> &'a mut Self { + Self::with_options(plane, &NcMenuOptions::new()) + } + + /// `NcMenu` constructor with options + pub unsafe fn with_options<'a>(plane: &mut NcPlane, options: &NcMenuOptions) -> &'a mut Self { + &mut *ncmenu_create(plane, options) + } +} + +impl NcMenuOptions { + /// `NcMenuOptions` simple constructor + pub fn new() -> Self { + Self::with_options(&mut [], 0, 0, 0, 0) + } + + /// `NcMenuOptions` width options + pub fn with_options( + sections: &mut [NcMenuSection], + count: u32, + headerc: NcChannelPair, + sectionc: NcChannelPair, + flags: u64, + ) -> Self { + Self { + // array of 'sectioncount' `MenuSection`s + sections: sections as *mut _ as *mut NcMenuSection, /// XXX TEST + + // must be positive TODO + sectioncount: count as i32, + + // styling for header + headerchannels: headerc, + + // styling for sections + sectionchannels: sectionc, + + // flag word of NCMENU_OPTION_* + flags: flags, + } + } +} + +impl NcMenuItem { + /// `NcMenuItem` simple constructor + pub fn new(mut desc: i8, shortcut: NcInput) -> Self { + Self { + // utf-8 menu item, NULL for horizontal separator + desc: &mut desc, + + // ´NcInput´ shortcut, all should be distinct + shortcut, + } + } +} + +impl NcMenuSection { + /// `NcMenuSection` simple constructor + pub fn new(name: &str, itemcount: i32, items: &mut [NcMenuItem], shortcut: NcInput) -> Self { + Self { + // utf-8 name string + name: CString::new(name).expect("Bad string").as_ptr() as *mut i8, + + // + itemcount, + + // array of itemcount `NcMenuItem`s + items: items as *mut _ as *mut NcMenuItem, + + // shortcut, will be underlined if present in name + shortcut, + } + } +} diff --git a/rust/src/widgets/menu/mod.rs b/rust/src/widgets/menu/mod.rs index 2cd9c8e33..d726197df 100644 --- a/rust/src/widgets/menu/mod.rs +++ b/rust/src/widgets/menu/mod.rs @@ -2,101 +2,49 @@ // functions already exported by bindgen : 13 // ------------------------------------------ -// 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 - -mod types; -pub use types::{NcMenu, NcMenuItem, NcMenuOptions, NcMenuSection}; -pub use types::{NCMENU_OPTION_BOTTOM, NCMENU_OPTION_HIDING}; - -use std::ffi::CString; - -use crate::{ncmenu_create, NcChannelPair, NcInput, NcPlane}; - -impl NcMenu { - /// `NcMenu` simple constructor - pub unsafe fn new<'a>(plane: &mut NcPlane) -> &'a mut Self { - Self::with_options(plane, &NcMenuOptions::new()) - } - - /// `NcMenu` constructor with options - pub unsafe fn with_options<'a>(plane: &mut NcPlane, options: &NcMenuOptions) -> &'a mut Self { - &mut *ncmenu_create(plane, options) - } -} - -impl NcMenuOptions { - /// `NcMenuOptions` simple constructor - pub fn new() -> Self { - Self::with_options(&mut [], 0, 0, 0, 0) - } - - /// `NcMenuOptions` width options - pub fn with_options( - sections: &mut [NcMenuSection], - count: u32, - headerc: NcChannelPair, - sectionc: NcChannelPair, - flags: u64, - ) -> Self { - Self { - // array of 'sectioncount' `MenuSection`s - sections: sections as *mut _ as *mut NcMenuSection, /// XXX TEST - - // must be positive TODO - sectioncount: count as i32, - - // styling for header - headerchannels: headerc, - - // styling for sections - sectionchannels: sectionc, - - // flag word of NCMENU_OPTION_* - flags: flags, - } - } -} - -impl NcMenuItem { - /// `NcMenuItem` simple constructor - pub fn new(mut desc: i8, shortcut: NcInput) -> Self { - Self { - // utf-8 menu item, NULL for horizontal separator - desc: &mut desc, - - // ´NcInput´ shortcut, all should be distinct - shortcut, - } - } -} - -impl NcMenuSection { - /// `NcMenuSection` simple constructor - pub fn new(name: &str, itemcount: i32, items: &mut [NcMenuItem], shortcut: NcInput) -> Self { - Self { - // utf-8 name string - name: CString::new(name).expect("Bad string").as_ptr() as *mut i8, - - // - itemcount, - - // array of itemcount `NcMenuItem`s - items: items as *mut _ as *mut NcMenuItem, - - // shortcut, will be underlined if present in name - shortcut, - } - } -} +// 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 + +mod methods; + +/// menus on the top or bottom rows +/// +/// A notcurses instance supports menu bars on the top or bottom row of the true +/// screen. +/// +/// A menu is composed of sections, which are in turn composed of items. +/// Either no sections are visible, and the menu is rolled up, or exactly one +/// section is unrolled. +/// +/// `ncmenu_rollup` places an `NcMenu` in the rolled up state. +/// `ncmenu_unroll` rolls up any unrolled section and unrolls the specified one. +/// `ncmenu_destroy` removes a menu bar, and frees all associated resources. +/// +/// `type in C: ncmenu (struct)` +pub type NcMenu = crate::bindings::bindgen::ncmenu; + +/// Options struct for [`NcMenu`] +pub type NcMenuOptions = crate::bindings::bindgen::ncmenu_options; + +/// Item for [`NcMenu`] +pub type NcMenuItem = crate::bindings::bindgen::ncmenu_item; + +/// Section for [`NcMenu`] +pub type NcMenuSection = crate::bindings::bindgen::ncmenu_section; + +/// Bottom row (as opposed to top row) +pub const NCMENU_OPTION_BOTTOM: u32 = crate::bindings::bindgen::NCMENU_OPTION_BOTTOM; + +/// Hide the menu when not unrolled +pub const NCMENU_OPTION_HIDING: u32 = crate::bindings::bindgen::NCMENU_OPTION_HIDING; diff --git a/rust/src/widgets/menu/types.rs b/rust/src/widgets/menu/types.rs deleted file mode 100644 index 12b6f3e06..000000000 --- a/rust/src/widgets/menu/types.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! `NcMenu` widget types - -/// menus on the top or bottom rows -/// -/// A notcurses instance supports menu bars on the top or bottom row of the true -/// screen. -/// -/// A menu is composed of sections, which are in turn composed of items. -/// Either no sections are visible, and the menu is rolled up, or exactly one -/// section is unrolled. -/// -/// `ncmenu_rollup` places an `NcMenu` in the rolled up state. -/// `ncmenu_unroll` rolls up any unrolled section and unrolls the specified one. -/// `ncmenu_destroy` removes a menu bar, and frees all associated resources. -/// -/// `type in C: ncmenu (struct)` -pub type NcMenu = crate::bindings::bindgen::ncmenu; - -/// Options struct for [`NcMenu`] -pub type NcMenuOptions = crate::bindings::bindgen::ncmenu_options; - -/// Item for [`NcMenu`] -pub type NcMenuItem = crate::bindings::bindgen::ncmenu_item; - -/// Section for [`NcMenu`] -pub type NcMenuSection = crate::bindings::bindgen::ncmenu_section; - -/// Bottom row (as opposed to top row) -pub const NCMENU_OPTION_BOTTOM: u32 = crate::bindings::bindgen::NCMENU_OPTION_BOTTOM; - -/// Hide the menu when not unrolled -pub const NCMENU_OPTION_HIDING: u32 = crate::bindings::bindgen::NCMENU_OPTION_HIDING; diff --git a/rust/src/widgets/mod.rs b/rust/src/widgets/mod.rs index 892665531..9cfd7d0c1 100644 --- a/rust/src/widgets/mod.rs +++ b/rust/src/widgets/mod.rs @@ -1,5 +1,4 @@ //! Widgets -//! mod menu; mod multiselector; diff --git a/rust/src/widgets/multiselector/mod.rs b/rust/src/widgets/multiselector/mod.rs index f0c8479f6..012e97bba 100644 --- a/rust/src/widgets/multiselector/mod.rs +++ b/rust/src/widgets/multiselector/mod.rs @@ -1,4 +1,10 @@ -//! `NcSelector` widget +//! `NcMultiSelector` widget. -mod types; -pub use types::{NcMultiSelector, NcMultiSelectorItem, NcMultiSelectorOptions}; +/// high-level widget for selecting items from a set +pub type NcMultiSelector = crate::bindings::bindgen::ncmultiselector; + +/// an item for [`NcMultiSelector`] +pub type NcMultiSelectorItem = crate::bindings::bindgen::ncmselector_item; + +/// Options structure for [`NcMultiSelector`] +pub type NcMultiSelectorOptions = crate::bindings::bindgen::ncmultiselector_options; diff --git a/rust/src/widgets/multiselector/types.rs b/rust/src/widgets/multiselector/types.rs deleted file mode 100644 index e414f7282..000000000 --- a/rust/src/widgets/multiselector/types.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! `NcMultiSelector` widget types - -/// high-level widget for selecting items from a set -pub type NcMultiSelector = crate::bindings::bindgen::ncmultiselector; - -/// an item for [`NcMultiSelector`] -pub type NcMultiSelectorItem = crate::bindings::bindgen::ncmselector_item; - -/// Options structure for [`NcMultiSelector`] -pub type NcMultiSelectorOptions = crate::bindings::bindgen::ncmultiselector_options; diff --git a/rust/src/widgets/plot/mod.rs b/rust/src/widgets/plot/mod.rs index 491c04231..2fdc0b093 100644 --- a/rust/src/widgets/plot/mod.rs +++ b/rust/src/widgets/plot/mod.rs @@ -1,8 +1,27 @@ -//! `NcPlot[F|U]64` widget - -mod types; -pub use types::{NcPlotF64, NcPlotOptions, NcPlotU64}; -pub use types::{ - NCPLOT_OPTION_DETECTMAXONLY, NCPLOT_OPTION_EXPONENTIALD, NCPLOT_OPTION_LABELTICKSD, - NCPLOT_OPTION_NODEGRADE, NCPLOT_OPTION_VERTICALI, -}; +//! `NcPlot[F|U]64` widget. + +/// A histogram, bound to an [`NcPlane`][crate::NcPlane] +/// (uses non-negative `f64`s) +pub type NcPlotF64 = crate::bindings::bindgen::ncdplot; + +/// A histogram, bound to an [`NcPlane`][crate::NcPlane] (uses `u64`s) +pub type NcPlotU64 = crate::bindings::bindgen::ncuplot; + +/// Options struct for +/// [`NcPlotF64`] or [`NcPlotU64`] +pub type NcPlotOptions = crate::bindings::bindgen::ncplot_options; + +/// Use domain detection only for max +pub const NCPLOT_OPTION_DETECTMAXONLY: u32 = crate::bindings::bindgen::NCPLOT_OPTION_DETECTMAXONLY; + +/// Exponential dependent axis +pub const NCPLOT_OPTION_EXPONENTIALD: u32 = crate::bindings::bindgen::NCPLOT_OPTION_EXPONENTIALD; + +/// Show labels for dependent axis +pub const NCPLOT_OPTION_LABELTICKSD: u32 = crate::bindings::bindgen::NCPLOT_OPTION_LABELTICKSD; + +/// Use domain detection only for max +pub const NCPLOT_OPTION_NODEGRADE: u32 = crate::bindings::bindgen::NCPLOT_OPTION_NODEGRADE; + +/// Independent axis is vertical +pub const NCPLOT_OPTION_VERTICALI: u32 = crate::bindings::bindgen::NCPLOT_OPTION_VERTICALI; diff --git a/rust/src/widgets/plot/types.rs b/rust/src/widgets/plot/types.rs deleted file mode 100644 index 8ed0efa77..000000000 --- a/rust/src/widgets/plot/types.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! `NcPlot[F|U]64` widget types - -/// A histogram, bound to an [`NcPlane`][crate::NcPlane] -/// (uses non-negative `f64`s) -pub type NcPlotF64 = crate::bindings::bindgen::ncdplot; - -/// A histogram, bound to an [`NcPlane`][crate::NcPlane] (uses `u64`s) -pub type NcPlotU64 = crate::bindings::bindgen::ncuplot; - -/// Options struct for -/// [`NcPlotF64`] or [`NcPlotU64`] -pub type NcPlotOptions = crate::bindings::bindgen::ncplot_options; - -/// Use domain detection only for max -pub const NCPLOT_OPTION_DETECTMAXONLY: u32 = crate::bindings::bindgen::NCPLOT_OPTION_DETECTMAXONLY; - -/// Exponential dependent axis -pub const NCPLOT_OPTION_EXPONENTIALD: u32 = crate::bindings::bindgen::NCPLOT_OPTION_EXPONENTIALD; - -/// Show labels for dependent axis -pub const NCPLOT_OPTION_LABELTICKSD: u32 = crate::bindings::bindgen::NCPLOT_OPTION_LABELTICKSD; - -/// Use domain detection only for max -pub const NCPLOT_OPTION_NODEGRADE: u32 = crate::bindings::bindgen::NCPLOT_OPTION_NODEGRADE; - -/// Independent axis is vertical -pub const NCPLOT_OPTION_VERTICALI: u32 = crate::bindings::bindgen::NCPLOT_OPTION_VERTICALI; diff --git a/rust/src/widgets/reader/methods.rs b/rust/src/widgets/reader/methods.rs new file mode 100644 index 000000000..0d452aac6 --- /dev/null +++ b/rust/src/widgets/reader/methods.rs @@ -0,0 +1,29 @@ +//! `NcReader*` methods and associated functions. + +use crate::{ncreader_create, NcPlane, NcReader, NcReaderOptions}; + +impl NcReader { + /// `NcReader` simple constructor + pub unsafe fn new<'a>(plane: &mut NcPlane) -> &'a mut Self { + Self::with_options(plane, &NcReaderOptions::new()) + } + + /// `NcReader` constructor with options + pub unsafe fn with_options<'a>(plane: &mut NcPlane, options: &NcReaderOptions) -> &'a mut Self { + &mut *ncreader_create(plane, options) + } +} + +impl NcReaderOptions { + /// `NcReaderOptions` simple constructor + pub fn new() -> Self { + Self { + // channels used for input + tchannels: 0, + // attributes used for input + tattrword: 0, + // bitfield of NCREADER_OPTION_* + flags: 0, + } + } +} diff --git a/rust/src/widgets/reader/mod.rs b/rust/src/widgets/reader/mod.rs index 23bc14755..f50c9f1f9 100644 --- a/rust/src/widgets/reader/mod.rs +++ b/rust/src/widgets/reader/mod.rs @@ -1,53 +1,48 @@ -//! `NcReader` widget +//! `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 -// -// static inline functions total: 0 -// ------------------------------------------- - -mod types; -pub use types::{NcReader, NcReaderOptions}; -pub use types::{ - NCREADER_OPTION_CURSOR, NCREADER_OPTION_HORSCROLL, NCREADER_OPTION_NOCMDKEYS, - NCREADER_OPTION_VERSCROLL, -}; - -use crate::{ncreader_create, NcPlane}; - -impl NcReader { - /// `NcReader` simple constructor - pub unsafe fn new<'a>(plane: &mut NcPlane) -> &'a mut Self { - Self::with_options(plane, &NcReaderOptions::new()) - } - - /// `NcReader` constructor with options - pub unsafe fn with_options<'a>(plane: &mut NcPlane, options: &NcReaderOptions) -> &'a mut Self { - &mut *ncreader_create(plane, options) - } -} - -impl NcReaderOptions { - /// `NcReaderOptions` simple constructor - pub fn new() -> Self { - Self { - // channels used for input - tchannels: 0, - // attributes used for input - tattrword: 0, - // bitfield of NCREADER_OPTION_* - flags: 0, - } - } -} +// 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`], destroying it on any +/// error (`ncreader_destroy`() otherwise destroys the ncplane). +/// +/// `type in C: ncreader (struct)` +/// +pub type NcReader = crate::bindings::bindgen::ncreader; + +/// Options struct for [`NcReader`] +/// +/// `type in C: ncreader_options (struct)` +/// +pub type NcReaderOptions = crate::bindings::bindgen::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::bindgen::NCREADER_OPTION_CURSOR; + +/// Enable horizontal scrolling. Virtual lines can then grow arbitrarily long. +pub const NCREADER_OPTION_HORSCROLL: u32 = crate::bindings::bindgen::NCREADER_OPTION_HORSCROLL; + +/// Disable all editing shortcuts. By default, emacs-style keys are available. +pub const NCREADER_OPTION_NOCMDKEYS: u32 = crate::bindings::bindgen::NCREADER_OPTION_NOCMDKEYS; + +/// Enable vertical scrolling. You can then use arbitrarily many virtual lines. +pub const NCREADER_OPTION_VERSCROLL: u32 = crate::bindings::bindgen::NCREADER_OPTION_VERSCROLL; diff --git a/rust/src/widgets/reader/types.rs b/rust/src/widgets/reader/types.rs deleted file mode 100644 index ccf752778..000000000 --- a/rust/src/widgets/reader/types.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! ´NcReader´ widget types - -/// 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`], destroying it on any -/// error (`ncreader_destroy`() otherwise destroys the ncplane). -/// -/// `type in C: ncreader (struct)` -/// -pub type NcReader = crate::bindings::bindgen::ncreader; - -/// Options struct for [`NcReader`] -/// -/// `type in C: ncreader_options (struct)` -/// -pub type NcReaderOptions = crate::bindings::bindgen::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::bindgen::NCREADER_OPTION_CURSOR; - -/// Enable horizontal scrolling. Virtual lines can then grow arbitrarily long. -pub const NCREADER_OPTION_HORSCROLL: u32 = crate::bindings::bindgen::NCREADER_OPTION_HORSCROLL; - -/// Disable all editing shortcuts. By default, emacs-style keys are available. -pub const NCREADER_OPTION_NOCMDKEYS: u32 = crate::bindings::bindgen::NCREADER_OPTION_NOCMDKEYS; - -/// Enable vertical scrolling. You can then use arbitrarily many virtual lines. -pub const NCREADER_OPTION_VERSCROLL: u32 = crate::bindings::bindgen::NCREADER_OPTION_VERSCROLL; diff --git a/rust/src/widgets/reel/mod.rs b/rust/src/widgets/reel/mod.rs index 265acf5c8..565ac938f 100644 --- a/rust/src/widgets/reel/mod.rs +++ b/rust/src/widgets/reel/mod.rs @@ -1,6 +1,32 @@ -//! `NcReel` widget -//! +//! `NcReel` widget. -mod types; -pub use types::{NcReel, NcReelOptions, NcTablet}; -pub use types::{NCREEL_OPTION_CIRCULAR, NCREEL_OPTION_INFINITESCROLL}; +/// 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` 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::bindgen::ncreel; + +/// Options struct for [`NcReel`] +pub type NcReelOptions = crate::bindings::bindgen::ncreel_options; + +/// Visual tablet for [`NcReel`] +pub type NcTablet = crate::bindings::bindgen::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::bindgen::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::bindgen::NCREEL_OPTION_INFINITESCROLL; diff --git a/rust/src/widgets/reel/types.rs b/rust/src/widgets/reel/types.rs deleted file mode 100644 index 5629daea5..000000000 --- a/rust/src/widgets/reel/types.rs +++ /dev/null @@ -1,30 +0,0 @@ -/// 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` 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::bindgen::ncreel; - -/// Options struct for [`NcReel`] -pub type NcReelOptions = crate::bindings::bindgen::ncreel_options; - -/// Visual tablet for [`NcReel`] -pub type NcTablet = crate::bindings::bindgen::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::bindgen::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::bindgen::NCREEL_OPTION_INFINITESCROLL; diff --git a/rust/src/widgets/selector/mod.rs b/rust/src/widgets/selector/mod.rs index 85a0687ad..f61dd52ce 100644 --- a/rust/src/widgets/selector/mod.rs +++ b/rust/src/widgets/selector/mod.rs @@ -1,5 +1,10 @@ -//! `NcSelector` widget -//! +//! `NcSelector` widget. -mod types; -pub use types::{NcSelector, NcSelectorItem, NcSelectorOptions}; +/// high-level widget for selecting one item from a set +pub type NcSelector = crate::bindings::bindgen::ncselector; + +/// an item for [`NcSelector`] +pub type NcSelectorItem = crate::bindings::bindgen::ncselector_item; + +/// Options structur for [`NcSelector`] +pub type NcSelectorOptions = crate::bindings::bindgen::ncselector_options; diff --git a/rust/src/widgets/selector/types.rs b/rust/src/widgets/selector/types.rs deleted file mode 100644 index 99be81006..000000000 --- a/rust/src/widgets/selector/types.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! `NcSelector` types - -/// high-level widget for selecting one item from a set -pub type NcSelector = crate::bindings::bindgen::ncselector; - -/// an item for [`NcSelector`] -pub type NcSelectorItem = crate::bindings::bindgen::ncselector_item; - -/// Options structur for [`NcSelector`] -pub type NcSelectorOptions = crate::bindings::bindgen::ncselector_options;