libnotcurses_sys/notcurses/
reimplemented.rs

1//! `notcurses_*` reimplemented functions.
2
3use core::ptr::{null, null_mut};
4
5use crate::{
6    c_api::{self, NcAlign_u32, NcResult_i32, NCRESULT_ERR},
7    Nc, NcError, NcInput, NcPlane, NcResult, NcTime,
8};
9
10/// Returns the offset into `avail_u` at which `u` ought be output given
11/// the requirements of `align`.
12///
13/// Returns `-`[`NcResult_i32::MAX`][NcResult_i32#associatedconstant.MAX] if
14/// [NCALIGN_UNALIGNED][c_api::NCALIGN_UNALIGNED] or invalid `align`.
15///
16/// *Method: Nc.[align()][Nc#method.align].*
17#[inline]
18pub fn notcurses_align(avail_u: u32, align: impl Into<NcAlign_u32>, u: u32) -> NcResult_i32 {
19    let align = align.into();
20    if align == c_api::NCALIGN_LEFT || align == c_api::NCALIGN_TOP {
21        return 0;
22    }
23    if align == c_api::NCALIGN_CENTER {
24        return ((avail_u - u) / 2) as NcResult_i32;
25    }
26    if align == c_api::NCALIGN_RIGHT || align == c_api::NCALIGN_BOTTOM {
27        return (avail_u - u) as NcResult_i32;
28    }
29    -NcResult_i32::MAX
30}
31
32/// Returns true if we can blit pixel-accurate bitmaps.
33///
34/// *Method: Nc.[canpixel()][Nc#method.canpixel].*
35#[inline]
36pub fn notcurses_canpixel(nc: &Nc) -> bool {
37    unsafe { c_api::notcurses_check_pixel_support(nc) != c_api::NCPIXEL_NONE }
38}
39
40/// Returns true if we can reliably use Unicode Braille.
41///
42/// *Method: Nc.[canbraille()][Nc#method.canbraille].*
43#[inline]
44pub fn notcurses_canbraille(nc: &Nc) -> bool {
45    notcurses_canutf8(nc) && nc.capabilities().braille
46}
47
48/// Returns true if it's possible to set the "hardware" palette.
49///
50/// Requires the "ccc" terminfo capability.
51///
52/// *Method: Nc.[canchangecolor()][Nc#method.canchangecolor].*
53#[inline]
54pub fn notcurses_canchangecolor(nc: &Nc) -> bool {
55    c_api::nccapability_canchangecolor(&nc.capabilities())
56}
57
58/// Returns true if fading is possible.
59///
60/// Fading requires either the "rgb" or "ccc" terminfo capability.
61///
62/// *Method: Nc.[canfade()][Nc#method.canfade].*
63#[inline]
64pub fn notcurses_canfade(nc: &Nc) -> bool {
65    notcurses_canchangecolor(nc) || notcurses_cantruecolor(nc)
66}
67
68/// Returns true if it's possible to directly specify RGB values per cell,
69/// or false if it's only possible to use palettes.
70///
71/// *Method: Nc.[cantruecolor()][Nc#method.cantruecolor].*
72pub fn notcurses_cantruecolor(nc: &Nc) -> bool {
73    nc.capabilities().rgb
74}
75
76/// Returns true if the encoding is UTF-8.
77///
78/// Requires `LANG` being set to a UTF-8 locale.
79///
80/// *Method: Nc.[canutf8()][Nc#method.canutf8].*
81#[inline]
82pub fn notcurses_canutf8(nc: &Nc) -> bool {
83    nc.capabilities().utf8
84}
85
86/// Returns true if we can reliably use Unicode half blocks.
87///
88/// *Method: Nc.[canhalfblock()][Nc#method.canhalfblock].*
89#[inline]
90pub fn notcurses_canhalfblock(nc: &Nc) -> bool {
91    notcurses_canutf8(nc)
92}
93
94/// Returns true if we can reliably use Unicode quadrant blocks.
95///
96/// *Method: Nc.[canquadrant()][Nc#method.canquadrant].*
97#[inline]
98pub fn notcurses_canquadrant(nc: &Nc) -> bool {
99    notcurses_canutf8(nc) && nc.capabilities().quadrants
100}
101
102/// Returns true if we can reliably use Unicode 13 sextants.
103///
104/// *Method: Nc.[cansextant()][Nc#method.cansextant].*
105#[inline]
106pub fn notcurses_cansextant(nc: &Nc) -> bool {
107    notcurses_canutf8(nc) && nc.capabilities().sextants
108}
109
110/// Reads input blocking until an event is processed or a signal is received
111/// (including resize events)
112///
113/// Will optionally write the event details in `input`.
114///
115/// In case of an invalid read (including on EOF) *-1* is returned.
116///
117/// *Method: Nc.[get_blocking()][Nc#method.get_blocking].*
118#[inline]
119pub fn notcurses_get_blocking(nc: &mut Nc, input: Option<&mut NcInput>) -> NcResult_i32 {
120    let input_ptr = if let Some(i) = input { i as *mut _ } else { null_mut() };
121    unsafe { c_api::notcurses_get(nc, null(), input_ptr) as NcResult_i32 }
122}
123
124/// Reads input without blocking.
125///
126/// Will optionally write the event details in `input`.
127///
128/// If no event is immediately ready, returns 0.
129///
130/// In case of an invalid read (including on EOF) *-1* is returned.
131///
132/// *Method: Nc.[get_nblock()][Nc#method.get_nblock].*
133#[inline]
134pub fn notcurses_get_nblock(nc: &mut Nc, input: Option<&mut NcInput>) -> NcResult_i32 {
135    let input_ptr = if let Some(i) = input { i as *mut _ } else { null_mut() };
136    unsafe {
137        let ts = NcTime::new(0, 0);
138        c_api::notcurses_get(nc, &ts, input_ptr) as NcResult_i32
139    }
140}
141
142/// Renders and rasterizes the standard pile in one shot. Blocking call.
143///
144/// *Method: Nc.[render()][Nc#method.render].*
145#[inline]
146pub fn notcurses_render(nc: &mut Nc) -> NcResult_i32 {
147    let stdplane = unsafe { c_api::notcurses_stdplane(nc) };
148    if unsafe { c_api::ncpile_render(stdplane) } == NCRESULT_ERR {
149        return NCRESULT_ERR;
150    }
151    unsafe { c_api::ncpile_rasterize(stdplane) }
152}
153
154/// [*notcurses_stdplane*][c_api::notcurses_stdplane], plus free bonus
155/// dimensions written to non-NULL y/x!
156///
157/// *Method: Nc.[stddim_yx()][Nc#method.stddim_yx].*
158#[inline]
159pub fn notcurses_stddim_yx<'a>(
160    nc: &'a mut Nc,
161    y: &mut u32,
162    x: &mut u32,
163) -> NcResult<&'a mut NcPlane> {
164    unsafe {
165        let sp = c_api::notcurses_stdplane(nc);
166        if !sp.is_null() {
167            c_api::ncplane_dim_yx(sp, y, x);
168            return Ok(&mut *sp);
169        }
170    }
171    Err(NcError::new())
172}
173
174/// [*notcurses_stdplane_const*][c_api::notcurses_stdplane_const], plus free
175/// bonus dimensions written to non-NULL y/x!
176///
177/// *Method: Nc.[stddim_yx_const()][Nc#method.stddim_yx_const].*
178#[inline]
179pub fn notcurses_stddim_yx_const<'a>(
180    nc: &'a Nc,
181    y: &mut u32,
182    x: &mut u32,
183) -> NcResult<&'a NcPlane> {
184    unsafe {
185        let sp = c_api::notcurses_stdplane_const(nc);
186        if !sp.is_null() {
187            c_api::ncplane_dim_yx(sp, y, x);
188            return Ok(&*sp);
189        }
190    }
191    Err(NcError::new())
192}
193
194/// Returns our current idea of the terminal dimensions in rows and cols.
195///
196/// *Method: Nc.[term_dim_yx()][Nc#method.term_dim_yx].*
197#[inline]
198pub fn notcurses_term_dim_yx(nc: &Nc) -> (u32, u32) {
199    let (mut y, mut x) = (0, 0);
200    unsafe {
201        c_api::ncplane_dim_yx(c_api::notcurses_stdplane_const(nc), &mut y, &mut x);
202    }
203    (y, x)
204}
205
206/// Disables all mice tracking.
207#[inline]
208pub fn notcurses_mice_disable(nc: &mut Nc) -> NcResult_i32 {
209    unsafe { c_api::notcurses_mice_enable(nc, c_api::NCMICE_NO_EVENTS) }
210}
211
212/// Returns the bottommost [`NcPlane`] on the standard pile,
213/// of which there is always at least one.
214///
215/// *Method: Nc.[bottom()][Nc#method.bottom].*
216#[inline]
217pub fn notcurses_bottom(nc: &mut Nc) -> &mut NcPlane {
218    unsafe { &mut *c_api::ncpile_bottom(c_api::notcurses_stdplane(nc)) }
219}
220
221/// Returns the topmost [`NcPlane`] on the standard pile,
222/// of which there is always at least one.
223///
224/// *Method: Nc.[top()][Nc#method.top].*
225#[inline]
226pub fn notcurses_top(nc: &mut Nc) -> &mut NcPlane {
227    unsafe { &mut *c_api::ncpile_top(c_api::notcurses_stdplane(nc)) }
228}