libnotcurses_sys/cell/
methods.rs

1//! `NcCell` methods and associated functions.
2
3use crate::{
4    c_api::{self, nccell_load, NcChannels_u64, NCRESULT_ERR},
5    cstring, error, rstring, NcAlpha, NcCell, NcChannel, NcChannels, NcError, NcPaletteIndex,
6    NcPlane, NcResult, NcRgb, NcStyle,
7};
8
9#[cfg(not(feature = "std"))]
10use alloc::{format, string::ToString};
11
12#[cfg(all(not(feature = "std"), feature = "libc"))]
13use alloc::string::String;
14
15/// # NcCell constructors
16impl NcCell {
17    /// New `NcCell`, expects a 7-bit [`char`].
18    #[inline]
19    #[allow(clippy::unnecessary_cast)]
20    pub fn from_char7b(ch: char) -> NcResult<Self> {
21        if !ch.is_ascii() {
22            return Err(NcError::new());
23        }
24        Ok(NcCell {
25            gcluster: (ch as u32).to_le(),
26            gcluster_backstop: 0,
27            width: 0_u8,
28            stylemask: NcStyle::None.into(),
29            channels: 0 as NcChannels_u64,
30        })
31    }
32
33    /// New `NcCell`, from a [`char`].
34    ///
35    /// Expects a plane where to save the extra data if it's greater than 4 bytes.
36    #[inline]
37    pub fn from_char(plane: &mut NcPlane, ch: char) -> NcResult<Self> {
38        let mut cell = Self::new();
39        let cs = cstring![ch.to_string()];
40        let res = unsafe { nccell_load(plane, &mut cell, cs.as_ptr()) };
41        if res == NCRESULT_ERR {
42            return Err(NcError::new());
43        }
44        Ok(cell)
45    }
46
47    /// New `NcCell`, from a [`&str`].
48    ///
49    /// Expects a plane where to save the extra data if it's greater than 4 bytes.
50    #[inline]
51    pub fn from_str(plane: &mut NcPlane, string: &str) -> NcResult<Self> {
52        let mut cell = Self::new();
53        let cs = cstring![string];
54        let res = unsafe { nccell_load(plane, &mut cell, cs.as_ptr()) };
55        if res == NCRESULT_ERR {
56            return Err(NcError::new());
57        }
58        Ok(cell)
59    }
60
61    /// New empty `NcCell`.
62    #[inline]
63    pub fn new() -> Self {
64        Self::from_char7b(0 as char).unwrap()
65    }
66
67    /// Breaks the UTF-8 string in `egc` down, setting up this `NcCell`,
68    /// and returns the number of bytes copied out of `egc`.
69    ///
70    /// The styling of the cell is left untouched, but any resources are released.
71    /// *C style function: [nccell_load()][c_api::nccell_load].*
72    pub fn load(plane: &mut NcPlane, cell: &mut NcCell, egc: &str) -> NcResult<u32> {
73        let cs = cstring![egc];
74        let bytes = unsafe { c_api::nccell_load(plane, cell, cs.as_ptr()) };
75        error![
76            bytes,
77            &format!["NcCell.load(NcPlane, NcCell, {:?})", egc],
78            bytes as u32
79        ]
80    }
81
82    /// Same as [load][NcCell#method.load], plus blasts the styling with
83    /// `style` and `channels`.
84    ///
85    /// - Breaks the UTF-8 string in `gcluster` down, setting up this NcCell.
86    /// - Returns the number of bytes copied out of `gcluster`.
87    /// - Any resources are released.
88    /// - Blasts the styling with `style` and `channels`.
89    ///
90    /// *C style function: [nccell_prime()][c_api::nccell_prime].*
91    pub fn prime(
92        plane: &mut NcPlane,
93        cell: &mut NcCell,
94        gcluster: &str,
95        style: impl Into<NcStyle>,
96        channels: impl Into<NcChannels>,
97    ) -> NcResult<u32> {
98        let bytes = c_api::nccell_prime(plane, cell, gcluster, style.into().0, channels.into().0);
99        error![bytes, "", bytes as u32]
100    }
101
102    /// Duplicate this `NcCell` into another one.
103    ///
104    /// Both must be or will be bound to `common_plane`.
105    ///
106    /// *C style function: [nccell_duplicate()][c_api::nccell_duplicate].*
107    pub fn duplicate(&self, common_plane: &mut NcPlane) -> NcResult<NcCell> {
108        let mut target = NcCell::new();
109        let res = unsafe { c_api::nccell_duplicate(common_plane, &mut target, self) };
110        error![res, "NcCell.duplicate()", target]
111    }
112
113    /// Initializes (zeroes out) this `NcCell`.
114    ///
115    /// *C style function: [nccell_init()][c_api::nccell_init].*
116    #[inline]
117    pub fn init(&mut self) {
118        c_api::nccell_init(self);
119    }
120
121    /// Releases resources held by the current cell in the [NcPlane] `plane`.
122    ///
123    /// *C style function: [nccell_release()][c_api::nccell_release].*
124    pub fn release(&mut self, plane: &mut NcPlane) {
125        unsafe {
126            c_api::nccell_release(plane, self);
127        }
128    }
129}
130
131// -----------------------------------------------------------------------------
132/// ## NcCell methods: bg|fg `NcChannel`s manipulation.
133impl NcCell {
134    /// Gets the background alpha and coloring bits from the cell [`NcChannels`]
135    /// as an [`NcChannel`].
136    ///
137    /// *C style function: [nccell_bchannel()][c_api::nccell_bchannel].*
138    pub fn bchannel(&self) -> NcChannel {
139        c_api::nccell_bchannel(self).into()
140    }
141
142    /// Gets the foreground alpha and coloring bits from the cell [`NcChannels`]
143    /// as an [`NcChannel`].
144    ///
145    /// *C style function: [nccell_fchannel()][c_api::nccell_fchannel].*
146    pub fn fchannel(&self) -> NcChannel {
147        c_api::nccell_fchannel(self).into()
148    }
149
150    /// Gets the alpha and coloring bits from the cell [`NcChannels`].
151    ///
152    /// *C style function: [nccell_channels()][c_api::nccell_channels].*
153    pub fn channels(&self) -> NcChannels {
154        c_api::nccell_channels(self).into()
155    }
156
157    /// Sets the background alpha and coloring bits of the cell [`NcChannels`],
158    /// returning the new [`NcChannels_u64`].
159    ///
160    /// *C style function: [nccell_bchannel()][c_api::nccell_bchannel].*
161    pub fn set_bchannel(&mut self, from: impl Into<NcChannel>) -> NcChannels {
162        c_api::nccell_set_bchannel(self, from.into().0).into()
163    }
164
165    /// Sets the foreground alpha and coloring bits from the cell [`NcChannels`],
166    /// returning the new [`NcChannels_u64`].
167    ///
168    /// *C style function: [nccell_set_fchannel()][c_api::nccell_set_fchannel].*
169    pub fn set_fchannel(&mut self, from: impl Into<NcChannel>) -> NcChannels {
170        c_api::nccell_set_fchannel(self, from.into().0).into()
171    }
172
173    /// Sets the alpha and coloring bits of the cell [`NcChannels`]
174    /// from another [`NcChannels`], returning the new [`NcChannels`].
175    ///
176    /// *C style function: [nccell_set_channels()][c_api::nccell_set_channels].*
177    pub fn set_channels(&mut self, from: impl Into<NcChannels>) -> NcChannels {
178        c_api::nccell_set_channels(self, from.into().0).into()
179    }
180
181    /// Gets the background [`NcAlpha`] (shifted to LSBs).
182    ///
183    /// *C style function: [nccell_bg_alpha()][c_api::nccell_bg_alpha].*
184    pub fn bg_alpha(&self) -> NcAlpha {
185        c_api::nccell_bg_alpha(self).into()
186    }
187
188    /// Is the background [`NcChannel`] using the "default background color"?
189    ///
190    /// *C style function: [nccell_bg_default_p()][c_api::nccell_bg_default_p].*
191    pub fn bg_default_p(&self) -> bool {
192        c_api::nccell_bg_default_p(self)
193    }
194
195    /// Gets the [`NcPaletteIndex`] of the background [`NcChannel`].
196    ///
197    /// *C style function: [nccell_bg_palindex()][c_api::nccell_bg_palindex].*
198    pub fn bg_palindex(&self) -> NcPaletteIndex {
199        c_api::nccell_bg_palindex(self)
200    }
201
202    /// Is the background [`NcChannel`] using an [`NcPaletteIndex`] indexed
203    /// [`NcPalette`][crate::NcPalette] color?
204    ///
205    /// *C style function: [nccell_bg_palindex_p()][c_api::nccell_bg_palindex_p].*
206    pub fn bg_palindex_p(&self) -> bool {
207        c_api::nccell_bg_palindex_p(self)
208    }
209
210    /// Gets the background [`NcRgb`] (shifted to LSBs).
211    ///
212    /// *C style function: [nccell_bg_rgb()][c_api::nccell_bg_rgb].*
213    pub fn bg_rgb(&self) -> NcRgb {
214        c_api::nccell_bg_rgb(self).into()
215    }
216
217    /// Gets the foreground [`NcAlpha`] (shifted to LSBs).
218    ///
219    /// *C style function: [nccell_fg_alpha()][c_api::nccell_fg_alpha].*
220    pub fn fg_alpha(&self) -> NcAlpha {
221        c_api::nccell_fg_alpha(self).into()
222    }
223
224    /// Is the foreground [`NcChannel`] using the "default foreground color"?
225    ///
226    /// *C style function: [nccell_fg_default_p()][c_api::nccell_fg_default_p].*
227    pub fn fg_default_p(&self) -> bool {
228        c_api::nccell_fg_default_p(self)
229    }
230
231    /// Gets the [`NcPaletteIndex`] of the foreground [`NcChannel`].
232    ///
233    /// *C style function: [nccell_fg_palindex()][c_api::nccell_fg_palindex].*
234    pub fn fg_palindex(&self) -> NcPaletteIndex {
235        c_api::nccell_fg_palindex(self)
236    }
237
238    /// Is the foreground [`NcChannel`] using an [`NcPaletteIndex`] indexed
239    /// [`NcPalette`][crate::NcPalette] color?
240    ///
241    /// *C style function: [nccell_fg_palindex_p()][c_api::nccell_fg_palindex_p].*
242    pub fn fg_palindex_p(&self) -> bool {
243        c_api::nccell_fg_palindex_p(self)
244    }
245
246    /// Gets the foreground [`NcRgb`] (shifted to LSBs).
247    ///
248    /// *C style function: [nccell_fg_rgb()][c_api::nccell_fg_rgb].*
249    pub fn fg_rgb(&self) -> NcRgb {
250        c_api::nccell_fg_rgb(self).into()
251    }
252
253    /// Sets the background [`NcAlpha`].
254    ///
255    /// *C style function: [nccell_set_bg_alpha()][c_api::nccell_set_bg_alpha].*
256    pub fn set_bg_alpha(&mut self, alpha: impl Into<NcAlpha>) {
257        c_api::nccell_set_bg_alpha(self, alpha.into());
258    }
259
260    /// Indicates to use the "default color" for the background [`NcChannel`].
261    ///
262    /// *C style function: [nccell_set_bg_default()][c_api::nccell_set_bg_default].*
263    pub fn set_bg_default(&mut self) {
264        c_api::nccell_set_bg_default(self);
265    }
266
267    /// Sets the background [`NcPaletteIndex`].
268    ///
269    /// Also sets
270    /// [`NcChannels::BG_PALETTE_MASK`][crate::NcChannels#associatedconstant.BG_PALETTE_MASK]
271    /// and
272    /// [`NcAlpha::OPAQUE`][NcAlpha#associatedconstant.OPAQUE], and clears out
273    /// [`NcChannels::BG_DEFAULT_MASK`][NcChannels#associatedconstant.BG_DEFAULT_MASK].
274    ///
275    /// *C style function: [nccell_set_bg_palindex()][c_api::nccell_set_bg_palindex].*
276    pub fn set_bg_palindex(&mut self, index: impl Into<NcPaletteIndex>) {
277        c_api::nccell_set_bg_palindex(self, index.into());
278    }
279
280    /// Sets the background [`NcRgb`] and marks it as not using the default color.
281    ///
282    /// *C style function: [nccell_set_bg_rgb()][c_api::nccell_set_bg_rgb].*
283    pub fn set_bg_rgb(&mut self, rgb: impl Into<NcRgb>) {
284        c_api::nccell_set_bg_rgb(self, rgb.into().0);
285    }
286
287    /// Sets the foreground [`NcAlpha`].
288    ///
289    /// *C style function: [nccell_set_fg_alpha()][c_api::nccell_set_fg_alpha].*
290    pub fn set_fg_alpha(&mut self, alpha: impl Into<NcAlpha>) {
291        c_api::nccell_set_fg_alpha(self, alpha.into());
292    }
293
294    /// Indicates to use the "default color" for the foreground [`NcChannel`].
295    ///
296    /// *C style function: [nccell_set_fg_default()][c_api::nccell_set_fg_default].*
297    pub fn set_fg_default(&mut self) {
298        c_api::nccell_set_fg_default(self);
299    }
300
301    /// Sets the foreground [`NcPaletteIndex`].
302    ///
303    /// Also sets
304    /// [`NcChannels::FG_PALETTE_MASK`][crate::NcChannels#associatedconstant.FG_PALETTE_MASK]
305    /// and
306    /// [`NcAlpha::OPAQUE`][NcAlpha#associatedconstant.OPAQUE], and clears out
307    /// [`NcChannels::FG_DEFAULT_MASK`][NcChannels#associatedconstant.FG_DEFAULT_MASK].
308    ///
309    /// *C style function: [nccell_set_fg_palindex()][c_api::nccell_set_fg_palindex].*
310    pub fn set_fg_palindex(&mut self, index: impl Into<NcPaletteIndex>) {
311        c_api::nccell_set_fg_palindex(self, index.into());
312    }
313
314    /// Sets the foreground [`NcRgb`] and marks it as not using the default color.
315    ///
316    /// *C style function: [nccell_set_fg_rgb()][c_api::nccell_set_fg_rgb].*
317    pub fn set_fg_rgb(&mut self, rgb: impl Into<NcRgb>) {
318        c_api::nccell_set_fg_rgb(self, rgb.into().0);
319    }
320}
321
322/// # `NcCell` methods: other components
323impl NcCell {
324    /// Returns true if the two cells have distinct `EGC`s, attributes,
325    /// or [`NcChannel`]s.
326    ///
327    /// The actual egcpool index needn't be the same--indeed, the planes
328    /// needn't even be the same. Only the expanded `EGC` must be bit-equal.
329    ///
330    /// *C style function: [nccellcmp()][c_api::nccellcmp].*
331    #[cfg(feature = "libc")]
332    #[cfg_attr(feature = "nightly", doc(cfg(feature = "libc")))]
333    pub fn compare(plane1: &NcPlane, cell1: &NcCell, plane2: &NcPlane, cell2: &NcCell) -> bool {
334        c_api::nccellcmp(plane1, cell1, plane2, cell2)
335    }
336
337    /// Saves the [`NcStyle`] and the [`NcChannels`], and returns the duplicatd `EGC`.
338    ///
339    /// *C style function: [nccell_fg_alpha()][c_api::nccell_fg_alpha].*
340    #[cfg(feature = "libc")]
341    #[cfg_attr(feature = "nightly", doc(cfg(feature = "libc")))]
342    pub fn extract(
343        &self,
344        plane: &mut NcPlane,
345        styles: &mut NcStyle,
346        channels: &mut NcChannels,
347    ) -> String {
348        c_api::nccell_extract(plane, self, styles.into(), channels.into())
349    }
350
351    /// Returns the [`NcStyle`] bits.
352    ///
353    /// *C style function: [nccell_styles()][c_api::nccell_styles].*
354    pub fn styles(&self) -> NcStyle {
355        c_api::nccell_styles(self).into()
356    }
357
358    /// Removes the specified [`NcStyle`] bits.
359    ///
360    /// *C style function: [nccell_off_styles()][c_api::nccell_off_styles].*
361    pub fn styles_off(&mut self, stylebits: impl Into<NcStyle>) {
362        c_api::nccell_off_styles(self, stylebits.into().0)
363    }
364
365    /// Adds the specified [`NcStyle`] bits.
366    ///
367    /// *C style function: [nccell_on_styles()][c_api::nccell_on_styles].*
368    pub fn styles_on(&mut self, stylebits: impl Into<NcStyle>) {
369        c_api::nccell_on_styles(self, stylebits.into().0)
370    }
371
372    /// Sets just the specified [`NcStyle`] bits.
373    ///
374    /// *C style function: [nccell_set_styles()][c_api::nccell_set_styles].*
375    pub fn styles_set(&mut self, stylebits: impl Into<NcStyle>) {
376        c_api::nccell_set_styles(self, stylebits.into().0)
377    }
378}
379
380/// # `NcCell` methods: text
381impl NcCell {
382    /// Returns the number of columns occupied by the cell.
383    ///
384    /// See [`ncstrwidth`][c_api::ncstrwidth] for an equivalent for multiple EGCs.
385    ///
386    /// *C style function: [nccell_cols()][c_api::nccell_cols].*
387    pub const fn cols(&self) -> u8 {
388        c_api::nccell_cols(self)
389    }
390
391    // TODO: add ncstrwidth associated method
392
393    /// Returns a pointer to the `EGC` of this NcCell in the `plane`.
394    ///
395    /// This pointer can be invalidated by any further operation on the referred
396    /// plane, so… watch out!
397    ///
398    /// *C style function: [nccell_extended_gcluster()][c_api::nccell_wide_left_p].*
399    pub fn egc(&self, plane: &NcPlane) -> &str {
400        let egcpointer = unsafe { c_api::nccell_extended_gcluster(plane, self) };
401        rstring![egcpointer]
402    }
403
404    /// Copies the UTF8-encoded `EGC` out of this NcCell,
405    /// whether simple or complex.
406    ///
407    /// The result is not tied to the [NcPlane],
408    /// and persists across erases and destruction.
409    ///
410    /// *C style function: [nccell_strdup()][c_api::nccell_strdup].*
411    #[cfg(feature = "libc")]
412    #[cfg_attr(feature = "nightly", doc(cfg(feature = "libc")))]
413    pub fn strdup(&self, plane: &NcPlane) -> String {
414        c_api::nccell_strdup(plane, self)
415    }
416
417    /// Does this NcCell contain a wide codepoint?
418    ///
419    /// *C style function: [nccell_double_wide_p()][c_api::nccell_double_wide_p].*
420    pub fn double_wide_p(&self) -> bool {
421        c_api::nccell_double_wide_p(self)
422    }
423
424    /// Is this the left half of a wide character?
425    ///
426    /// *C style function: [nccell_wide_left_p()][c_api::nccell_wide_left_p].*
427    pub fn wide_left_p(&self) -> bool {
428        c_api::nccell_wide_right_p(self)
429    }
430
431    /// Is this the right side of a wide character?
432    ///
433    /// *C style function: [nccell_wide_right_p()][c_api::nccell_wide_right_p].*
434    pub fn wide_right_p(&self) -> bool {
435        c_api::nccell_wide_right_p(self)
436    }
437}
438
439/// # `NcCell` methods: boxes
440impl NcCell {
441    /// Loads up six cells with the `EGC`s necessary to draw a box.
442    ///
443    /// On error, any [`NcCell`]s this function might have loaded before the error
444    /// are [release][NcCell#method.release]d.
445    /// There must be at least six `EGC`s in `gcluster`.
446    ///
447    /// *C style function: [nccells_load_box()][c_api::nccells_load_box].*
448    pub fn load_box(
449        plane: &mut NcPlane,
450        style: impl Into<NcStyle>,
451        channels: impl Into<NcChannels>,
452        ul: &mut NcCell,
453        ur: &mut NcCell,
454        ll: &mut NcCell,
455        lr: &mut NcCell,
456        hl: &mut NcCell,
457        vl: &mut NcCell,
458        gcluster: &str,
459    ) -> NcResult<()> {
460        let (style, channels) = (style.into(), channels.into());
461        error![c_api::nccells_load_box(
462            plane, style, channels, ul, ur, ll, lr, hl, vl, gcluster
463        )]
464    }
465
466    /// NcCell.[load_box()][NcCell#method.box] with the double box-drawing characters.
467    ///
468    /// *C style function: [nccells_double_box()][c_api::nccells_double_box].*
469    pub fn double_box(
470        plane: &mut NcPlane,
471        style: impl Into<NcStyle>,
472        channels: impl Into<NcChannels>,
473        ul: &mut NcCell,
474        ur: &mut NcCell,
475        ll: &mut NcCell,
476        lr: &mut NcCell,
477        hl: &mut NcCell,
478        vl: &mut NcCell,
479    ) -> NcResult<()> {
480        error![c_api::nccells_double_box(
481            plane,
482            style.into().0,
483            channels.into().0,
484            ul,
485            ur,
486            ll,
487            lr,
488            hl,
489            vl
490        )]
491    }
492
493    /// NcCell.[load_box()][NcCell#method.box] with the rounded box-drawing characters.
494    ///
495    /// *C style function: [nccells_rounded_box()][c_api::nccells_double_box].*
496    pub fn rounded_box(
497        plane: &mut NcPlane,
498        style: impl Into<NcStyle>,
499        channels: impl Into<NcChannels>,
500        ul: &mut NcCell,
501        ur: &mut NcCell,
502        ll: &mut NcCell,
503        lr: &mut NcCell,
504        hl: &mut NcCell,
505        vl: &mut NcCell,
506    ) -> NcResult<()> {
507        error![c_api::nccells_rounded_box(
508            plane,
509            style.into().0,
510            channels.into().0,
511            ul,
512            ur,
513            ll,
514            lr,
515            hl,
516            vl
517        )]
518    }
519
520    /// NcCell.[load_box()][NcCell#method.box] with ASCII characters.
521    ///
522    /// *C style function: [nccells_ascii_box()][c_api::nccells_ascii_box].*
523    pub fn ascii_box(
524        plane: &mut NcPlane,
525        style: impl Into<NcStyle>,
526        channels: impl Into<NcChannels>,
527        ul: &mut NcCell,
528        ur: &mut NcCell,
529        ll: &mut NcCell,
530        lr: &mut NcCell,
531        hl: &mut NcCell,
532        vl: &mut NcCell,
533    ) -> NcResult<()> {
534        error![c_api::nccells_ascii_box(
535            plane,
536            style.into().0,
537            channels.into().0,
538            ul,
539            ur,
540            ll,
541            lr,
542            hl,
543            vl
544        )]
545    }
546    /// NcCell.[load_box()][NcCell#method.box] with the heavy line
547    /// box-drawing characters.
548    ///
549    /// *C style function: [nccells_heavy_box()][c_api::nccells_heavy_box].*
550    pub fn heavy_box(
551        plane: &mut NcPlane,
552        style: impl Into<NcStyle>,
553        channels: impl Into<NcChannels>,
554        ul: &mut NcCell,
555        ur: &mut NcCell,
556        ll: &mut NcCell,
557        lr: &mut NcCell,
558        hl: &mut NcCell,
559        vl: &mut NcCell,
560    ) -> NcResult<()> {
561        error![c_api::nccells_heavy_box(
562            plane,
563            style.into().0,
564            channels.into().0,
565            ul,
566            ur,
567            ll,
568            lr,
569            hl,
570            vl
571        )]
572    }
573
574    /// NcCell.[load_box()][NcCell#method.box] with the light line
575    /// box-drawing characters.
576    ///
577    /// *C style function: [nccells_light_box()][c_api::nccells_light_box].*
578    pub fn light_box(
579        plane: &mut NcPlane,
580        style: impl Into<NcStyle>,
581        channels: impl Into<NcChannels>,
582        ul: &mut NcCell,
583        ur: &mut NcCell,
584        ll: &mut NcCell,
585        lr: &mut NcCell,
586        hl: &mut NcCell,
587        vl: &mut NcCell,
588    ) -> NcResult<()> {
589        error![c_api::nccells_light_box(
590            plane,
591            style.into().0,
592            channels.into().0,
593            ul,
594            ur,
595            ll,
596            lr,
597            hl,
598            vl
599        )]
600    }
601}