use core::{ffi::c_char, ptr::null_mut};
#[cfg(not(feature = "std"))]
use alloc::{ffi::CString, string::ToString};
#[cfg(feature = "std")]
use std::ffi::CString;
use crate::{
c_api::{
self, nccell_release, NcAlign_u32, NcAlpha_u32, NcBoxMask_u32, NcChannel_u32,
NcChannels_u64, NcResult_i32, NcRgb_u32, NcStyle_u16, NCRESULT_ERR, NCRESULT_OK,
},
cstring, NcCell, NcPlane,
};
#[inline]
pub fn ncplane_fg_alpha(plane: &NcPlane) -> NcAlpha_u32 {
c_api::ncchannels_fg_alpha(ncplane_channels(plane))
}
#[inline]
pub fn ncplane_bg_alpha(plane: &NcPlane) -> NcAlpha_u32 {
c_api::ncchannels_bg_alpha(ncplane_channels(plane))
}
#[inline]
pub fn ncplane_fchannel(plane: &NcPlane) -> NcChannel_u32 {
c_api::ncchannels_fchannel(ncplane_channels(plane))
}
#[inline]
pub fn ncplane_bchannel(plane: &NcPlane) -> NcChannel_u32 {
c_api::ncchannels_bchannel(ncplane_channels(plane))
}
#[inline]
pub fn ncplane_set_fchannel(
plane: &mut NcPlane,
channel: impl Into<NcChannel_u32>,
) -> NcChannels_u64 {
unsafe { c_api::ffi::ncplane_set_fchannel(plane, channel.into()) }
}
#[inline]
pub fn ncplane_set_bchannel(
plane: &mut NcPlane,
channel: impl Into<NcChannel_u32>,
) -> NcChannels_u64 {
unsafe { c_api::ffi::ncplane_set_bchannel(plane, channel.into()) }
}
#[inline]
pub fn ncplane_channels(plane: &NcPlane) -> NcChannels_u64 {
unsafe { c_api::ffi::ncplane_channels(plane) }
}
#[inline]
pub fn ncplane_set_channels(plane: &mut NcPlane, channels: impl Into<NcChannels_u64>) {
unsafe {
c_api::ffi::ncplane_set_channels(plane, channels.into());
}
}
#[inline]
pub fn ncplane_fg_rgb8(
plane: &NcPlane,
red: &mut u8,
green: &mut u8,
blue: &mut u8,
) -> NcChannel_u32 {
c_api::ncchannels_fg_rgb8(ncplane_channels(plane), red, green, blue)
}
#[inline]
pub fn ncplane_bg_rgb8(
plane: &NcPlane,
red: &mut u8,
green: &mut u8,
blue: &mut u8,
) -> NcChannel_u32 {
c_api::ncchannels_bg_rgb8(ncplane_channels(plane), red, green, blue)
}
#[inline]
pub fn ncplane_fg_rgb(plane: &NcPlane) -> NcRgb_u32 {
c_api::ncchannels_fg_rgb(ncplane_channels(plane))
}
#[inline]
pub fn ncplane_bg_rgb(plane: &NcPlane) -> NcRgb_u32 {
c_api::ncchannels_bg_rgb(ncplane_channels(plane))
}
#[inline]
pub fn ncplane_fg_default_p(plane: &NcPlane) -> bool {
c_api::ncchannels_fg_default_p(ncplane_channels(plane))
}
#[inline]
pub fn ncplane_bg_default_p(plane: &NcPlane) -> bool {
c_api::ncchannels_bg_default_p(ncplane_channels(plane))
}
#[inline]
pub fn ncplane_set_default(plane: &mut NcPlane) -> NcChannels_u64 {
let channels = c_api::ncchannels_set_default(&mut ncplane_channels(plane));
ncplane_set_channels(plane, channels);
channels
}
#[inline]
pub fn ncplane_set_not_default(plane: &mut NcPlane) -> NcChannels_u64 {
let channels = c_api::ncchannels_set_not_default(&mut ncplane_channels(plane));
c_api::ncplane_set_channels(plane, channels);
channels
}
#[inline]
pub fn ncplane_set_fg_not_default(plane: &NcPlane) -> NcChannels_u64 {
c_api::ncchannels_set_fg_not_default(&mut ncplane_channels(plane))
}
#[inline]
pub fn ncplane_set_bg_not_default(plane: &NcPlane) -> NcChannels_u64 {
c_api::ncchannels_set_bg_not_default(&mut ncplane_channels(plane))
}
#[inline]
pub fn ncplane_putc(plane: &mut NcPlane, cell: &NcCell) -> NcResult_i32 {
unsafe { c_api::ncplane_putc_yx(plane, -1, -1, cell) }
}
#[inline]
pub fn ncplane_putchar(plane: &mut NcPlane, ch: char) -> NcResult_i32 {
unsafe {
let cell = NcCell::from_char(plane, ch);
if cell.is_err() {
return NCRESULT_ERR;
}
c_api::ncplane_putc_yx(plane, -1, -1, &cell.unwrap())
}
}
#[inline]
pub fn ncplane_putchar_yx(plane: &mut NcPlane, y: u32, x: u32, ch: char) -> NcResult_i32 {
unsafe {
let cell = NcCell::from_char(plane, ch);
if cell.is_err() {
return NCRESULT_ERR;
}
c_api::ncplane_putc_yx(plane, y as i32, x as i32, &cell.unwrap())
}
}
#[inline]
pub fn ncplane_putchar_stained(plane: &mut NcPlane, ch: char) -> NcResult_i32 {
ncplane_putstr_stained(plane, &ch.to_string())
}
#[inline]
pub fn ncplane_putegc(plane: &mut NcPlane, egc: &str, sbytes: Option<&mut usize>) -> NcResult_i32 {
let sbytes_ptr = if let Some(sb) = sbytes { sb as *mut _ } else { null_mut() };
let cs = cstring![egc];
let egc_ptr = cs.as_ptr() as *const c_char;
unsafe { c_api::ffi::ncplane_putegc_yx(plane, -1, -1, egc_ptr, sbytes_ptr) }
}
#[inline]
pub fn ncplane_putegc_yx(
plane: &mut NcPlane,
y: Option<u32>,
x: Option<u32>,
egc: &str,
sbytes: Option<&mut usize>,
) -> NcResult_i32 {
let sbytes_ptr = if let Some(sb) = sbytes { sb as *mut _ } else { null_mut() };
let cs = cstring![egc];
unsafe {
c_api::ffi::ncplane_putegc_yx(
plane,
y.unwrap_or(u32::MAX) as i32,
x.unwrap_or(u32::MAX) as i32,
cs.as_ptr(),
sbytes_ptr,
)
}
}
#[inline]
pub fn ncplane_putegc_stained(
plane: &mut NcPlane,
egc: &str,
sbytes: Option<&mut usize>,
) -> NcResult_i32 {
let sbytes_ptr = if let Some(sb) = sbytes { sb as *mut _ } else { null_mut() };
let cs = cstring![egc];
unsafe { c_api::ffi::ncplane_putegc_stained(plane, cs.as_ptr(), sbytes_ptr) }
}
#[inline]
pub fn ncplane_putstr(plane: &mut NcPlane, string: &str) -> NcResult_i32 {
ncplane_putstr_yx(plane, None, None, string)
}
#[inline]
pub fn ncplane_putstr_yx(
plane: &mut NcPlane,
y: Option<u32>,
x: Option<u32>,
string: &str,
) -> NcResult_i32 {
let cs = cstring![string];
let mut cs_ptr = cs.as_ptr();
let (mut y, mut x) = (y, x);
let mut ret = 0;
while unsafe { cs_ptr.read() != 0 } {
let mut wcs = 0;
let cols = unsafe {
c_api::ffi::ncplane_putegc_yx(
plane,
y.unwrap_or(u32::MAX) as i32,
x.unwrap_or(u32::MAX) as i32,
cs_ptr,
&mut wcs,
)
};
if cols < 0 {
return -ret;
}
if wcs == 0 {
break;
}
y = None;
x = None;
cs_ptr = unsafe { cs_ptr.add(wcs) };
ret += cols;
}
ret
}
#[inline]
pub fn ncplane_putstr_aligned(
plane: &mut NcPlane,
y: Option<u32>,
align: impl Into<NcAlign_u32>,
string: &str,
) -> NcResult_i32 {
let (mut validbytes, mut validwidth) = (0, 0);
let cs = cstring![string];
unsafe {
c_api::ncstrwidth(cs.as_ptr(), &mut validbytes, &mut validwidth);
}
let xpos = ncplane_halign(plane, align.into(), validwidth as u32);
if xpos < 0 {
NCRESULT_ERR
} else {
ncplane_putstr_yx(plane, y, Some(xpos as u32), string)
}
}
#[inline]
pub fn ncplane_putstr_stained(plane: &mut NcPlane, string: &str) -> NcResult_i32 {
let cstring = CString::new(string).unwrap();
let mut cstring_ptr = cstring.as_ptr();
let mut ret = 0;
while unsafe { cstring_ptr.read() != 0 } {
let mut wcs = 0;
let cols = unsafe { c_api::ffi::ncplane_putegc_stained(plane, cstring_ptr, &mut wcs) };
if cols < 0 {
return -ret;
}
if wcs == 0 {
break;
}
cstring_ptr = unsafe { cstring_ptr.add(wcs) };
ret += cols;
}
ret
}
#[inline]
pub fn ncplane_putnstr_yx(
plane: &mut NcPlane,
y: Option<u32>,
x: Option<u32>,
num_bytes: usize,
string: &str,
) -> NcResult_i32 {
let cstring = CString::new(string).unwrap();
let cstring_bytes_len = cstring.as_bytes().len();
let cstring_ptr = cstring.as_ptr();
let (ret, mut offset) = (0, 0);
let (mut y, mut x) = (y, x);
while offset < num_bytes && offset < cstring_bytes_len {
let mut wcs = 0;
let cols = unsafe {
c_api::ffi::ncplane_putegc_yx(
plane,
y.unwrap_or(u32::MAX) as i32,
x.unwrap_or(u32::MAX) as i32,
cstring_ptr.add(offset),
&mut wcs,
)
};
if cols < 0 {
return c_api::NCRESULT_ERR;
}
if wcs == 0 {
break;
}
y = None;
x = None;
offset += wcs;
}
ret
}
#[inline]
pub fn ncplane_putnstr(plane: &mut NcPlane, num_bytes: usize, string: &str) -> NcResult_i32 {
c_api::ncplane_putnstr_yx(plane, None, None, num_bytes, string)
}
#[inline]
pub fn ncplane_moverel(plane: &mut NcPlane, rows: i32, cols: i32) -> NcResult_i32 {
let (mut orig_y, mut orig_x) = (0, 0);
unsafe {
c_api::ncplane_yx(plane, &mut orig_y, &mut orig_x);
c_api::ncplane_move_yx(plane, orig_y + rows, orig_x + cols)
}
}
#[inline]
pub fn ncplane_move_bottom(plane: &mut NcPlane) {
unsafe {
c_api::ncplane_move_above(plane, null_mut());
}
}
#[inline]
pub fn ncplane_move_top(plane: &mut NcPlane) {
unsafe {
c_api::ncplane_move_below(plane, null_mut());
}
}
#[inline]
pub fn ncplane_move_family_top(plane: &mut NcPlane) {
unsafe {
c_api::ncplane_move_family_below(plane, null_mut());
}
}
#[inline]
pub fn ncplane_move_family_bottom(plane: &mut NcPlane) {
unsafe {
c_api::ncplane_move_family_above(plane, null_mut());
}
}
#[inline]
pub fn ncplane_dim_x(plane: &NcPlane) -> u32 {
unsafe {
let mut x = 0;
c_api::ncplane_dim_yx(plane, null_mut(), &mut x);
x
}
}
#[inline]
pub fn ncplane_dim_y(plane: &NcPlane) -> u32 {
unsafe {
let mut y = 0;
c_api::ncplane_dim_yx(plane, &mut y, null_mut());
y
}
}
#[inline]
pub fn ncplane_resize_simple(plane: &mut NcPlane, len_y: u32, len_x: u32) -> NcResult_i32 {
let (mut old_y, mut old_x) = (0, 0);
unsafe {
c_api::ncplane_dim_yx(plane, &mut old_y, &mut old_x);
}
let keep_len_y = {
if old_y > len_y {
len_y
} else {
old_y
}
};
let keep_len_x = {
if old_x > len_x {
len_x
} else {
old_x
}
};
unsafe { c_api::ncplane_resize(plane, 0, 0, keep_len_y, keep_len_x, 0, 0, len_y, len_x) }
}
#[inline]
pub fn ncplane_halign(
plane: &NcPlane,
align: impl Into<NcAlign_u32>,
numcols: u32,
) -> NcResult_i32 {
c_api::notcurses_align(ncplane_dim_x(plane), align, numcols)
}
#[inline]
pub fn ncplane_valign(
plane: &NcPlane,
align: impl Into<NcAlign_u32>,
numrows: u32,
) -> NcResult_i32 {
c_api::notcurses_align(ncplane_dim_y(plane), align, numrows)
}
#[inline]
pub fn ncplane_hline(plane: &mut NcPlane, cell: &NcCell, len: u32) -> NcResult_i32 {
unsafe { c_api::ncplane_hline_interp(plane, cell, len, cell.channels, cell.channels) }
}
#[inline]
pub fn ncplane_vline(plane: &mut NcPlane, cell: &NcCell, len: u32) -> NcResult_i32 {
unsafe { c_api::ncplane_vline_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,
boxmask: impl Into<NcBoxMask_u32>,
) -> NcResult_i32 {
unsafe {
c_api::ncplane_cursor_move_yx(plane, 0, 0);
let (mut dimy, mut dimx) = (0, 0);
c_api::ncplane_dim_yx(plane, &mut dimy, &mut dimx);
ncplane_box_sized(
plane,
ul,
ur,
ll,
lr,
hline,
vline,
dimy,
dimx,
boxmask.into(),
)
}
}
#[inline]
pub fn ncplane_perimeter_double(
plane: &mut NcPlane,
stylemask: impl Into<NcStyle_u16>,
channels: impl Into<NcChannels_u64>,
boxmask: impl Into<NcBoxMask_u32>,
) -> NcResult_i32 {
if unsafe { c_api::ncplane_cursor_move_yx(plane, 0, 0) } != NCRESULT_OK {
return NCRESULT_ERR;
}
let (mut dimy, mut dimx) = (0, 0);
unsafe {
c_api::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 c_api::nccells_double_box(
plane, stylemask, 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, boxmask);
unsafe {
nccell_release(plane, &mut ul);
nccell_release(plane, &mut ur);
nccell_release(plane, &mut ll);
nccell_release(plane, &mut lr);
nccell_release(plane, &mut hl);
nccell_release(plane, &mut vl);
}
ret
}
#[inline]
pub fn ncplane_perimeter_rounded(
plane: &mut NcPlane,
stylemask: impl Into<NcStyle_u16>,
channels: impl Into<NcChannels_u64>,
boxmask: impl Into<NcBoxMask_u32>,
) -> NcResult_i32 {
if unsafe { c_api::ncplane_cursor_move_yx(plane, 0, 0) } != NCRESULT_OK {
return NCRESULT_ERR;
}
let (mut dimy, mut dimx) = (0, 0);
unsafe {
c_api::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 c_api::nccells_rounded_box(
plane, stylemask, 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, boxmask);
unsafe {
nccell_release(plane, &mut ul);
nccell_release(plane, &mut ur);
nccell_release(plane, &mut ll);
nccell_release(plane, &mut lr);
nccell_release(plane, &mut hl);
nccell_release(plane, &mut vl);
}
ret
}
#[inline]
pub fn ncplane_ascii_box(
plane: &mut NcPlane,
stylemask: impl Into<NcStyle_u16>,
channels: impl Into<NcChannels_u64>,
end_y: u32,
end_x: u32,
boxmask: impl Into<NcBoxMask_u32>,
) -> NcResult_i32 {
#[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 = c_api::nccells_ascii_box(
plane, stylemask, channels, &mut ul, &mut ur, &mut ll, &mut lr, &mut hl, &mut vl,
);
if ret == NCRESULT_OK {
ret = c_api::ncplane_box(
plane,
&ul,
&ur,
&ll,
&lr,
&hl,
&vl,
end_y,
end_x,
boxmask.into(),
);
}
nccell_release(plane, &mut ul);
nccell_release(plane, &mut ur);
nccell_release(plane, &mut ll);
nccell_release(plane, &mut lr);
nccell_release(plane, &mut hl);
nccell_release(plane, &mut vl);
}
ret
}
#[inline]
pub fn ncplane_box_sized(
plane: &mut NcPlane,
ul: &NcCell,
ur: &NcCell,
ll: &NcCell,
lr: &NcCell,
hline: &NcCell,
vline: &NcCell,
len_y: u32,
len_x: u32,
boxmask: impl Into<NcBoxMask_u32>,
) -> NcResult_i32 {
let (mut y, mut x) = (0, 0);
unsafe {
c_api::ncplane_cursor_yx(plane, &mut y, &mut x);
c_api::ncplane_box(
plane,
ul,
ur,
ll,
lr,
hline,
vline,
y + len_y - 1,
x + len_x - 1,
boxmask.into(),
)
}
}
#[inline]
pub fn ncplane_double_box(
plane: &mut NcPlane,
stylemask: impl Into<NcStyle_u16>,
channels: impl Into<NcChannels_u64>,
end_y: u32,
end_x: u32,
boxmask: impl Into<NcBoxMask_u32>,
) -> NcResult_i32 {
#[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 = c_api::nccells_double_box(
plane, stylemask, channels, &mut ul, &mut ur, &mut ll, &mut lr, &mut hl, &mut vl,
);
if ret == NCRESULT_OK {
ret = c_api::ncplane_box(
plane,
&ul,
&ur,
&ll,
&lr,
&hl,
&vl,
end_y,
end_x,
boxmask.into(),
);
}
nccell_release(plane, &mut ul);
nccell_release(plane, &mut ur);
nccell_release(plane, &mut ll);
nccell_release(plane, &mut lr);
nccell_release(plane, &mut hl);
nccell_release(plane, &mut vl);
}
ret
}
#[inline]
pub fn ncplane_double_box_sized(
plane: &mut NcPlane,
stylemask: impl Into<NcStyle_u16>,
channels: impl Into<NcChannels_u64>,
len_y: u32,
len_x: u32,
boxmask: impl Into<NcBoxMask_u32>,
) -> NcResult_i32 {
let (mut y, mut x) = (0, 0);
unsafe {
c_api::ncplane_cursor_yx(plane, &mut y, &mut x);
}
c_api::ncplane_double_box(
plane,
stylemask,
channels,
y + len_y - 1,
x + len_x - 1,
boxmask,
)
}
#[inline]
pub fn ncplane_rounded_box(
plane: &mut NcPlane,
stylemask: impl Into<NcStyle_u16>,
channels: impl Into<NcChannels_u64>,
end_y: u32,
end_x: u32,
boxmask: impl Into<NcBoxMask_u32>,
) -> NcResult_i32 {
#[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 = c_api::nccells_rounded_box(
plane, stylemask, channels, &mut ul, &mut ur, &mut ll, &mut lr, &mut hl, &mut vl,
);
if ret == NCRESULT_OK {
ret = c_api::ncplane_box(
plane,
&ul,
&ur,
&ll,
&lr,
&hl,
&vl,
end_y,
end_x,
boxmask.into(),
);
}
nccell_release(plane, &mut ul);
nccell_release(plane, &mut ur);
nccell_release(plane, &mut ll);
nccell_release(plane, &mut lr);
nccell_release(plane, &mut hl);
nccell_release(plane, &mut vl);
}
ret
}
#[inline]
pub fn ncplane_rounded_box_sized(
plane: &mut NcPlane,
stylemask: impl Into<NcStyle_u16>,
channels: impl Into<NcChannels_u64>,
len_y: u32,
len_x: u32,
boxmask: impl Into<NcBoxMask_u32>,
) -> NcResult_i32 {
let (mut y, mut x) = (0, 0);
unsafe {
c_api::ncplane_cursor_yx(plane, &mut y, &mut x);
}
ncplane_rounded_box(
plane,
stylemask,
channels,
y + len_y - 1,
x + len_x - 1,
boxmask,
)
}
#[inline]
pub fn ncplane_gradient(
plane: &mut NcPlane,
y: Option<u32>,
x: Option<u32>,
len_y: Option<u32>,
len_x: Option<u32>,
egc: &str,
stylemask: impl Into<NcStyle_u16>,
ul: impl Into<NcChannels_u64>,
ur: impl Into<NcChannels_u64>,
ll: impl Into<NcChannels_u64>,
lr: impl Into<NcChannels_u64>,
) -> NcResult_i32 {
let cs = cstring![egc];
let egc_ptr = cs.as_ptr() as *const c_char;
unsafe {
c_api::ffi::ncplane_gradient(
plane,
y.unwrap_or(u32::MAX) as i32,
x.unwrap_or(u32::MAX) as i32,
len_y.unwrap_or(0),
len_x.unwrap_or(0),
egc_ptr,
stylemask.into(),
ul.into(),
ur.into(),
ll.into(),
lr.into(),
)
}
}
#[inline]
pub fn ncplane_cursor_y(plane: &NcPlane) -> u32 {
let mut y = 0;
unsafe {
c_api::ncplane_cursor_yx(plane, &mut y, null_mut());
}
y
}
#[inline]
pub fn ncplane_cursor_x(plane: &NcPlane) -> u32 {
let mut x = 0;
unsafe {
c_api::ncplane_cursor_yx(plane, null_mut(), &mut x);
}
x
}