libnotcurses_sys/plane/
methods.rs

1//! `NcPlane*` methods and associated functions.
2
3use core::{
4    ffi::{c_char, c_void},
5    ptr::null_mut,
6    slice::from_raw_parts_mut,
7};
8
9use crate::{
10    c_api, cstring, error, error_ref, error_ref_mut, rstring_free, Nc, NcAlign, NcAlpha, NcBlitter,
11    NcBoxMask, NcCell, NcChannel, NcChannels, NcError, NcFadeCb, NcPaletteIndex, NcPixelGeometry,
12    NcPlane, NcPlaneOptions, NcResizeCb, NcResult, NcRgb, NcRgba, NcStyle, NcTime,
13};
14
15#[cfg(feature = "std")]
16use crate::NcFile;
17
18#[cfg(not(feature = "std"))]
19use alloc::{format, string::String, vec::Vec};
20
21/// # NcPlane constructors & destructors
22impl NcPlane {
23    /// Creates a new `NcPlane` child of `parent` plane.
24    ///
25    /// Will be placed at the offset `y`×`x` (relative to the origin of `parent`)
26    /// and with the specified size.
27    ///
28    /// The number of `rows` and `cols` must both be positive.
29    ///
30    /// This plane is initially at the top of the z-buffer, as if [`move_top`]
31    /// had been called on it.
32    ///
33    /// *C style function: [ncplane_create()][c_api::ncplane_create].*
34    ///
35    /// [`move_top`]: NcPlane#method.move_top
36    pub fn new_child<'parent, 'plane, 'opts>(
37        parent: &'parent mut NcPlane,
38        options: &'opts NcPlaneOptions,
39    ) -> NcResult<&'plane mut NcPlane> {
40        error_ref_mut![
41            unsafe { c_api::ncplane_create(parent, options) },
42            &format!["NcPlane::new_plane(NcPlane, {:?})", options] // TODO: show name
43        ]
44    }
45
46    /// Same as [`new_child`] but creates a new pile.
47    ///
48    /// The returned `NcPlane` will be the top, bottom, and root of the new pile.
49    ///
50    /// *C style function: [ncpile_create()][c_api::ncpile_create].*
51    ///
52    /// [`new_child`]: NcPlane#method.new_child
53    pub fn new_pile<'nc, 'plane, 'opts>(
54        nc: &'nc mut Nc,
55        options: &'opts NcPlaneOptions,
56    ) -> NcResult<&'plane mut NcPlane> {
57        error_ref_mut![
58            unsafe { c_api::ncpile_create(nc, options) },
59            &format!["NcPlane::with_options(Nc, {:?})", options]
60        ]
61    }
62
63    /// Creates a new `NcPlane` child of `parent` plane.
64    ///
65    /// Will be placed at the offset `y`×`x` (relative to the origin of `parent`)
66    /// and with the specified size.
67    ///
68    /// The number of `rows` and `cols` must both be positive.
69    ///
70    /// *C style function: [ncplane_create()][c_api::ncplane_create].*
71    pub fn new_child_sized<'plane>(
72        parent: &mut NcPlane,
73        y: i32,
74        x: i32,
75        rows: u32,
76        cols: u32,
77    ) -> NcResult<&'plane mut NcPlane> {
78        Self::new_child(parent, &NcPlaneOptions::new(y, x, rows, cols))
79    }
80
81    /// Same as [`new_child_sized`] but creates a new pile.
82    ///
83    /// The returned `NcPlane` will be the top, bottom, and root of the new pile.
84    /// Creates a new `NcPlane` child of `parent` plane.
85    ///
86    /// *C style function: [ncpile_create()][c_api::ncpile_create].*
87    ///
88    /// [`new_child_sized`]: NcPlane#method.new_child_sized
89    pub fn new_pile_sized<'nc, 'plane>(
90        nc: &'nc mut Nc,
91        y: i32,
92        x: i32,
93        rows: u32,
94        cols: u32,
95    ) -> NcResult<&'plane mut NcPlane> {
96        Self::new_pile(nc, &NcPlaneOptions::new(y, x, rows, cols))
97    }
98
99    /// Destroys this `NcPlane`.
100    ///
101    /// None of its contents will be visible after the next render call.
102    ///
103    /// It is an error to attempt to destroy the standard plane.
104    ///
105    /// *C style function: [ncplane_destroy()][c_api::ncplane_destroy].*
106    pub fn destroy(&mut self) -> NcResult<()> {
107        error![unsafe { c_api::ncplane_destroy(self) }, "NcPlane.destroy()"]
108    }
109}
110
111// -----------------------------------------------------------------------------
112/// ## NcPlane methods: `NcAlpha`
113impl NcPlane {
114    /// Gets the foreground [`NcAlpha`] from this `NcPlane`, shifted to LSBs.
115    ///
116    /// *C style function: [ncplane_fg_alpha()][c_api::ncplane_fg_alpha].*
117    #[inline]
118    pub fn fg_alpha(&self) -> NcAlpha {
119        c_api::ncchannels_fg_alpha(c_api::ncplane_channels(self)).into()
120    }
121
122    /// Gets the background [`NcAlpha`] for this `NcPlane`, shifted to LSBs.
123    ///
124    /// *C style function: [ncplane_bg_alpha()][c_api::ncplane_bg_alpha].*
125    #[inline]
126    pub fn bg_alpha(&self) -> NcAlpha {
127        c_api::ncchannels_bg_alpha(c_api::ncplane_channels(self)).into()
128    }
129
130    /// Sets the foreground [`NcAlpha`] from this `NcPlane`.
131    ///
132    /// *C style function: [ncplane_set_fg_alpha()][c_api::ncplane_set_fg_alpha].*
133    pub fn set_fg_alpha(&mut self, alpha: impl Into<NcAlpha>) -> NcResult<()> {
134        let alpha = alpha.into();
135        error![
136            unsafe { c_api::ncplane_set_fg_alpha(self, alpha as i32) },
137            &format!("NcPlane.set_fg_alpha({})", alpha)
138        ]
139    }
140
141    /// Sets the background [`NcAlpha`] for this `NcPlane`.
142    ///
143    /// *C style function: [ncplane_set_bg_alpha()][c_api::ncplane_set_bg_alpha].*
144    pub fn set_bg_alpha(&mut self, alpha: impl Into<NcAlpha>) -> NcResult<()> {
145        let alpha = alpha.into();
146        error![
147            unsafe { c_api::ncplane_set_bg_alpha(self, alpha as i32) },
148            &format!("NcPlane.set_bg_alpha({})", alpha)
149        ]
150    }
151}
152
153// -----------------------------------------------------------------------------
154/// ## NcPlane methods: `NcChannel`
155impl NcPlane {
156    /// Gets the current [`NcChannels`] from this `NcPlane`.
157    ///
158    /// *C style function: [ncplane_channels()][c_api::ncplane_channels].*
159    pub fn channels(&self) -> NcChannels {
160        c_api::ncplane_channels(self).into()
161    }
162
163    /// Sets the current [`NcChannels`] for this `NcPlane`.
164    ///
165    /// *C style function: [ncplane_set_channels()][c_api::ncplane_set_channels].*
166    pub fn set_channels(&mut self, channels: impl Into<NcChannels>) {
167        c_api::ncplane_set_channels(self, channels.into().0);
168    }
169
170    /// Gets the foreground [`NcChannel`] from an [`NcPlane`].
171    ///
172    /// *C style function: [ncplane_fchannel()][c_api::ncplane_fchannel].*
173    #[inline]
174    pub fn fchannel(&self) -> NcChannel {
175        c_api::ncchannels_fchannel(c_api::ncplane_channels(self)).into()
176    }
177
178    /// Gets the background [`NcChannel`] from an [`NcPlane`].
179    ///
180    /// *C style function: [ncplane_bchannel()][c_api::ncplane_bchannel].*
181    #[inline]
182    pub fn bchannel(&self) -> NcChannel {
183        c_api::ncchannels_bchannel(c_api::ncplane_channels(self)).into()
184    }
185
186    /// Sets the current foreground [`NcChannel`] for this `NcPlane`.
187    /// Returns the updated [`NcChannels`].
188    ///
189    /// *C style function: [ncplane_set_fchannel()][c_api::ncplane_set_fchannel].*
190    pub fn set_fchannel(&mut self, channel: impl Into<NcChannel>) -> NcChannels {
191        c_api::ncplane_set_fchannel(self, channel.into().0).into()
192    }
193
194    /// Sets the current background [`NcChannel`] for this `NcPlane`.
195    /// Returns the updated [`NcChannels`].
196    ///
197    /// *C style function: [ncplane_set_bchannel()][c_api::ncplane_set_bchannel].*
198    pub fn set_bchannel(&mut self, channel: impl Into<NcChannel>) -> NcChannels {
199        c_api::ncplane_set_bchannel(self, channel.into().0).into()
200    }
201
202    /// Sets the given [`NcChannels`]s throughout the specified region,
203    /// keeping content and attributes unchanged.
204    ///
205    /// The upper left corner is at `y`, `x`, and `None` may be
206    /// specified to indicate the cursor's position in that dimension.
207    ///
208    /// The area is specified by 'len_y', 'len_x', and `None` may be specified
209    /// to indicate everything remaining to the right and below, respectively.
210    ///
211    /// It is an error for any coordinate to be outside the plane.
212    ///
213    /// Returns the number of cells set, or -1 on failure.
214    ///
215    /// *C style function: [ncplane_stain()][c_api::ncplane_stain].*
216    pub fn stain(
217        &mut self,
218        y: Option<u32>,
219        x: Option<u32>,
220        len_y: Option<u32>,
221        len_x: Option<u32>,
222        ul: impl Into<NcChannels>,
223        ur: impl Into<NcChannels>,
224        ll: impl Into<NcChannels>,
225        lr: impl Into<NcChannels>,
226    ) -> NcResult<u32> {
227        let (ul, ur, ll, lr) = (ul.into(), ur.into(), ll.into(), lr.into());
228        let res = unsafe {
229            c_api::ncplane_stain(
230                self,
231                y.unwrap_or(u32::MAX) as i32, // -1_i32
232                x.unwrap_or(u32::MAX) as i32, // "
233                len_y.unwrap_or(0),
234                len_x.unwrap_or(0),
235                ul.0,
236                ur.0,
237                ll.0,
238                lr.0,
239            )
240        };
241        error![
242            res,
243            &format!(
244                "NcPlane.stain({:?}, {:?}, {:?}, {:?}, {:0X}, {:0X}, {:0X}, {:0X})",
245                y, x, len_y, len_x, ul, ur, ll, lr
246            ),
247            res as u32
248        ]
249    }
250}
251
252// -----------------------------------------------------------------------------
253/// ## NcPlane methods: `NcRgb`, components & default color
254impl NcPlane {
255    /// Gets the foreground [`NcRgb`] from this `NcPlane`, shifted to LSBs.
256    ///
257    /// *C style function: [ncplane_fg_rgb()][c_api::ncplane_fg_rgb].*
258    #[inline]
259    pub fn fg_rgb(&self) -> NcRgb {
260        c_api::ncchannels_fg_rgb(c_api::ncplane_channels(self)).into()
261    }
262
263    /// Gets the background [`NcRgb`] from this `NcPlane`, shifted to LSBs.
264    ///
265    /// *C style function: [ncplane_bg_rgb()][c_api::ncplane_bg_rgb].*
266    #[inline]
267    pub fn bg_rgb(&self) -> NcRgb {
268        c_api::ncchannels_bg_rgb(c_api::ncplane_channels(self)).into()
269    }
270
271    /// Sets the foreground [`NcRgb`] for this `NcPlane`.
272    ///
273    /// *C style function: [ncplane_set_fg_rgb()][c_api::ncplane_set_fg_rgb].*
274    #[inline]
275    pub fn set_fg_rgb(&mut self, rgb: impl Into<NcRgb>) {
276        unsafe {
277            c_api::ncplane_set_fg_rgb(self, rgb.into().into());
278        }
279    }
280
281    /// Sets the background [`NcRgb`] for this `NcPlane`.
282    ///
283    /// *C style function: [ncplane_set_bg_rgb()][c_api::ncplane_set_bg_rgb].*
284    #[inline]
285    pub fn set_bg_rgb(&mut self, rgb: impl Into<NcRgb>) {
286        unsafe {
287            c_api::ncplane_set_bg_rgb(self, rgb.into().into());
288        }
289    }
290
291    /// Is this `NcPlane`'s foreground using the "default foreground color"?
292    ///
293    /// *C style function: [ncplane_fg_default_p()][c_api::ncplane_fg_default_p].*
294    #[inline]
295    pub fn fg_default(&self) -> bool {
296        c_api::ncchannels_fg_default_p(c_api::ncplane_channels(self))
297    }
298
299    /// Is this `NcPlane`'s background using the "default background color"?
300    ///
301    /// *C style function: [ncplane_bg_default_p()][c_api::ncplane_bg_default_p].*
302    #[inline]
303    pub fn bg_default(&self) -> bool {
304        c_api::ncchannels_bg_default_p(c_api::ncplane_channels(self))
305    }
306
307    /// Uses the default color for the foreground.
308    ///
309    /// *C style function: [ncplane_set_fg_default()][c_api::ncplane_set_fg_default].*
310    #[inline]
311    pub fn set_fg_default(&mut self) {
312        unsafe {
313            c_api::ncplane_set_fg_default(self);
314        }
315    }
316
317    /// Uses the default color for the background.
318    ///
319    /// *C style function: [ncplane_set_bg_default()][c_api::ncplane_set_bg_default].*
320    #[inline]
321    pub fn set_bg_default(&mut self) {
322        unsafe {
323            c_api::ncplane_set_bg_default(self);
324        }
325    }
326
327    /// Marks the foreground as NOT using the default color.
328    ///
329    /// Returns the new [`NcChannels`].
330    ///
331    /// *C style function: [ncplane_set_fg_not_default()][c_api::ncplane_set_fg_not_default].*
332    //
333    // Not in the C API
334    #[inline]
335    pub fn set_fg_not_default(&mut self) -> NcChannels {
336        c_api::ncplane_set_fg_not_default(self).into()
337    }
338
339    /// Marks the background as NOT using the default color.
340    ///
341    /// Returns the new [`NcChannels`].
342    ///
343    /// *C style function: [ncplane_set_bg_not_default()][c_api::ncplane_set_bg_not_default].*
344    //
345    // Not in the C API
346    #[inline]
347    pub fn set_bg_not_default(&mut self) -> NcChannels {
348        c_api::ncplane_set_bg_not_default(self).into()
349    }
350
351    /// Marks both the foreground and background as using the default color.
352    ///
353    /// Returns the new [`NcChannels`].
354    ///
355    /// *C style function: [ncplane_set_default()][c_api::ncplane_set_default].*
356    //
357    // Not in the C API
358    #[inline]
359    pub fn set_default(&mut self) -> NcChannels {
360        c_api::ncplane_set_default(self).into()
361    }
362
363    /// Marks both the foreground and background as NOT using the default color.
364    ///
365    /// Returns the new [`NcChannels`].
366    ///
367    /// *C style function: [ncplane_set_not_default()][c_api::ncplane_set_not_default].*
368    //
369    // Not in the C API
370    #[inline]
371    pub fn set_not_default(&mut self) -> NcChannels {
372        c_api::ncplane_set_not_default(self).into()
373    }
374}
375
376// -----------------------------------------------------------------------------
377/// ## NcPlane methods: `NcStyle` & `PaletteIndex`
378impl NcPlane {
379    /// Sets the given style throughout the specified region, keeping content
380    /// and channels unchanged.
381    ///
382    /// The upper left corner is at `y`, `x`, and `None` may be
383    /// specified to indicate the cursor's position in that dimension.
384    ///
385    /// The area is specified by 'len_y', 'len_x', and `None` may be specified
386    /// to indicate everything remaining to the right and below, respectively.
387    ///
388    /// It is an error for any coordinate to be outside the plane.
389    ///
390    /// Returns the number of cells set, or -1 on failure.
391    ///
392    /// *C style function: [ncplane_format()][c_api::ncplane_format].*
393    pub fn format(
394        &mut self,
395        y: Option<u32>,
396        x: Option<u32>,
397        len_y: Option<u32>,
398        len_x: Option<u32>,
399        style: impl Into<NcStyle>,
400    ) -> NcResult<u32> {
401        let style = style.into();
402        let res = unsafe {
403            c_api::ncplane_format(
404                self,
405                y.unwrap_or(u32::MAX) as i32, // -1_i32
406                x.unwrap_or(u32::MAX) as i32, // "
407                len_y.unwrap_or(0),
408                len_x.unwrap_or(0),
409                style.into(),
410            )
411        };
412        error![
413            res,
414            &format!(
415                "NcPlane.format({:?}, {:?}, {:?}, {:?}, {:0X})",
416                y, x, len_y, len_x, style
417            ),
418            res as u32
419        ]
420    }
421
422    /// Returns the current styles for this `NcPlane`.
423    ///
424    /// *C style function: [ncplane_styles()][c_api::ncplane_styles].*
425    pub fn styles(&self) -> NcStyle {
426        unsafe { c_api::ncplane_styles(self).into() }
427    }
428
429    /// Removes the specified `styles` from this `NcPlane`'s existing spec.
430    ///
431    /// *C style function: [ncplane_off_styles()][c_api::ncplane_off_styles].*
432    pub fn off_styles(&mut self, styles: impl Into<NcStyle>) {
433        unsafe {
434            c_api::ncplane_off_styles(self, styles.into().into());
435        }
436    }
437
438    /// Adds the specified `styles` to this `NcPlane`'s existing spec.
439    ///
440    /// *C style function: [ncplane_on_styles()][c_api::ncplane_on_styles].*
441    pub fn on_styles(&mut self, styles: impl Into<NcStyle>) {
442        unsafe {
443            c_api::ncplane_on_styles(self, styles.into().into());
444        }
445    }
446
447    /// Sets just the specified `styles` for this `NcPlane`.
448    ///
449    /// *C style function: [ncplane_set_styles()][c_api::ncplane_set_styles].*
450    pub fn set_styles(&mut self, styles: impl Into<NcStyle>) {
451        unsafe {
452            c_api::ncplane_set_styles(self, styles.into().into());
453        }
454    }
455
456    /// Sets this `NcPlane`'s foreground [`NcPaletteIndex`].
457    ///
458    /// Also sets the foreground palette index bit, sets it foreground-opaque,
459    /// and clears the foreground default color bit.
460    ///
461    /// *C style function: [ncplane_set_fg_palindex()][c_api::ncplane_set_fg_palindex].*
462    pub fn set_fg_palindex(&mut self, palindex: impl Into<NcPaletteIndex>) {
463        unsafe {
464            c_api::ncplane_set_fg_palindex(self, palindex.into() as u32);
465        }
466    }
467
468    /// Sets this `NcPlane`'s background [`impl Into<NcPaletteIndex>`].
469    ///
470    /// Also sets the background palette index bit, sets it background-opaque,
471    /// and clears the background default color bit.
472    ///
473    /// *C style function: [ncplane_set_bg_palindex()][c_api::ncplane_set_bg_palindex].*
474    pub fn set_bg_palindex(&mut self, palindex: impl Into<NcPaletteIndex>) {
475        unsafe {
476            c_api::ncplane_set_bg_palindex(self, palindex.into() as u32);
477        }
478    }
479}
480
481// -----------------------------------------------------------------------------
482/// ## NcPlane methods: `NcCell` & strings
483impl NcPlane {
484    /// Retrieves the current contents of the [`NcCell`] under the cursor,
485    /// returning the `EGC` and writing out the [`NcStyle`] and the [`NcChannels`].
486    ///
487    /// *C style function: [ncplane_at_cursor()][c_api::ncplane_at_cursor].*
488    #[cfg(feature = "libc")]
489    #[cfg_attr(feature = "nightly", doc(cfg(feature = "libc")))]
490    pub fn at_cursor(
491        &mut self,
492        stylemask: &mut NcStyle,
493        channels: &mut NcChannels,
494    ) -> NcResult<String> {
495        let egc = unsafe { c_api::ncplane_at_cursor(self, stylemask.into(), &mut channels.0) };
496        if egc.is_null() {
497            return Err(NcError::with_msg(
498                c_api::NCRESULT_ERR,
499                &format!("NcPlane.at_cursor({:0X}, {:0X})", stylemask, channels),
500            ));
501        }
502        Ok(rstring_free![egc])
503    }
504
505    /// Retrieves the current contents of the [`NcCell`] under the cursor
506    /// into `cell`. Returns the number of bytes in the `EGC`.
507    ///
508    /// This NcCell is invalidated if the associated NcPlane is destroyed.
509    ///
510    /// *C style function: [ncplane_at_cursor_cell()][c_api::ncplane_at_cursor_cell].*
511    #[inline]
512    pub fn at_cursor_cell(&mut self, cell: &mut NcCell) -> NcResult<u32> {
513        let bytes = unsafe { c_api::ncplane_at_cursor_cell(self, cell) };
514        error![
515            bytes,
516            &format!("NcPlane.at_cursor_cell({:?})", cell),
517            bytes as u32
518        ]
519    }
520
521    /// Returns a copy of the current contents of the specified [`NcCell`].
522    ///
523    /// Writes out the [`NcStyle`] and the [`NcChannels`].
524    ///
525    /// # Usage
526    ///
527    /// The return represents how the cell will be used during rendering,
528    /// and thus integrates any base cell where appropriate:
529    ///
530    /// - If called upon the secondary columns of a wide glyph, the EGC will be
531    /// returned (i.e. this function does not distinguish between the primary
532    /// and secondary columns of a wide glyph).
533    /// - If called on a sprixel plane, its control sequence is returned for all
534    /// valid locations.
535    ///
536    /// *C style function: [ncplane_at_yx()][c_api::ncplane_at_yx].*
537    #[cfg(feature = "libc")]
538    #[cfg_attr(feature = "nightly", doc(cfg(feature = "libc")))]
539    pub fn at_yx(
540        &mut self,
541        y: u32,
542        x: u32,
543        stylemask: &mut NcStyle,
544        channels: &mut NcChannels,
545    ) -> NcResult<String> {
546        let egc = unsafe {
547            c_api::ncplane_at_yx(self, y as i32, x as i32, stylemask.into(), &mut channels.0)
548        };
549        if egc.is_null() {
550            return Err(NcError::with_msg(
551                c_api::NCRESULT_ERR,
552                &format!(
553                    "NcPlane.at_yx({}, {}, {:0X}, {:0X})",
554                    y, x, stylemask, channels
555                ),
556            ));
557        }
558        Ok(rstring_free![egc])
559    }
560
561    /// Retrieves the current contents of the specified [`NcCell`] into `cell`.
562    /// Returns the number of bytes in the `EGC`.
563    ///
564    /// This NcCell is invalidated if the associated plane is destroyed.
565    ///
566    /// *C style function: [ncplane_at_yx_cell()][c_api::ncplane_at_yx_cell].*
567    #[inline]
568    pub fn at_yx_cell(&mut self, y: u32, x: u32, cell: &mut NcCell) -> NcResult<u32> {
569        let bytes = unsafe { c_api::ncplane_at_yx_cell(self, y as i32, x as i32, cell) };
570        error![
571            bytes,
572            &format!("NcPlane.at_yx_cell({}, {}, {:?})", y, x, cell),
573            bytes as u32
574        ]
575    }
576
577    /// Extracts this `NcPlane`'s base [`NcCell`].
578    ///
579    /// The reference is invalidated if this `NcPlane` is destroyed.
580    ///
581    /// *C style function: [ncplane_base()][c_api::ncplane_base].*
582    pub fn base(&mut self) -> NcResult<NcCell> {
583        let mut cell = NcCell::new();
584        let res = unsafe { c_api::ncplane_base(self, &mut cell) };
585        error![res, "NcPlane.base()", cell]
586    }
587
588    /// Sets this `NcPlane`'s base [`NcCell`] from its components.
589    ///
590    /// Returns the number of bytes copied out of `egc` if succesful.
591    ///
592    /// It will be used for purposes of rendering anywhere that the `NcPlane`'s
593    /// gcluster is 0.
594    ///
595    /// Note that erasing the `NcPlane` does not reset the base cell.
596    ///
597    /// *C style function: [ncplane_set_base()][c_api::ncplane_set_base].*
598    // call stack:
599    // - ncplane_set_base calls nccell_prime:
600    //      return nccell_prime(ncp, &ncp->basecell, egc, stylemask, channels);
601    // - nccell_prime calls notcurses.c/nccell_load:
602    //      return nccell_load(n, c, gcluster);
603    // - cell-load calls internal.h/pool load:
604    //      return pool_load(&n->pool, c, gcluster);
605    pub fn set_base(
606        &mut self,
607        egc: &str,
608        style: impl Into<NcStyle>,
609        channels: impl Into<NcChannels>,
610    ) -> NcResult<u32> {
611        let (style, channels) = (style.into(), channels.into());
612        let cs = cstring![egc];
613        let res = unsafe { c_api::ncplane_set_base(self, cs.as_ptr(), style.into(), channels.0) };
614        error![
615            res,
616            &format!("NcPlane.set_base({:?}, {:0X}, {:0X})", egc, style, channels),
617            res as u32
618        ]
619    }
620
621    /// Sets this `NcPlane`'s base [`NcCell`].
622    ///
623    /// It will be used for purposes of rendering anywhere that the `NcPlane`'s
624    /// gcluster is 0.
625    ///
626    /// Note that erasing the `NcPlane` does not reset the base cell.
627    ///
628    /// *C style function: [ncplane_set_base_cell()][c_api::ncplane_set_base_cell].*
629    pub fn set_base_cell(&mut self, cell: &NcCell) -> NcResult<()> {
630        error![
631            unsafe { c_api::ncplane_set_base_cell(self, cell) },
632            &format!("NcPlane.base({:?})", cell)
633        ]
634    }
635
636    /// Creates a flat string from the `EGC`'s of the selected region of the
637    /// `NcPlane`.
638    ///
639    /// Starts at the plane's `beg_y` * `beg_x` coordinates (which must lie on
640    /// the plane), continuing for `len_y` x `len_x` cells.
641    ///
642    /// Use `None` for either or all of `beg_y` and `beg_x` in order to
643    /// use the current cursor position along that axis.
644    ///
645    /// Use `None` for either or both of `len_y` and `len_x` in order to
646    /// go through the boundary of the plane in that axis (same as `0`).
647    ///
648    /// # Errors
649    /// If either `len_y` or `len_x` fall outside the plane's boundaries.
650    ///
651    /// *C style function: [ncplane_contents()][c_api::ncplane_contents].*
652    pub fn contents(
653        &mut self,
654        beg_y: Option<u32>,
655        beg_x: Option<u32>,
656        len_y: Option<u32>,
657        len_x: Option<u32>,
658    ) -> NcResult<String> {
659        let ptr = unsafe {
660            c_api::ncplane_contents(
661                self,
662                beg_y.unwrap_or(u32::MAX) as i32, // -1_i32
663                beg_x.unwrap_or(u32::MAX) as i32, // "
664                len_y.unwrap_or(0),
665                len_x.unwrap_or(0),
666            )
667        };
668        if ptr.is_null() {
669            Err(NcError::with_msg(
670                c_api::NCRESULT_ERR,
671                "NcPlane.contents error",
672            ))
673        } else {
674            Ok(rstring_free![ptr])
675        }
676    }
677
678    /// Erases every [`NcCell`] in this `NcPlane`, resetting all attributes to
679    /// normal, all colors to the default color, and all cells to undrawn.
680    ///
681    /// All cells associated with this `NcPlane` are invalidated, and must not
682    /// be used after the call, excluding the base cell. The cursor is homed.
683    ///
684    /// *C style function: [ncplane_erase()][c_api::ncplane_erase].*
685    pub fn erase(&mut self) {
686        unsafe {
687            c_api::ncplane_erase(self);
688        }
689    }
690
691    /// Erases every cell in the region beginning at (`beg_y`, `beg_x`) and
692    /// having a size (`len_y` × `len_x`) for non-zero lengths.
693    ///
694    /// If `beg_y` and/or `beg_x` are `None`, the current cursor position
695    /// along that axis is used.
696    ///
697    /// A negative `len_y` means to move up from the origin, and a negative
698    /// `len_x` means to move left from the origin. A positive `len_y` moves down,
699    /// and a positive `len_x` moves right.
700    ///
701    /// A value of `0` for the length erases everything along that dimension.
702    ///
703    /// # Errors
704    /// It is an error if the starting coordinate is not in the plane,
705    /// but the ending coordinate may be outside the plane.
706    ///
707    /// ```ignore
708    /// // For example, on a plane of 20 rows and 10 columns, with the cursor at
709    /// // row 10 and column 5, the following would hold:
710    ///
711    /// (None, None, 0, 1) // clears the column to the right of the cursor (col 6)
712    /// (None, None, 0, -1) // clears the column to the left of the cursor (col 4)
713    /// (None, None, i32::MAX, 0) // clears all rows with or below the cursor (rows 10..19)
714    /// (None, None, i32::MIN, 0) // clears all rows with or above the cursor (rows 0..10)
715    /// (None, 4, 3, 3) // clears from [row 5, col 4] through [row 7, col 6]
716    /// (None, 4, -3, -3) // clears from [row 5, col 4] through [row 3, col 2]
717    /// (4, None, 0, 3) // clears columns 5, 6, and 7
718    /// (None, None, 0, 0) // clears the plane *if the cursor is in a legal position*
719    /// (0, 0, 0, 0) // clears the plane in all cases
720    /// ```
721    /// See also the [`erase_region` example][0].
722    ///
723    /// [0]: https://github.com/dankamongmen/libnotcurses-sys/blob/main/examples/erase_region.rs
724    ///
725    /// *C style function: [ncplane_erase_region()][c_api::ncplane_erase_region].*
726    pub fn erase_region(
727        &mut self,
728        beg_y: Option<u32>,
729        beg_x: Option<u32>,
730        len_y: i32,
731        len_x: i32,
732    ) -> NcResult<()> {
733        error![
734            unsafe {
735                c_api::ncplane_erase_region(
736                    self,
737                    beg_y.unwrap_or(u32::MAX) as i32, // -1_i32
738                    beg_x.unwrap_or(u32::MAX) as i32, // "
739                    len_y,
740                    len_x,
741                )
742            },
743            &format!(
744                "NcPlane.erase_region({:?}, {:?}, {}, {})",
745                beg_y, beg_x, len_y, len_x
746            )
747        ]
748    }
749
750    /// Replaces the `NcCell` at the **specified** coordinates with the provided
751    /// `NcCell`, advancing the cursor by its width (but not past the end of
752    /// the plane).
753    ///
754    /// The new `NcCell` must already be associated with this `NcPlane`.
755    ///
756    /// On success, returns the number of columns the cursor was advanced.
757    ///
758    /// If the glyph can not fit in the current line, it is an error, unless
759    /// scrolling is enabled.
760    ///
761    /// *C style function: [ncplane_putc_yx()][c_api::ncplane_putc_yx].*
762    pub fn putc_yx(&mut self, y: u32, x: u32, cell: &NcCell) -> NcResult<u32> {
763        let res = unsafe { c_api::ncplane_putc_yx(self, y as i32, x as i32, cell) };
764        error![
765            res,
766            &format!("NcPlane.putc_yx({}, {}, {:?})", y, x, cell),
767            res as u32
768        ]
769    }
770
771    /// Replaces the [`NcCell`] at the **current** coordinates with the provided
772    /// `NcCell`, advancing the cursor by its width (but not past the end of
773    /// the plane).
774    ///
775    /// The new `NcCell` must already be associated with the `NcPlane`.
776    ///
777    /// On success, returns the number of columns the cursor was advanced.
778    ///
779    /// If the glyph can not fit in the current line, it is an error, unless
780    /// scrolling is enabled.
781    ///
782    /// *C style function: [ncplane_putc()][c_api::ncplane_putc].*
783    pub fn putc(&mut self, cell: &NcCell) -> NcResult<u32> {
784        let res = c_api::ncplane_putc(self, cell);
785        error![res, &format!("NcPlane.putc({:?})", cell), res as u32]
786    }
787
788    /// Calls [`putchar_yx`][NcPlane#method.putchar_yx] at the current cursor
789    /// location.
790    ///
791    /// On success, returns the number of columns the cursor was advanced.
792    ///
793    /// If the glyph can not fit in the current line, it is an error, unless
794    /// scrolling is enabled.
795    ///
796    /// NOTE: Unlike the original C function, this one accepts any 4-byte `char`.
797    ///
798    /// *C style function: [ncplane_putchar()][c_api::ncplane_putchar].*
799    pub fn putchar(&mut self, ch: char) -> NcResult<u32> {
800        let res = c_api::ncplane_putchar(self, ch);
801        error![res, &format!("NcPlane.putchar({:?})", ch), res as u32]
802    }
803
804    /// Replaces the [`NcCell`] at the current location with the provided `char`,
805    /// while retaining the previous style.
806    ///
807    /// On success, returns the number of columns the cursor was advanced.
808    ///
809    /// If the glyph can not fit in the current line, it is an error, unless
810    /// scrolling is enabled.
811    ///
812    /// NOTE: Unlike the original C function, this one accepts any 4-byte `char`.
813    ///
814    /// *C style function: [ncplane_putchar_stained()][c_api::ncplane_putchar_stained].*
815    // WIP
816    pub fn putchar_stained(&mut self, ch: char) -> NcResult<u32> {
817        let res = c_api::ncplane_putchar_stained(self, ch);
818        error![
819            res,
820            &format!("NcPlane.putchar_stained({:?})", ch),
821            res as u32
822        ]
823    }
824
825    /// Replaces the [`NcCell`] at the specified coordinates with the provided
826    /// [`char`], using the current style.
827    ///
828    /// On success, returns the number of columns the cursor was advanced.
829    ///
830    /// If the glyph can not fit in the current line, it is an error, unless
831    /// scrolling is enabled.
832    ///
833    /// NOTE: Unlike the original C function, this one accepts any 4-byte `char`.
834    ///
835    /// *C style function: [ncplane_putchar_yx()][c_api::ncplane_putchar_yx].*
836    pub fn putchar_yx(&mut self, y: u32, x: u32, ch: char) -> NcResult<u32> {
837        let res = c_api::ncplane_putchar_yx(self, y, x, ch);
838        error![
839            res,
840            &format!("NcPlane.putchar_yx({}, {}, {:?})", y, x, ch),
841            res as u32
842        ]
843    }
844
845    /// Replaces the [`NcCell`] at the current location with the provided `egc`,
846    /// using the current style.
847    ///
848    /// Advances the cursor by the width of the cluster (but not past the end of
849    /// the the plane), and this number is returned on success.
850    ///
851    /// The number of bytes converted from the `egc` can be optionally written
852    /// to `sbytes`.
853    ///
854    /// If the glyph can not fit in the current line, it is an error, unless
855    /// scrolling is enabled.
856    ///
857    /// NOTE: Unlike the original C function, this one accepts any 4-byte `char`.
858    ///
859    /// *C style function: [ncplane_putegc()][c_api::ncplane_putegc].*
860    pub fn putegc(&mut self, egc: &str, sbytes: Option<&mut usize>) -> NcResult<u32> {
861        let res = c_api::ncplane_putegc(self, egc, sbytes);
862        error![res, &format!("NcPlane.putegc({:?}, …)", egc), res as u32]
863    }
864
865    /// Replaces the [`NcCell`] at the specified coordinates with the provided
866    /// `egc`, using the current style.
867    ///
868    /// Advances the cursor by the width of the cluster (but not past the end of
869    /// the the plane), and this number is returned on success.
870    ///
871    /// The number of bytes converted from the `egc` can be optionally written
872    /// to `sbytes`.
873    ///
874    /// If the glyph can not fit in the current line, it is an error, unless
875    /// scrolling is enabled.
876    ///
877    /// NOTE: Unlike the original C function, this one accepts any 4-byte `char`.
878    ///
879    /// *C style function: [ncplane_putegc_yx()][c_api::ncplane_putegc_yx].*
880    pub fn putegc_yx(
881        &mut self,
882        y: Option<u32>,
883        x: Option<u32>,
884        egc: &str,
885        sbytes: Option<&mut usize>,
886    ) -> NcResult<u32> {
887        let res = c_api::ncplane_putegc_yx(self, y, x, egc, sbytes);
888        error![
889            res,
890            &format!("NcPlane.putegc_yx({:?}, {:?}, {:?}, …)", y, x, egc),
891            res as u32
892        ]
893    }
894
895    /// Replaces the [`NcCell`] at the current location with the provided `egc`,
896    /// while retaining the previous style.
897    ///
898    /// Advances the cursor by the width of the cluster (but not past the end of
899    /// the the plane), and this number is returned on success.
900    ///
901    /// The number of bytes converted from the `egc` can be optionally written
902    /// to `sbytes`.
903    ///
904    /// If the glyph can not fit in the current line, it is an error, unless
905    /// scrolling is enabled.
906    ///
907    /// NOTE: Unlike the original C function, this one accepts any 4-byte `char`.
908    ///
909    /// *C style function: [ncplane_putegc_stained()][c_api::ncplane_putegc_stained].*
910    pub fn putegc_stained(&mut self, egc: &str, sbytes: Option<&mut usize>) -> NcResult<u32> {
911        let res = c_api::ncplane_putegc_stained(self, egc, sbytes);
912        error![
913            res,
914            &format!("NcPlane.putegc_stained({:?}, …)", egc),
915            res as u32
916        ]
917    }
918
919    /// Write the specified text to the plane, breaking lines sensibly,
920    /// beginning at the specified line.
921    ///
922    /// Returns the number of columns written, including the cleared columns.
923    ///
924    /// When breaking a line, the line will be cleared to the end of the plane
925    /// (the last line will *not* be so cleared).
926    //
927    // MAYBE:
928    // The number of bytes written from the input is written to '*bytes'
929    // if it is not NULL.
930    //
931    // Cleared columns are included in the return value, but *not* included in
932    // the number of bytes written.
933    //
934    /// Leaves the cursor at the end of output. A partial write will be
935    /// accomplished as far as it can;
936    //
937    // determine whether the write completed by inspecting '*bytes'.
938    ///
939    /// If a glyph can not fit in the current line, it is an error, unless
940    /// scrolling is enabled.
941    ///
942    /// *C style function: [ncplane_puttext()][c_api::ncplane_puttext].*
943    pub fn puttext(&mut self, y: u32, align: impl Into<NcAlign>, string: &str) -> NcResult<u32> {
944        let cs = cstring![string];
945        let res = unsafe {
946            c_api::ncplane_puttext(self, y as i32, align.into().into(), cs.as_ptr(), null_mut())
947        };
948        error![res, &format!("NcPlane.puttext({:?})", string), res as u32]
949    }
950
951    /// Writes a string to the current location, using the current style.
952    ///
953    /// Advances the cursor by some positive number of columns (though not
954    /// beyond the end of the plane), and this number is returned on success.
955    ///
956    /// Newlines are counted as 1 column.
957    ///
958    /// On error, a non-positive number is returned, indicating
959    /// the number of columns which were written before the error.
960    ///
961    /// If a glyph can not fit in the current line, it is an error, unless
962    /// scrolling is enabled.
963    ///
964    /// *C style function: [ncplane_putstr()][c_api::ncplane_putstr].*
965    #[inline]
966    pub fn putstr(&mut self, string: &str) -> NcResult<u32> {
967        let res = c_api::ncplane_putstr(self, string);
968        error![res, &format!("NcPlane.putstr({:?})", string), res as u32]
969    }
970
971    /// Same as [`putstr`][NcPlane#method.putstr], but it also puts a newline
972    /// character at the end.
973    ///
974    /// This will only work if scrolling is enabled in the plane.
975    ///
976    /// *(No equivalent C style function)*
977    pub fn putstrln(&mut self, string: &str) -> NcResult<u32> {
978        let mut cols = self.putstr(string)?;
979        cols += self.putstr("\n")?;
980        Ok(cols)
981    }
982
983    /// Prints a new line character.
984    ///
985    /// This will only work if scrolling is enabled in the plane.
986    ///
987    /// *(No equivalent C style function)*
988    pub fn putln(&mut self) -> NcResult<u32> {
989        let cols = self.putstr("\n")?;
990        Ok(cols)
991    }
992
993    /// Writes a string to the current location, retaining the previous style.
994    ///
995    /// Advances the cursor by some positive number of columns (though not
996    /// beyond the end of the plane); this number is returned on success.
997    ///
998    /// On error, a non-positive number is returned, indicating the number of
999    /// columns which were written before the error.
1000    ///
1001    /// If a glyph can not fit in the current line, it is an error, unless
1002    /// scrolling is enabled.
1003    ///
1004    /// *C style function: [ncplane_putstr_stained()][c_api::ncplane_putstr_stained].*
1005    pub fn putstr_stained(&mut self, string: &str) -> NcResult<u32> {
1006        let res = c_api::ncplane_putstr_stained(self, string);
1007        error![
1008            res,
1009            &format!("NcPlane.putstr_stained({:?})", string),
1010            res as u32
1011        ]
1012    }
1013
1014    /// Writes a string to the provided location, using the current style
1015    /// and [`NcAlign`]ed on *x*.
1016    ///
1017    /// Advances the cursor by some positive number of columns (though not
1018    /// beyond the end of the plane); this number is returned on success.
1019    ///
1020    /// On error, a non-positive number is returned, indicating the number of
1021    /// columns which were written before the error.
1022    ///
1023    /// If a glyph can not fit in the current line, it is an error, unless
1024    /// scrolling is enabled.
1025    ///
1026    /// *C style function: [ncplane_putstr_aligned()][c_api::ncplane_putstr_aligned].*
1027    pub fn putstr_aligned(
1028        &mut self,
1029        y: Option<u32>,
1030        align: impl Into<NcAlign>,
1031        string: &str,
1032    ) -> NcResult<u32> {
1033        let align = align.into();
1034        let res = c_api::ncplane_putstr_aligned(self, y, align, string);
1035        error![
1036            res,
1037            &format!("NcPlane.putstr_aligned({:?}, {}, {:?})", y, align, string),
1038            res as u32
1039        ]
1040    }
1041
1042    /// Writes a string to the provided location, using the current style.
1043    ///
1044    /// Advances the cursor by some positive number of columns (though not
1045    /// beyond the end of the plane); this number is returned on success.
1046    ///
1047    /// On error, a non-positive number is returned, indicating the number of
1048    /// columns which were written before the error.
1049    ///
1050    /// If a glyph can not fit in the current line, it is an error, unless
1051    /// scrolling is enabled.
1052    ///
1053    /// *C style function: [ncplane_putstr_yx()][c_api::ncplane_putstr_yx].*
1054    pub fn putstr_yx(&mut self, y: Option<u32>, x: Option<u32>, string: &str) -> NcResult<u32> {
1055        let res = c_api::ncplane_putstr_yx(self, y, x, string);
1056        error![
1057            res,
1058            &format!("NcPlane.putstr_yx({:?}, {:?}, {:?})", y, x, string),
1059            res as u32
1060        ]
1061    }
1062
1063    /// Writes a string to the provided location, [`NcAlign`]ed on *x*
1064    /// and retaining the previous style.
1065    ///
1066    /// Advances the cursor by some positive number of columns (though not
1067    /// beyond the end of the plane); this number is returned on success.
1068    ///
1069    /// On error, a non-positive number is returned, indicating the number of
1070    /// columns which were written before the error.
1071    ///
1072    /// If a glyph can not fit in the current line, it is an error, unless
1073    /// scrolling is enabled.
1074    ///
1075    /// *(No equivalent C style function)*
1076    pub fn putstr_aligned_stained(
1077        &mut self,
1078        y: Option<u32>,
1079        align: impl Into<NcAlign>,
1080        string: &str,
1081    ) -> NcResult<u32> {
1082        let align = align.into();
1083        let width = string.chars().count() as u32;
1084        let xpos = self.halign(align, width)?;
1085        let new_y = if let Some(y) = y { y } else { self.cursor_y() };
1086        self.cursor_move_yx(new_y, xpos)?;
1087        let res = c_api::ncplane_putstr_stained(self, string);
1088        error![
1089            res,
1090            &format!(
1091                "NcPlane.putstr_aligned_stained({}, {}, {:?})",
1092                new_y, align, string
1093            ),
1094            res as u32
1095        ]
1096    }
1097
1098    /// Writes a string to the provided location, while retaining the previous
1099    /// style.
1100    ///
1101    /// Advances the cursor by some positive number of columns (though not
1102    /// beyond the end of the plane); this number is returned on success.
1103    ///
1104    /// On error, a non-positive number is returned, indicating the number of
1105    /// columns which were written before the error.
1106    ///
1107    /// If a glyph can not fit in the current line, it is an error, unless
1108    /// scrolling is enabled.
1109    ///
1110    /// *(No equivalent C style function)*
1111    pub fn putstr_yx_stained(&mut self, y: u32, x: u32, string: &str) -> NcResult<u32> {
1112        self.cursor_move_yx(y, x)?;
1113        let res = c_api::ncplane_putstr_stained(self, string);
1114        error![
1115            res,
1116            &format!("NcPlane.putstr_yx_stained({}, {}, {:?})", y, x, string),
1117            res as u32
1118        ]
1119    }
1120
1121    /// Writes a string to the current location, using the current style,
1122    /// and no more than `num_bytes` bytes will be written.
1123    ///
1124    /// Advances the cursor by some positive number of columns (though not
1125    /// beyond the end of the plane), and this number is returned on success.
1126    ///
1127    /// On error, a non-positive number is returned, indicating the number of
1128    /// columns which were written before the error.
1129    ///
1130    /// If a glyph can not fit in the current line, it is an error, unless
1131    /// scrolling is enabled.
1132    ///
1133    /// *C style function: [ncplane_putnstr()][c_api::ncplane_putnstr].*
1134    #[inline]
1135    pub fn putnstr(&mut self, num_bytes: usize, string: &str) -> NcResult<u32> {
1136        let res = c_api::ncplane_putnstr(self, num_bytes, string);
1137        error![
1138            res,
1139            &format!("NcPlane.puntstr({}, {:?})", num_bytes, string),
1140            res as u32
1141        ]
1142    }
1143
1144    /// Writes a string to the provided location, using the current style,
1145    /// [`NcAlign`]ed on *x*, and no more than `num_bytes` bytes will be written.
1146    ///
1147    /// Advances the cursor by some positive number of columns (though not
1148    /// beyond the end of the plane), and this number is returned on success.
1149    ///
1150    /// On error, a non-positive number is returned, indicating the number of
1151    /// columns which were written before the error.
1152    ///
1153    /// If a glyph can not fit in the current line, it is an error, unless
1154    /// scrolling is enabled.
1155    ///
1156    /// *C style function: [ncplane_putnstr_aligned()][c_api::ncplane_putnstr_aligned].*
1157    pub fn putnstr_aligned(
1158        &mut self,
1159        y: Option<u32>,
1160        align: impl Into<NcAlign>,
1161        num_bytes: usize,
1162        string: &str,
1163    ) -> NcResult<u32> {
1164        let align = align.into();
1165        let cs = cstring![string];
1166        let new_y = if let Some(y) = y { y as i32 } else { self.cursor_y() as i32 };
1167        let res = unsafe {
1168            c_api::ncplane_putnstr_aligned(self, new_y, align.into(), num_bytes, cs.as_ptr())
1169        };
1170        error![
1171            res,
1172            &format!(
1173                "NcPlane.putnstr_aligned({}, {}, {}, {:?})",
1174                new_y, align, num_bytes, string
1175            ),
1176            res as u32
1177        ]
1178    }
1179
1180    /// Writes a string to the provided location, using the current style,
1181    /// and no more than `num_bytes` bytes will be written.
1182    ///
1183    /// Advances the cursor by some positive number of columns (though not
1184    /// beyond the end of the plane); this number is returned on success.
1185    ///
1186    /// On error, a non-positive number is returned, indicating the number of
1187    /// columns which were written before the error.
1188    ///
1189    /// If a glyph can not fit in the current line, it is an error, unless
1190    /// scrolling is enabled.
1191    ///
1192    /// *C style function: [ncplane_putnstr_yx()][c_api::ncplane_putnstr_yx].*
1193    pub fn putnstr_yx(
1194        &mut self,
1195        y: Option<u32>,
1196        x: Option<u32>,
1197        num_bytes: usize,
1198        string: &str,
1199    ) -> NcResult<u32> {
1200        let res = c_api::ncplane_putnstr_yx(self, y, x, num_bytes, string);
1201        error![
1202            res,
1203            &format!(
1204                "NcPlane.putnstr_yx({:?}, {:?}, {}, {:?})",
1205                y, x, num_bytes, string
1206            ),
1207            res as u32
1208        ]
1209    }
1210
1211    /// Considers the glyph at `y`,`x` coordinates as the fill target,
1212    /// and copies `cell` to it and to all cardinally-connected cells.
1213    ///
1214    /// Returns the number of cells polyfilled.
1215    ///
1216    /// An invalid initial `y`, `x` is an error.
1217    ///
1218    /// *C style function: [ncplane_putnstr_yx()][c_api::ncplane_putnstr_yx].*
1219    pub fn polyfill_yx(&mut self, y: u32, x: u32, cell: &NcCell) -> NcResult<usize> {
1220        let res = unsafe { c_api::ncplane_polyfill_yx(self, y as i32, x as i32, cell) };
1221        error![
1222            res,
1223            &format!("NcPlane.polyfill_yx({}, {}, {:?})", y, x, cell),
1224            res as usize
1225        ]
1226    }
1227}
1228
1229// -----------------------------------------------------------------------------
1230/// ## NcPlane methods: `NcPlane` & `Nc`
1231impl NcPlane {
1232    /// Duplicates this `NcPlane`.
1233    ///
1234    /// The new NcPlane will have the same geometry, the same rendering state,
1235    /// and all the same duplicated content.
1236    ///
1237    /// The new plane will be immediately above the old one on the z axis,
1238    /// and will be bound to the same parent. Bound planes are not duplicated;
1239    /// the new plane is bound to the current parent, but has no bound planes.
1240    ///
1241    /// *C style function: [ncplane_dup()][c_api::ncplane_dup].*
1242    //
1243    // TODO: deal with the opaque field that is stored in NcPlaneOptions.userptr
1244    //
1245    // SAFETY: it's a new NcPlane, not a new one
1246    #[allow(clippy::mut_from_ref)]
1247    pub fn dup(&self) -> &mut NcPlane {
1248        unsafe { &mut *c_api::ncplane_dup(self, null_mut()) }
1249    }
1250
1251    /// Returns the topmost `NcPlane` of the current pile.
1252    ///
1253    /// # Safety
1254    /// You must be careful not to end up with multiple exclusive references
1255    /// to the plane.
1256    ///
1257    /// *C style function: [ncpile_top()][c_api::ncpile_top].*
1258    pub unsafe fn top(&mut self) -> &mut NcPlane {
1259        &mut *c_api::ncpile_top(self)
1260    }
1261
1262    /// Returns the bottommost `NcPlane` of the current pile.
1263    ///
1264    /// # Safety
1265    /// You must be careful not to end up with multiple exclusive references
1266    /// to the plane.
1267    ///
1268    /// *C style function: [ncpile_bottom()][c_api::ncpile_bottom].*
1269    pub unsafe fn bottom<'a>(&mut self) -> &'a mut NcPlane {
1270        &mut *c_api::ncpile_bottom(self)
1271    }
1272
1273    /// Relocates this `NcPlane` at the bottom of the z-buffer.
1274    ///
1275    /// *C style function: [ncplane_move_bottom()][c_api::ncplane_move_bottom].*
1276    pub fn move_bottom(&mut self) {
1277        c_api::ncplane_move_bottom(self);
1278    }
1279
1280    /// Relocates this `NcPlane` at the top of the z-buffer.
1281    ///
1282    /// *C style function: [ncplane_move_top()][c_api::ncplane_move_top].*
1283    pub fn move_top(&mut self) {
1284        c_api::ncplane_move_top(self);
1285    }
1286
1287    /// Moves this `NcPlane` relative to the standard plane, or the plane to
1288    /// which it is bound.
1289    ///
1290    /// It is an error to attempt to move the standard plane.
1291    ///
1292    /// *C style function: [ncplane_move_yx()][c_api::ncplane_move_yx].*
1293    pub fn move_yx(&mut self, y: i32, x: i32) -> NcResult<()> {
1294        error![
1295            unsafe { c_api::ncplane_move_yx(self, y, x) },
1296            &format!("NcPlane.move_yx({}, {})", y, x)
1297        ]
1298    }
1299
1300    /// Moves this `NcPlane` relative to its current location.
1301    ///
1302    /// Negative values move up and left, respectively.
1303    /// Pass 0 to hold an axis constant.
1304    ///
1305    /// It is an error to attempt to move the standard plane.
1306    ///
1307    /// *C style function: [ncplane_moverel()][c_api::ncplane_moverel].*
1308    pub fn move_rel(&mut self, rows: i32, cols: i32) -> NcResult<()> {
1309        error![
1310            c_api::ncplane_moverel(self, rows, cols),
1311            &format!("NcPlane.move_rel({}, {})", rows, cols)
1312        ]
1313    }
1314
1315    /// Returns the `NcPlane` above this one, or None if already at the top.
1316    ///
1317    /// *C style function: [ncplane_above()][c_api::ncplane_above].*
1318    pub fn above(&mut self) -> Option<&mut NcPlane> {
1319        let ptr = unsafe { c_api::ncplane_above(self) };
1320        if ptr.is_null() {
1321            None
1322        } else {
1323            Some(unsafe { &mut *ptr })
1324        }
1325    }
1326
1327    /// Returns the `NcPlane` below this one, or None if already at the bottom.
1328    ///
1329    /// *C style function: [ncplane_below()][c_api::ncplane_below].*
1330    pub fn below(&mut self) -> Option<&mut NcPlane> {
1331        let ptr = unsafe { c_api::ncplane_below(self) };
1332        if ptr.is_null() {
1333            None
1334        } else {
1335            Some(unsafe { &mut *ptr })
1336        }
1337    }
1338
1339    /// Relocates this `NcPlane` above the `above` NcPlane, in the z-buffer.
1340    ///
1341    /// Returns an error if the current plane is already in the desired location.
1342    /// Both planes must not be the same.
1343    ///
1344    /// *C style function: [ncplane_move_above()][c_api::ncplane_move_above].*
1345    pub fn move_above(&mut self, above: &mut NcPlane) -> NcResult<()> {
1346        error![
1347            unsafe { c_api::ncplane_move_above(self, above) },
1348            "NcPlane.move_above()"
1349        ]
1350    }
1351
1352    /// Relocates this `NcPlane` below the `below` NcPlane, in the z-buffer.
1353    ///
1354    /// Returns an error the current plane is already in the desired location.
1355    /// Both planes must not be the same.
1356    ///
1357    /// *C style function: [ncplane_move_below()][c_api::ncplane_move_below].*
1358    pub fn move_below(&mut self, below: &mut NcPlane) -> NcResult<()> {
1359        error![
1360            unsafe { c_api::ncplane_move_below(self, below) },
1361            "NcPlane.move_below()"
1362        ]
1363    }
1364
1365    /// Splices this plane and its bound planes out of the z-buffer,
1366    /// and reinserts them at the bottom.
1367    ///
1368    /// Relative order will be maintained between the reinserted planes.
1369    ///
1370    /// For a plane E bound to C, with z-ordering A B C D E, moving the C family
1371    /// to the bottom results in A B D C E.
1372    ///
1373    /// *C style function: [ncplane_move_family_bottom()][c_api::ncplane_move_family_bottom].*
1374    pub fn move_family_bottom(&mut self) {
1375        c_api::ncplane_move_family_bottom(self)
1376    }
1377
1378    /// Splices this plane and its bound planes out of the z-buffer,
1379    /// and reinserts them at the top.
1380    ///
1381    /// Relative order will be maintained between the reinserted planes.
1382    ///
1383    /// For a plane E bound to C, with z-ordering A B C D E, moving the C family
1384    /// to the top results in C E A B D.
1385    ///
1386    /// *C style function: [ncplane_move_family_top()][c_api::ncplane_move_family_top].*
1387    pub fn move_family_top(&mut self) {
1388        c_api::ncplane_move_family_top(self)
1389    }
1390
1391    /// Splices this plane and its bound planes out of the z-buffer,
1392    /// and reinserts them above the `above` plane.
1393    ///
1394    /// Relative order will be maintained between the reinserted planes.
1395    ///
1396    /// For a plane E bound to C, with z-ordering A B C D E, moving the C family
1397    /// to the top results in C E A B D.
1398    ///
1399    /// *C style function: [ncplane_move_family_below()][c_api::ncplane_move_family_below].*
1400    pub fn move_family_above(&mut self, above: &mut NcPlane) -> NcResult<()> {
1401        error![
1402            unsafe { c_api::ncplane_move_family_above(self, above) },
1403            "NcPlane.move_family_above()"
1404        ]
1405    }
1406
1407    /// Splices this plane and its bound planes out of the z-buffer,
1408    /// and reinserts them below the `below` plane.
1409    ///
1410    /// Relative order will be maintained between the reinserted planes.
1411    ///
1412    /// For a plane E bound to C, with z-ordering A B C D E, moving the C family
1413    /// to the bottom results in A B D C E.
1414    ///
1415    /// *C style function: [ncplane_move_family_below()][c_api::ncplane_move_family_below].*
1416    pub fn move_family_below(&mut self, below: &mut NcPlane) -> NcResult<()> {
1417        error![
1418            unsafe { c_api::ncplane_move_family_below(self, below) },
1419            "NcPlane.move_family_below()"
1420        ]
1421    }
1422
1423    /// Merges the `NcPlane` `source` down onto the current `NcPlane` (`self`).
1424    ///
1425    /// This is most rigorously defined as "write to `self` the frame that would
1426    /// be rendered were the entire stack made up only of the specified subregion
1427    /// of `source` and, below it, the subregion of `self` having the specified
1428    /// origin.
1429    ///
1430    /// Use `None` for either or all of `beg_src_y` and `beg_src_x` in order to
1431    /// use the current cursor position along that axis.
1432    ///
1433    /// Use `None` for either or both of `len_y` and `len_x` in order to
1434    /// go through the boundary of the plane in that axis (same as `0`).
1435    ///
1436    /// Merging is independent of the position of both planes on the z-axis.
1437    ///
1438    /// It is an error to define a subregion that is not entirely contained
1439    /// within `source`.
1440    ///
1441    /// It is an error to define a target origin such that the projected
1442    /// subregion is not entirely contained within `self`.
1443    ///
1444    /// Behavior is undefined if both planes are equivalent.
1445    ///
1446    /// `self` is modified, but `source` remains unchanged.
1447    ///
1448    /// Neither `source` nor `self` may have sprixels.
1449    ///
1450    /// *C style function: [ncplane_mergedown()][c_api::ncplane_mergedown].*
1451    pub fn mergedown(
1452        &mut self,
1453        source: &mut NcPlane,
1454        beg_src_y: Option<u32>,
1455        beg_src_x: Option<u32>,
1456        len_y: Option<u32>,
1457        len_x: Option<u32>,
1458        dst_y: Option<u32>,
1459        dst_x: Option<u32>,
1460    ) -> NcResult<()> {
1461        error![
1462            unsafe {
1463                c_api::ncplane_mergedown(
1464                    source,
1465                    self,
1466                    beg_src_y.unwrap_or(u32::MAX) as i32, // -1_i32
1467                    beg_src_x.unwrap_or(u32::MAX) as i32, // "
1468                    len_y.unwrap_or(0),
1469                    len_x.unwrap_or(0),
1470                    dst_y.unwrap_or(u32::MAX) as i32, // -1_i32
1471                    dst_x.unwrap_or(u32::MAX) as i32, // "
1472                )
1473            },
1474            &format!(
1475                "NcPlane.mergedown(NcPlane, {:?}, {:?}, {:?}, {:?}, {:?}, {:?})",
1476                beg_src_y, beg_src_x, len_y, len_x, dst_y, dst_x
1477            )
1478        ]
1479    }
1480
1481    /// Merges `source` down onto this `NcPlane`.
1482    ///
1483    /// If `source` does not intersect, this plane will not be changed,
1484    /// but it is not an error.
1485    ///
1486    /// See [`mergedown`][NcPlane#method.mergedown]
1487    /// for more information.
1488    ///
1489    /// *C style function: [ncplane_mergedown_simple()][c_api::ncplane_mergedown_simple].*
1490    //
1491    // TODO: maybe create a reversed method, and/or an associated function,
1492    // for `mergedown` too.
1493    pub fn mergedown_simple(&mut self, source: &mut NcPlane) -> NcResult<()> {
1494        error![
1495            unsafe { c_api::ncplane_mergedown_simple(source, self) },
1496            "NcPlane.mergedown_simple(NcPlane)"
1497        ]
1498    }
1499
1500    /// Gets the parent to which this `NcPlane` is bound, if any.
1501    ///
1502    /// # Safety
1503    /// You must be careful not to end up with multiple exclusive references
1504    /// to the same `NcPlane`, or with one exclusive reference and one
1505    /// or more shared references.
1506    ///
1507    /// *C style function: [ncplane_parent()][c_api::ncplane_parent].*
1508    //
1509    // CHECK what happens when it's bound to itself.
1510    pub unsafe fn parent(&mut self) -> NcResult<&mut NcPlane> {
1511        error_ref_mut![c_api::ncplane_parent(self), "NcPlane.parent()"]
1512    }
1513
1514    /// Gets the parent to which this `NcPlane` is bound, if any.
1515    ///
1516    /// # Safety
1517    /// You must be careful not to end up with multiple exclusive references
1518    /// to the same `NcPlane`, or with one exclusive reference and one
1519    /// or more shared references.
1520    ///
1521    /// *C style function: [ncplane_parent_const()][c_api::ncplane_parent_const].*
1522    //
1523    // CHECK what happens when it's bound to itself.
1524    pub unsafe fn parent_const(&self) -> NcResult<&NcPlane> {
1525        error_ref![c_api::ncplane_parent_const(self), "NcPlane.parent_const()"]
1526    }
1527
1528    /// Unbounds this `NcPlane` from its parent, makes it a bound child of
1529    /// 'newparent', and returns itself.
1530    ///
1531    /// Any planes bound to this `NcPlane` are reparented to the previous parent.
1532    ///
1533    /// If this `NcPlane` is equal to `newparent`, then becomes the root of a new
1534    /// pile, unless it is already the root of a pile, in which case this is a
1535    /// no-op.
1536    ///
1537    /// The standard plane cannot be reparented.
1538    ///
1539    /// *C style function: [ncplane_reparent()][c_api::ncplane_reparent].*
1540    // CHECK: if it's necessary to return the plane.
1541    pub fn reparent<'a>(&mut self, newparent: &'a mut NcPlane) -> NcResult<&'a mut NcPlane> {
1542        error_ref_mut![
1543            unsafe { c_api::ncplane_reparent(self, newparent) },
1544            "NcPlane.reparent(NcPlane)"
1545        ]
1546    }
1547
1548    /// Like [`reparent`][NcPlane#method.reparent], except any bound
1549    /// planes comes along with this `NcPlane` to its new destination.
1550    ///
1551    /// Their z-order is maintained.
1552    ///
1553    /// *C style function: [ncplane_reparent_family()][c_api::ncplane_reparent_family].*
1554    //
1555    // CHECK: if it's necessary to return the plane.
1556    // CHECK: If 'newparent' is an ancestor, NULL is returned & no changes're made.
1557    pub fn reparent_family<'a>(&mut self, newparent: &'a mut NcPlane) -> NcResult<&'a mut NcPlane> {
1558        error_ref_mut![
1559            unsafe { c_api::ncplane_reparent_family(self, newparent) },
1560            "NcPlane.reparent_family(NcPlane)"
1561        ]
1562    }
1563
1564    /// Makes the physical screen match the last rendered frame from the pile of
1565    /// which this `NcPlane` is a part.
1566    ///
1567    /// This is a blocking call. Don't call this before the pile has been
1568    /// rendered (doing so will likely result in a blank screen).
1569    ///
1570    /// *C style function: [ncpile_rasterize()][c_api::ncpile_rasterize].*
1571    pub fn rasterize(&mut self) -> NcResult<()> {
1572        error![
1573            unsafe { c_api::ncpile_rasterize(self) },
1574            "NcPlane.rasterize()"
1575        ]
1576    }
1577
1578    /// Renders the pile of which this `NcPlane` is a part.
1579    ///
1580    /// Rendering this pile again will blow away the render.
1581    /// To actually write out the render, call ncpile_rasterize().
1582    ///
1583    /// *C style function: [ncpile_render()][c_api::ncpile_render].*
1584    pub fn render(&mut self) -> NcResult<()> {
1585        error![unsafe { c_api::ncpile_render(self) }, "NcPlane.render()"]
1586    }
1587
1588    /// Renders and rasterizes the pile of which this `NcPlane` is a part.
1589    ///
1590    /// *(No equivalent C style function)*
1591    pub fn render_raster(&mut self) -> NcResult<()> {
1592        self.render()?;
1593        self.rasterize()?;
1594        Ok(())
1595    }
1596
1597    /// Performs the rendering and rasterization portion of
1598    /// [`render`][NcPlane#method.render] and [`rasterize`][NcPlane#method.rasterize]
1599    /// but does not write the resulting buffer out to the terminal.
1600    ///
1601    /// Using this function, the user can control the writeout process.
1602    /// The returned buffer must be freed by the caller.
1603    ///
1604    /// *C style function: [ncpile_render_to_buffer()][c_api::ncpile_render_to_buffer].*
1605    // CHECK this works
1606    pub fn render_to_buffer(&mut self, buffer: &mut Vec<u8>) -> NcResult<()> {
1607        let len = buffer.len() as u32;
1608        let mut buf = buffer.as_mut_ptr() as *mut c_char;
1609
1610        error![
1611            unsafe { c_api::ncpile_render_to_buffer(self, &mut buf, &mut len.try_into().unwrap()) },
1612            &format!["NcPlane.render_to_buffer(buffer, {})", len]
1613        ]
1614    }
1615
1616    /// Writes the last rendered frame, in its entirety, to `fp`.
1617    ///
1618    /// If a frame has not yet been rendered, nothing will be written.
1619    ///
1620    /// *C style function: [ncpile_render_to_file()][c_api::ncpile_render_to_file].*
1621    #[cfg(feature = "std")]
1622    #[cfg_attr(feature = "nightly", doc(cfg(feature = "std")))]
1623    pub fn render_to_file(&mut self, fp: &mut NcFile) -> NcResult<()> {
1624        error![unsafe { c_api::ncpile_render_to_file(self, fp.as_nc_ptr()) }]
1625    }
1626    /// Gets a mutable reference to the [`Nc`] context of this `NcPlane`.
1627    ///
1628    /// # Safety
1629    /// You have now multiple exclusive references to the same notcurses context, congrats!
1630    ///
1631    /// *C style function: [ncplane_notcurses()][c_api::ncplane_notcurses].*
1632    pub unsafe fn notcurses<'a>(&self) -> NcResult<&'a mut Nc> {
1633        error_ref_mut![c_api::ncplane_notcurses(self), "NcPlane.notcurses()"]
1634    }
1635
1636    /// Gets an immutable reference to the [`Nc`] context of this `NcPlane`.
1637    ///
1638    /// # Safety
1639    /// You have now both exclusive and shared references to the same notcurses context, congrats!
1640    ///
1641    /// *C style function: [ncplane_notcurses_const()][c_api::ncplane_notcurses_const].*
1642    pub unsafe fn notcurses_const<'a>(&self) -> NcResult<&'a Nc> {
1643        error_ref![c_api::ncplane_notcurses_const(self), "NcPlane.notcurses()"]
1644    }
1645}
1646
1647// -----------------------------------------------------------------------------
1648/// ## NcPlane methods: cursor
1649impl NcPlane {
1650    /// Moves the cursor to 0, 0.
1651    ///
1652    /// *C style function: [ncplane_home()][c_api::ncplane_home].*
1653    pub fn cursor_home(&mut self) {
1654        unsafe {
1655            c_api::ncplane_home(self);
1656        }
1657    }
1658
1659    /// Returns the current position of the cursor within this `NcPlane`.
1660    ///
1661    /// *C style function: [ncplane_cursor_yx()][c_api::ncplane_cursor_yx].*
1662    //
1663    // NOTE: y and/or x may be NULL.
1664    // check for null and return NcResult
1665    pub fn cursor_yx(&self) -> (u32, u32) {
1666        let (mut y, mut x) = (0, 0);
1667        unsafe { c_api::ncplane_cursor_yx(self, &mut y, &mut x) };
1668        (y, x)
1669    }
1670
1671    /// Returns the current row of the cursor within this `NcPlane`.
1672    ///
1673    /// *C style function: [ncplane_cursor_y()][c_api::ncplane_cursor_y].*
1674    pub fn cursor_y(&self) -> u32 {
1675        c_api::ncplane_cursor_y(self)
1676    }
1677
1678    /// Returns the current column of the cursor within this `NcPlane`.
1679    ///
1680    /// *C style function: [ncplane_cursor_x()][c_api::ncplane_cursor_x].*
1681    pub fn cursor_x(&self) -> u32 {
1682        c_api::ncplane_cursor_x(self)
1683    }
1684
1685    /// Moves the cursor to the specified position within this `NcPlane`.
1686    ///
1687    /// The cursor doesn't need to be visible.
1688    ///
1689    /// Parameters exceeding the plane's dimensions will result in an error,
1690    /// and the cursor position will remain unchanged.
1691    ///
1692    /// *C style function: [ncplane_cursor_move_yx()][c_api::ncplane_cursor_move_yx].*
1693    pub fn cursor_move_yx(&mut self, y: u32, x: u32) -> NcResult<()> {
1694        error![
1695            unsafe { c_api::ncplane_cursor_move_yx(self, y as i32, x as i32) },
1696            &format!("NcPlane.move_yx({}, {})", y, x)
1697        ]
1698    }
1699
1700    /// Moves the cursor to the specified row within this `NcPlane`.
1701    ///
1702    /// *(No equivalent C style function)*
1703    pub fn cursor_move_y(&mut self, y: u32) -> NcResult<()> {
1704        let x = self.cursor_x();
1705        error![
1706            unsafe { c_api::ncplane_cursor_move_yx(self, y as i32, x as i32) },
1707            &format!("NcPlane.move_y({})", y)
1708        ]
1709    }
1710
1711    /// Moves the cursor to the specified column within this `NcPlane`.
1712    ///
1713    /// *(No equivalent C style function)*
1714    pub fn cursor_move_x(&mut self, x: u32) -> NcResult<()> {
1715        let y = self.cursor_y();
1716        error![
1717            unsafe { c_api::ncplane_cursor_move_yx(self, y as i32, x as i32) },
1718            &format!("NcPlane.move_x({})", x)
1719        ]
1720    }
1721
1722    /// Moves the cursor the number of rows specified (forward or backwards).
1723    ///
1724    /// It will error if the target row exceeds the plane dimensions.
1725    ///
1726    /// *(No equivalent C style function)*
1727    pub fn cursor_move_rows(&mut self, rows: i32) -> NcResult<()> {
1728        let (y, x) = self.cursor_yx();
1729        self.cursor_move_yx((y as i32 + rows) as u32, x)
1730    }
1731
1732    /// Moves the cursor the number of columns specified (forward or backwards).
1733    ///
1734    /// It will error if the target column exceeds the plane dimensions.
1735    ///
1736    /// *(No equivalent C style function)*
1737    pub fn cursor_move_cols(&mut self, cols: i32) -> NcResult<()> {
1738        let (y, x) = self.cursor_yx();
1739        self.cursor_move_yx(y, (x as i32 + cols) as u32)
1740    }
1741
1742    /// Moves the cursor relatively, the number of rows and columns specified
1743    /// (forward or backwards).
1744    ///
1745    /// It will error if the target row or column exceeds the plane dimensions.
1746    ///
1747    /// *C style function: [ncplane_cursor_move_rel()][c_api::ncplane_cursor_move_rel].*
1748    pub fn cursor_move_rel(&mut self, rows: i32, cols: i32) -> NcResult<()> {
1749        self.cursor_move_rows(rows)?;
1750        self.cursor_move_cols(cols)?;
1751        Ok(())
1752    }
1753}
1754
1755// -----------------------------------------------------------------------------
1756/// ## NcPlane methods: size, position & alignment
1757impl NcPlane {
1758    /// Returns the column at which `numcols` columns ought start in order to be
1759    /// aligned according to `align` within this plane.
1760    ///
1761    /// Returns `-`[NCRESULT_MAX][c_api::NCRESULT_MAX] if
1762    /// [`NcAlign::Unaligned`].
1763    ///
1764    /// *C style function: [ncplane_halign()][c_api::ncplane_halign].*
1765    #[inline]
1766    pub fn halign(&self, align: impl Into<NcAlign>, numcols: u32) -> NcResult<u32> {
1767        let align = align.into();
1768        let res = c_api::ncplane_halign(self, align, numcols);
1769        error![
1770            res,
1771            &format!("NcPlane.halign({:?}, {})", align, numcols),
1772            res as u32
1773        ]
1774    }
1775
1776    /// Returns the row at which `numrows` rows ought start in order to be
1777    /// aligned according to `align` within this plane.
1778    ///
1779    /// Returns `-`[NCRESULT_MAX][c_api::NCRESULT_MAX] if
1780    /// [`NcAlign::Unaligned`].
1781    ///
1782    /// *C style function: [ncplane_valign()][c_api::ncplane_valign].*
1783    #[inline]
1784    pub fn valign(&self, align: impl Into<NcAlign>, numrows: u32) -> NcResult<u32> {
1785        let align = align.into();
1786        let res = c_api::ncplane_valign(self, align, numrows);
1787        error![
1788            res,
1789            &format!("NcPlane.valign({:?}, {})", align, numrows),
1790            res as u32
1791        ]
1792    }
1793
1794    /// Finds the center coordinate of a plane.
1795    ///
1796    /// In the case of an even number of rows/columns the top/left is preferred
1797    /// (in such a case, there will be one more cell to the bottom/right
1798    /// of the center than the top/left).
1799    /// The center is then modified relative to the plane's origin.
1800    ///
1801    /// *C style function: [ncplane_center_abs()][c_api::ncplane_center_abs].*
1802    pub fn center_abs(&self) -> (u32, u32) {
1803        let (mut y, mut x) = (0, 0);
1804        unsafe {
1805            c_api::ncplane_center_abs(self, &mut y, &mut x);
1806        }
1807        (y as u32, x as u32)
1808    }
1809
1810    /// Returns the dimensions of this `NcPlane`.
1811    ///
1812    /// *C style function: [ncplane_dim_yx()][c_api::ncplane_dim_yx].*
1813    pub fn dim_yx(&self) -> (u32, u32) {
1814        let (mut y, mut x) = (0, 0);
1815        unsafe { c_api::ncplane_dim_yx(self, &mut y, &mut x) };
1816        (y, x)
1817    }
1818
1819    /// Returns the rows of this `NcPlane`.
1820    ///
1821    /// *C style function: [ncplane_dim_y()][c_api::ncplane_dim_y].*
1822    #[inline]
1823    pub fn dim_y(&self) -> u32 {
1824        self.dim_yx().0
1825    }
1826
1827    /// Returns the columns of this `NcPlane`.
1828    ///
1829    /// *C style function: [ncplane_dim_x()][c_api::ncplane_dim_x].*
1830    #[inline]
1831    pub fn dim_x(&self) -> u32 {
1832        self.dim_yx().1
1833    }
1834
1835    #[doc(hidden)]
1836    #[deprecated = "use the `dim_y` method instead."]
1837    pub fn rows(&self) -> u32 {
1838        self.dim_yx().0
1839    }
1840
1841    #[doc(hidden)]
1842    #[deprecated = "use the `dim_x` method instead."]
1843    pub fn cols(&self) -> u32 {
1844        self.dim_yx().1
1845    }
1846
1847    /// Creates an RGBA flat array from the selected region of the plane.
1848    ///
1849    /// Begins at the plane's `beg_y`x`beg_x` coordinate (which must lie on the
1850    /// plane), continuing for `len_y`x`len_x` cells.
1851    ///
1852    /// Use `None` for either or both of `beg_y` and `beg_x` in order to
1853    /// use the current cursor position along that axis.
1854    ///
1855    /// Use `None` for either or both of `len_y` and `len_x` in order to
1856    /// go through the boundary of the plane in that axis (same as `0`).
1857    ///
1858    /// Only glyphs from the specified blitset may be present.
1859    ///
1860    /// *C style function: [ncplane_as_rgba()][c_api::ncplane_as_rgba].*
1861    pub fn as_rgba(
1862        &mut self,
1863        blitter: impl Into<NcBlitter>,
1864        beg_y: Option<u32>,
1865        beg_x: Option<u32>,
1866        len_y: Option<u32>,
1867        len_x: Option<u32>,
1868    ) -> NcResult<&mut [NcRgba]> {
1869        let blitter = blitter.into();
1870
1871        // pixel geometry
1872        let mut pxdim_y = 0;
1873        let mut pxdim_x = 0;
1874
1875        let res_array = unsafe {
1876            c_api::ncplane_as_rgba(
1877                self,
1878                blitter.into(),
1879                beg_y.unwrap_or(u32::MAX) as i32, // -1_i32
1880                beg_x.unwrap_or(u32::MAX) as i32, // "
1881                len_y.unwrap_or(0),
1882                len_x.unwrap_or(0),
1883                &mut pxdim_y,
1884                &mut pxdim_x,
1885            )
1886        };
1887
1888        error_ref_mut![
1889            res_array,
1890            &format![
1891                "NcPlane.rgba({}, {:?}, {:?}, {:?}, {:?})",
1892                blitter, beg_y, beg_x, len_y, len_x
1893            ],
1894            from_raw_parts_mut(res_array as *mut NcRgba, (pxdim_y * pxdim_x) as usize)
1895        ]
1896    }
1897
1898    /// Returns an [`NcPixelGeometry`] structure filled with pixel geometry for
1899    /// the display region, each cell, and the maximum displayable bitmap.
1900    ///
1901    /// This function calls
1902    /// [notcurses_check_pixel_support][c_api::notcurses_check_pixel_support],
1903    /// possibly leading to an interrogation of the terminal.
1904    ///
1905    /// *C style function: [ncplane_pixel_geom()][c_api::ncplane_pixel_geom].*
1906    pub fn pixel_geom(&self) -> NcPixelGeometry {
1907        let mut pxy = 0;
1908        let mut pxx = 0;
1909        let mut celldimy = 0;
1910        let mut celldimx = 0;
1911        let mut maxbmapy = 0;
1912        let mut maxbmapx = 0;
1913        unsafe {
1914            c_api::ncplane_pixel_geom(
1915                self,
1916                &mut pxy,
1917                &mut pxx,
1918                &mut celldimy,
1919                &mut celldimx,
1920                &mut maxbmapy,
1921                &mut maxbmapx,
1922            );
1923        }
1924        NcPixelGeometry {
1925            term_y: pxy,
1926            term_x: pxx,
1927            cell_y: celldimy,
1928            cell_x: celldimx,
1929            max_bitmap_y: maxbmapy,
1930            max_bitmap_x: maxbmapx,
1931        }
1932    }
1933
1934    /// Resizes this `NcPlane`.
1935    ///
1936    /// The four parameters `keep_y`, `keep_x`, `keep_len_y`, and `keep_len_x`
1937    /// defines a subset of this `NcPlane` to keep unchanged.
1938    /// This may be a section of size 0.
1939    ///
1940    /// `keep_x` and `keep_y` are relative to this `NcPlane`. They must specify a
1941    /// coordinate within the ncplane's totality. If either of `keep_len_y` or
1942    /// `keep_len_x` is non-zero, both must be non-zero.
1943    ///
1944    /// `y_off` and `x_off` are relative to `keep_y` and `keep_x`, and place the
1945    /// upper-left corner of the resized `NcPlane`.
1946    ///
1947    /// `len_y` and `len_x` are the dimensions of this `NcPlane` after resizing.
1948    /// `len_y` must be greater than or equal to `keep_len_y`,
1949    /// and `len_x` must be greater than or equal to `keeplenx`.
1950    ///
1951    /// It is an error to attempt to resize the standard plane.
1952    ///
1953    /// *C style function: [ncplane_resize()][c_api::ncplane_resize].*
1954    pub fn resize(
1955        &mut self,
1956        keep_y: u32,
1957        keep_x: u32,
1958        keep_len_y: u32,
1959        keep_len_x: u32,
1960        off_y: i32,
1961        off_x: i32,
1962        len_y: u32,
1963        len_x: u32,
1964    ) -> NcResult<()> {
1965        error![
1966            unsafe {
1967                c_api::ncplane_resize(
1968                    self,
1969                    keep_y as i32,
1970                    keep_x as i32,
1971                    keep_len_y,
1972                    keep_len_x,
1973                    off_y,
1974                    off_x,
1975                    len_y,
1976                    len_x,
1977                )
1978            },
1979            &format!(
1980                "NcPlane.resize({}, {}, {}, {}, {}, {}, {}, {})",
1981                keep_y, keep_x, keep_len_y, keep_len_x, off_y, off_x, len_y, len_x
1982            )
1983        ]
1984    }
1985
1986    /// Suitable for use as a 'resizecb' with planes created with
1987    /// [`NcPlaneFlag::Marginalized`][crate::NcPlaneFlag#associatedconstant.Marginalized].
1988    ///
1989    /// This will resize this plane against its parent, attempting to enforce
1990    /// the supplied margins.
1991    ///
1992    /// *C style function: [ncplane_resize_marginalized()][c_api::ncplane_resize_marginalized].*
1993    pub fn resize_marginalized(&mut self) -> NcResult<()> {
1994        error![
1995            unsafe { c_api::ncplane_resize_marginalized(self) },
1996            "NcPlane.resize_marginalized()"
1997        ]
1998    }
1999
2000    /// Suitable for use as a 'resizecb', this will resize the plane
2001    /// to the visual region's size. It is used for the standard plane.
2002    ///
2003    /// *C style function: [ncplane_resize_maximize()][c_api::ncplane_resize_maximize].*
2004    pub fn resize_maximize(&mut self) -> NcResult<()> {
2005        error![
2006            unsafe { c_api::ncplane_resize_maximize(self) },
2007            "NcPlane.resize_maximize()"
2008        ]
2009    }
2010
2011    /// Moves the plane such that it is entirely within its parent, if possible.
2012    /// no resizing is performed.
2013    ///
2014    /// *C style function: [ncplane_resize_placewithin()][c_api::ncplane_resize_placewithin].*
2015    pub fn resize_placewithin(&mut self) -> NcResult<()> {
2016        error![
2017            unsafe { c_api::ncplane_resize_placewithin(self) },
2018            "NcPlane.resize_placewithin()"
2019        ]
2020    }
2021
2022    /// Realigns this `NcPlane` against its parent, using the alignment specified
2023    /// at creation time.
2024    ///
2025    /// Suitable for use as an [`NcResizeCb`].
2026    ///
2027    /// *C style function: [ncplane_resize_realign()][c_api::ncplane_resize_realign].*
2028    //
2029    // TODO: suitable for use as an NcResizeCb?
2030    pub fn resize_realign(&mut self) -> NcResult<()> {
2031        error![unsafe { c_api::ncplane_resize_realign(self) }]
2032    }
2033
2034    /// Resizes this `NcPlane`, retaining what data we can (everything, unless we're
2035    /// shrinking in some dimension). Keeps the origin where it is.
2036    ///
2037    /// *C style function: [ncplane_resize_simple()][c_api::ncplane_resize_simple].*
2038    #[inline]
2039    pub fn resize_simple(&mut self, len_y: u32, len_x: u32) -> NcResult<()> {
2040        error![c_api::ncplane_resize_simple(self, len_y, len_x)]
2041    }
2042
2043    /// Returns this `NcPlane`'s current resize callback, or `None` if not set.
2044    ///
2045    /// *C style function: [ncplane_resizecb()][c_api::ncplane_resizecb].*
2046    pub fn resizecb(&self) -> Option<NcResizeCb> {
2047        unsafe { c_api::ncresizecb_to_rust(c_api::ncplane_resizecb(self)) }
2048    }
2049
2050    /// Replaces this `NcPlane`'s existing resize callback (may be `None`)
2051    ///
2052    /// The standard plane's resize callback may not be changed.
2053    ///
2054    /// *C style function: [ncplane_set_resizecb()][c_api::ncplane_set_resizecb].*
2055    pub fn set_resizecb(&mut self, resizecb: Option<NcResizeCb>) {
2056        unsafe { c_api::ncplane_set_resizecb(self, c_api::ncresizecb_to_c(resizecb)) }
2057    }
2058
2059    /// Rotate the plane π/2 radians (90°) clockwise.
2060    ///
2061    /// This cannot be performed on arbitrary planes, because glyphs cannot be
2062    /// arbitrarily rotated.
2063    ///
2064    /// The glyphs which can be rotated are limited: line-drawing characters,
2065    /// spaces, half blocks, and full blocks.
2066    ///
2067    /// The plane must have an even number of columns.
2068    ///
2069    /// Use the ncvisual rotation for a more flexible approach.
2070    ///
2071    /// *C style function: [ncplane_rotate_cw()][c_api::ncplane_rotate_cw].*
2072    pub fn rotate_cw(&mut self) -> NcResult<()> {
2073        error![unsafe { c_api::ncplane_rotate_cw(self) }]
2074    }
2075
2076    /// Rotate the plane π/2 radians (90°) counter-clockwise.
2077    ///
2078    /// See [`rotate_cw`][NcPlane#method.rotate_cw]
2079    /// for more information.
2080    ///
2081    /// *C style function: [ncplane_rotate_ccw()][c_api::ncplane_rotate_ccw].*
2082    pub fn rotate_ccw(&mut self) -> NcResult<()> {
2083        error![unsafe { c_api::ncplane_rotate_ccw(self) }]
2084    }
2085
2086    /// Maps the specified coordinates relative to the origin of this `NcPlane`,
2087    /// to the same absolute coordinates relative to the origin of `target`.
2088    ///
2089    /// *C style function: [ncplane_translate()][c_api::ncplane_translate].*
2090    pub fn translate(&self, target: &NcPlane, y: &mut i32, x: &mut i32) {
2091        unsafe { c_api::ncplane_translate(self, target, y, x) }
2092    }
2093
2094    /// Returns true if the provided absolute `y`/`x` coordinates are within
2095    /// this `NcPlane`, or false otherwise.
2096    ///
2097    /// Either way, translates the absolute coordinates relative to this `NcPlane`.
2098    ///
2099    /// *C style function: [ncplane_translate_abs()][c_api::ncplane_translate_abs].*
2100    pub fn translate_abs(&self, y: &mut i32, x: &mut i32) -> bool {
2101        unsafe { c_api::ncplane_translate_abs(self, y, x) }
2102    }
2103
2104    /// Gets the `y`, `x` origin of this `NcPlane` relative to its parent,
2105    /// or its pile, if it's a root plane.
2106    ///
2107    /// *C style function: [ncplane_yx()][c_api::ncplane_yx].*
2108    //
2109    // CHECK: negative offsets
2110    pub fn yx(&self) -> (i32, i32) {
2111        let (mut y, mut x) = (0, 0);
2112        unsafe { c_api::ncplane_yx(self, &mut y, &mut x) };
2113        (y, x)
2114    }
2115
2116    /// Gets the `y` origin of this `NcPlane` relative to its parent,
2117    /// or its pile, if it's a root plane.
2118    ///
2119    /// *C style function: [ncplane_y()][c_api::ncplane_y].*
2120    pub fn y(&self) -> i32 {
2121        unsafe { c_api::ncplane_y(self) }
2122    }
2123
2124    /// Gets the `x` origin of this `NcPlane` relative to its parent,
2125    /// or its pile, if it's a root plane.
2126    ///
2127    /// *C style function: [ncplane_x()][c_api::ncplane_x].*
2128    pub fn x(&self) -> i32 {
2129        unsafe { c_api::ncplane_x(self) }
2130    }
2131
2132    /// Gets the origin of this plane relative to its pile.
2133    ///
2134    /// *C style function: [ncplane_abs_yx()][c_api::ncplane_abs_yx].*
2135    pub fn abs_yx(&self) -> (i32, i32) {
2136        let mut y = 0;
2137        let mut x = 0;
2138        unsafe {
2139            c_api::ncplane_abs_yx(self, &mut y, &mut x);
2140        }
2141        (y, x)
2142    }
2143
2144    /// Gets the origin of this plane relative to its pile, in the y axis.
2145    ///
2146    /// *C style function: [ncplane_abs_y()][c_api::ncplane_abs_y].*
2147    pub fn abs_y(&self) -> i32 {
2148        unsafe { c_api::ncplane_abs_y(self) }
2149    }
2150
2151    /// Gets the origin of this plane relative to its pile, in the x axis.
2152    ///
2153    /// *C style function: [ncplane_abs_x()][c_api::ncplane_abs_x].*
2154    pub fn abs_x(&self) -> i32 {
2155        unsafe { c_api::ncplane_abs_x(self) }
2156    }
2157
2158    /// Returns `true` if this `NcPlane` has scrolling enabled, or `false` otherwise.
2159    ///
2160    /// *C style function: [ncplane_scrolling_p()][c_api::ncplane_scrolling_p].*
2161    pub fn scrolling_p(&self) -> bool {
2162        unsafe { c_api::ncplane_scrolling_p(self) }
2163    }
2164
2165    /// (Un)Sets the scrolling behaviour of the plane, and
2166    /// returns true if scrolling was previously enabled, of false, if disabled.
2167    ///
2168    /// All planes are created with scrolling disabled. Attempting to print past
2169    /// the end of a line will stop at the plane boundary, and indicate an error.
2170    ///
2171    /// On a plane 10 columns wide and two rows high, printing "0123456789"
2172    /// at the origin should succeed, but printing "01234567890" will by default
2173    /// fail at the eleventh character. In either case, the cursor will be left
2174    /// at location 0x10; it must be moved before further printing can take place. I
2175    ///
2176    /// See also
2177    /// `NcPlaneOptions::`[`VSCROLL`][NcPlaneOptions#associatedconstant.VSCROLL]
2178    ///
2179    /// *C style function: [ncplane_set_scrolling()][c_api::ncplane_set_scrolling].*
2180    pub fn set_scrolling(&mut self, scroll: bool) -> bool {
2181        unsafe { c_api::ncplane_set_scrolling(self, scroll.into()) }
2182    }
2183
2184    /// Sends `n` scroll events to the current plane.
2185    ///
2186    /// Returns an error if the current plane is not a scrolling plane,
2187    /// and otherwise returns the number of lines scrolled.
2188    ///
2189    /// *C style function: [ncplane_scrollup()][c_api::ncplane_scrollup].*
2190    pub fn scrollup(&mut self, n: u32) -> NcResult<u32> {
2191        let res = unsafe { c_api::ncplane_scrollup(self, n as i32) };
2192        error![res, "", res as u32]
2193    }
2194
2195    /// Scrolls the current plane until `child` is no longer hidden beneath it.
2196    ///
2197    /// Returns an error if `child` is not a child of this plane, or if this
2198    /// plane is not scrolling, or `child` is fixed.
2199    ///
2200    /// Returns the number of scrolling events otherwise (might be 0).
2201    ///
2202    /// *C style function: [ncplane_scrollup_child()][c_api::ncplane_scrollup_child].*
2203    pub fn scrollup_child(&mut self, child: &NcPlane) -> NcResult<u32> {
2204        let res = unsafe { c_api::ncplane_scrollup_child(self, child) };
2205        error![res, "", res as u32]
2206    }
2207
2208    /// Returns `true` if this `NcPlane` has autogrow enabled, or `false` otherwise.
2209    ///
2210    /// *C style function: [ncplane_autogrow_p()][c_api::ncplane_autogrow_p].*
2211    pub fn autogrow_p(&self) -> bool {
2212        unsafe { c_api::ncplane_autogrow_p(self) }
2213    }
2214
2215    /// (Un)Sets the automatic growth of the plane to accommodate output.
2216    ///
2217    /// Returns true if autogrow was previously enabled, or false otherwise.
2218    ///
2219    /// By default, planes are created with autogrow disabled.
2220    ///
2221    /// Normally, once output reaches the right boundary of a plane, it is
2222    /// impossible to place more output unless the cursor is first moved.
2223    ///
2224    /// If scrolling is enabled, the cursor will automatically move down and to
2225    /// the left in this case, but upon reaching the bottom right corner of the
2226    /// plane, it is impossible to place more output without a scrolling event.
2227    ///
2228    /// If autogrow is in play, the plane will automatically be enlarged to
2229    /// accommodate output. If scrolling is disabled, growth takes place to the
2230    /// right; it otherwise takes place at the bottom.
2231    ///
2232    /// The plane only grows in one dimension.
2233    ///
2234    /// *C style function: [ncplane_set_autogrow()][c_api::ncplane_set_autogrow].*
2235    pub fn set_autogrow(&mut self, autogrow: bool) -> bool {
2236        unsafe { c_api::ncplane_set_autogrow(self, autogrow.into()) }
2237    }
2238}
2239
2240// -----------------------------------------------------------------------------
2241/// ## NcPlane methods: boxes & perimeters
2242impl NcPlane {
2243    /// Draws a box with its upper-left corner at the current cursor position,
2244    /// and its lower-right corner at `stop_y` * `stop_x`.
2245    ///
2246    /// The 6 cells provided are used to draw the upper-left, ur, ll, and lr corners,
2247    /// then the horizontal and vertical lines.
2248    ///
2249    /// See [`NcBoxMask`] for information about the border and gradient masks,
2250    /// and the drawing of corners.
2251    ///
2252    /// If the gradient bit is not set, the style from the hline/vlline cells
2253    /// is used for the horizontal and vertical lines, respectively.
2254    ///
2255    /// If the gradient bit is set, the color is linearly interpolated between
2256    /// the two relevant corner cells.
2257    ///
2258    /// *C style function: [ncplane_box()][c_api::ncplane_box].*
2259    pub fn r#box(
2260        &mut self,
2261        ul: &NcCell,
2262        ur: &NcCell,
2263        ll: &NcCell,
2264        lr: &NcCell,
2265        hline: &NcCell,
2266        vline: &NcCell,
2267        stop_y: u32,
2268        stop_x: u32,
2269        boxmask: impl Into<NcBoxMask>,
2270    ) -> NcResult<()> {
2271        error![unsafe {
2272            c_api::ncplane_box(
2273                self,
2274                ul,
2275                ur,
2276                ll,
2277                lr,
2278                hline,
2279                vline,
2280                stop_y,
2281                stop_x,
2282                boxmask.into().0,
2283            )
2284        }]
2285    }
2286
2287    /// Draws a box with its upper-left corner at the current cursor position,
2288    /// having dimensions `len_y` * `len_x`.
2289    /// The minimum box size is 2x2, and it cannot be drawn off-screen.
2290    ///
2291    /// See the [`box`][NcPlane#method.box] method for more information.
2292    ///
2293    /// *C style function: [ncplane_box_sized()][c_api::ncplane_box_sized].*
2294    #[inline]
2295    pub fn box_sized(
2296        &mut self,
2297        ul: &NcCell,
2298        ur: &NcCell,
2299        ll: &NcCell,
2300        lr: &NcCell,
2301        hline: &NcCell,
2302        vline: &NcCell,
2303        len_y: u32,
2304        len_x: u32,
2305        boxmask: impl Into<NcBoxMask>,
2306    ) -> NcResult<()> {
2307        error![c_api::ncplane_box_sized(
2308            self,
2309            ul,
2310            ur,
2311            ll,
2312            lr,
2313            hline,
2314            vline,
2315            len_y,
2316            len_x,
2317            boxmask.into()
2318        )]
2319    }
2320
2321    /// NcPlane.[`box`][NcPlane#method.box] with ASCII characters.
2322    ///
2323    /// *C style function: [ncplane_ascii_box()][c_api::ncplane_ascii_box].*
2324    #[inline]
2325    pub fn ascii_box(
2326        &mut self,
2327        stylemask: impl Into<NcStyle>,
2328        channels: impl Into<NcChannels>,
2329        stop_y: u32,
2330        stop_x: u32,
2331        boxmask: impl Into<NcBoxMask>,
2332    ) -> NcResult<()> {
2333        error![c_api::ncplane_ascii_box(
2334            self,
2335            stylemask.into().0,
2336            channels.into().0,
2337            stop_y,
2338            stop_x,
2339            boxmask.into()
2340        )]
2341    }
2342
2343    /// NcPlane.[`box`][NcPlane#method.box] with the double box-drawing characters.
2344    ///
2345    /// *C style function: [ncplane_double_box()][c_api::ncplane_double_box].*
2346    #[inline]
2347    pub fn double_box(
2348        &mut self,
2349        stylemask: impl Into<NcStyle>,
2350        channels: impl Into<NcChannels>,
2351        stop_y: u32,
2352        stop_x: u32,
2353        boxmask: impl Into<NcBoxMask>,
2354    ) -> NcResult<()> {
2355        error![c_api::ncplane_double_box(
2356            self,
2357            stylemask.into().0,
2358            channels.into().0,
2359            stop_y,
2360            stop_x,
2361            boxmask.into()
2362        )]
2363    }
2364
2365    /// NcPlane.[`box_sized`][NcPlane#method.box_sized] with the double
2366    /// box-drawing characters.
2367    ///
2368    /// *C style function: [ncplane_double_box_sized()][c_api::ncplane_double_box_sized].*
2369    #[inline]
2370    pub fn double_box_sized(
2371        &mut self,
2372        stylemask: impl Into<NcStyle>,
2373        channels: impl Into<NcChannels>,
2374        len_y: u32,
2375        len_x: u32,
2376        boxmask: impl Into<NcBoxMask>,
2377    ) -> NcResult<()> {
2378        error![c_api::ncplane_double_box(
2379            self,
2380            stylemask.into().0,
2381            channels.into().0,
2382            len_y,
2383            len_x,
2384            boxmask.into()
2385        )]
2386    }
2387
2388    /// Draws the perimeter around this `NcPlane`.
2389    ///
2390    /// *C style function: [ncplane_perimeter()][c_api::ncplane_perimeter].*
2391    #[inline]
2392    pub fn perimeter(
2393        &mut self,
2394        ul: &NcCell,
2395        ur: &NcCell,
2396        ll: &NcCell,
2397        lr: &NcCell,
2398        hline: &NcCell,
2399        vline: &NcCell,
2400        boxmask: impl Into<NcBoxMask>,
2401    ) -> NcResult<()> {
2402        error![c_api::ncplane_perimeter(
2403            self,
2404            ul,
2405            ur,
2406            ll,
2407            lr,
2408            hline,
2409            vline,
2410            boxmask.into()
2411        )]
2412    }
2413
2414    /// `NcPlane.`[`perimeter`][NcPlane#method.perimeter] with the double box-drawing characters.
2415    ///
2416    /// *C style function: [ncplane_perimeter_double()][c_api::ncplane_perimeter_double].*
2417    #[inline]
2418    pub fn perimeter_double(
2419        &mut self,
2420        stylemask: impl Into<NcStyle>,
2421        channels: impl Into<NcChannels>,
2422        boxmask: impl Into<NcBoxMask>,
2423    ) -> NcResult<()> {
2424        error![c_api::ncplane_perimeter_double(
2425            self,
2426            stylemask.into().0,
2427            channels.into().0,
2428            boxmask.into()
2429        )]
2430    }
2431
2432    /// `NcPlane.`[`perimeter`][NcPlane#method.perimeter] with the rounded box-drawing characters.
2433    ///
2434    /// *C style function: [ncplane_perimeter_rounded()][c_api::ncplane_perimeter_rounded].*
2435    #[inline]
2436    pub fn perimeter_rounded(
2437        &mut self,
2438        stylemask: impl Into<NcStyle>,
2439        channels: impl Into<NcChannels>,
2440        boxmask: impl Into<NcBoxMask>,
2441    ) -> NcResult<()> {
2442        error![c_api::ncplane_perimeter_rounded(
2443            self,
2444            stylemask.into().0,
2445            channels.into().0,
2446            boxmask.into()
2447        )]
2448    }
2449}
2450
2451// -----------------------------------------------------------------------------
2452/// ## NcPlane methods: fading, gradients & greyscale
2453impl NcPlane {
2454    /// Fades this `NcPlane` in, over the specified time, calling 'fader' at
2455    /// each iteration.
2456    ///
2457    /// Usage:
2458    /// 1. Load this `NcPlane` with the target cells without rendering.
2459    /// 2. call this function.
2460    ///
2461    /// When it's done, the `NcPlane` will have reached the target levels,
2462    /// starting from zeroes.
2463    ///
2464    /// *C style function: [ncplane_fadein()][c_api::ncplane_fadein].*
2465    pub fn fadein(&mut self, time: &NcTime, fader: NcFadeCb) -> NcResult<()> {
2466        error![unsafe { c_api::ncplane_fadein(self, time, fader, null_mut()) }]
2467    }
2468
2469    /// Fades in through 'iter' iterations,
2470    /// where 'iter' < 'ncfadectx_iterations(nctx)'.
2471    ///
2472    /// *C style function: [ncplane_fadein_iteration()][c_api::ncplane_fadein_iteration].*
2473    pub fn fadein_iteration(&mut self, time: &NcTime, fader: NcFadeCb) -> NcResult<()> {
2474        error![unsafe { c_api::ncplane_fadein(self, time, fader, null_mut()) }]
2475    }
2476
2477    /// Fades this `NcPlane` out, over the specified time, calling 'fader' at
2478    /// each iteration.
2479    ///
2480    /// Requires a terminal which supports truecolor, or at least palette
2481    /// modification (if the terminal uses a palette, our ability to fade planes
2482    /// is limited, and affected by the complexity of the rest of the screen).
2483    ///
2484    /// *C style function: [ncplane_fadeout()][c_api::ncplane_fadeout].*
2485    pub fn fadeout(&mut self, time: &NcTime, fader: NcFadeCb) -> NcResult<()> {
2486        error![unsafe { c_api::ncplane_fadeout(self, time, fader, null_mut()) }]
2487    }
2488
2489    /// Fades out through 'iter' iterations,
2490    /// where 'iter' < 'ncfadectx_iterations(nctx)'.
2491    ///
2492    /// *C style function: [ncplane_fadeout_iteration()][c_api::ncplane_fadeout_iteration].*
2493    pub fn fadeout_iteration(&mut self, time: &NcTime, fader: NcFadeCb) -> NcResult<()> {
2494        error![unsafe { c_api::ncplane_fadeout(self, time, fader, null_mut()) }]
2495    }
2496
2497    /// Pulses this `NcPlane` in and out until the callback returns non-zero,
2498    /// relying on the callback 'fader' to initiate rendering.
2499    ///
2500    /// `time` defines the half-period (i.e. the transition from black to full
2501    /// brightness, or back again).
2502    ///
2503    /// Proper use involves preparing (but not rendering) the `NcPlane`,
2504    /// then calling this method, which will fade in from black to the
2505    /// specified colors.
2506    ///
2507    /// *C style function: [ncplane_pulse()][c_api::ncplane_pulse].*
2508    pub fn pulse(&mut self, time: &NcTime, fader: NcFadeCb) -> NcResult<()> {
2509        error![unsafe { c_api::ncplane_pulse(self, time, fader, null_mut()) }]
2510    }
2511
2512    /// Draws a gradient with its upper-left corner at the current cursor
2513    /// position, stopping at `stop_y` * `stop_x`.
2514    ///
2515    /// Returns the number of cells filled on success,
2516    /// or [`NCRESULT_ERR`][c_api::NCRESULT_ERR] on error.
2517    ///
2518    /// The glyph composed of `egc` and `stylemask` is used for all cells.
2519    /// The channels specified by `ul`, `ur`, `ll`, and `lr` are composed into
2520    /// foreground and background gradients.
2521    ///
2522    /// To do a vertical gradient, `ul` ought equal `ur` and `ll` ought equal
2523    /// `lr`. To do a horizontal gradient, `ul` ought equal `ll` and `ur` ought
2524    /// equal `ul`.
2525    ///
2526    /// To color everything the same, all four channels should be equivalent.
2527    /// The resulting alpha values are equal to incoming alpha values.
2528    ///
2529    /// Palette-indexed color is not supported.
2530    ///
2531    /// Preconditions for gradient operations (error otherwise):
2532    ///
2533    /// all: only RGB colors, unless all four channels match as default
2534    /// all: all alpha values must be the same
2535    /// 1x1: all four colors must be the same
2536    /// 1xN: both top and both bottom colors must be the same (vertical gradient)
2537    /// Nx1: both left and both right colors must be the same (horizontal gradient)
2538    ///
2539    /// *C style function: [ncplane_gradient()][c_api::ncplane_gradient].*
2540    pub fn gradient(
2541        &mut self,
2542        y: Option<u32>,
2543        x: Option<u32>,
2544        stop_y: Option<u32>,
2545        stop_x: Option<u32>,
2546        egc: &str,
2547        stylemask: impl Into<NcStyle>,
2548        ul: impl Into<NcChannels>,
2549        ur: impl Into<NcChannels>,
2550        ll: impl Into<NcChannels>,
2551        lr: impl Into<NcChannels>,
2552    ) -> NcResult<u32> {
2553        let res = c_api::ncplane_gradient(
2554            self,
2555            y,
2556            x,
2557            stop_y,
2558            stop_x,
2559            egc,
2560            stylemask.into(),
2561            ul.into().0,
2562            ur.into().0,
2563            ll.into().0,
2564            lr.into().0,
2565        );
2566        error![res, "", res as u32]
2567    }
2568
2569    /// Does a high-resolution gradient using upper blocks and synced backgrounds.
2570    ///
2571    /// This doubles the number of vertical gradations, but restricts you to
2572    /// half blocks (appearing to be full blocks).
2573    ///
2574    /// Returns the number of cells filled on success.
2575    ///
2576    /// Use `None` for either or all of `beg_y` and `beg_x` in order to
2577    /// use the current cursor position along that axis.
2578    ///
2579    /// Use `None` for either or both of `len_y` and `len_x` in order to
2580    /// go through the boundary of the plane in that axis (same as `0`).
2581    ///
2582    /// *C style function: [ncplane_gradient2x1()][c_api::ncplane_gradient2x1].*
2583    pub fn gradient2x1(
2584        &mut self,
2585        y: Option<u32>,
2586        x: Option<u32>,
2587        len_y: Option<u32>,
2588        len_x: Option<u32>,
2589        ul: impl Into<NcChannel>,
2590        ur: impl Into<NcChannel>,
2591        ll: impl Into<NcChannel>,
2592        lr: impl Into<NcChannel>,
2593    ) -> NcResult<u32> {
2594        let res = unsafe {
2595            c_api::ncplane_gradient2x1(
2596                self,
2597                y.unwrap_or(u32::MAX) as i32, // -1_i32
2598                x.unwrap_or(u32::MAX) as i32, // "
2599                len_y.unwrap_or(0),
2600                len_x.unwrap_or(0),
2601                ul.into().0,
2602                ur.into().0,
2603                ll.into().0,
2604                lr.into().0,
2605            )
2606        };
2607        error![res, "", res as u32]
2608    }
2609
2610    /// Converts this `NcPlane`'s content to greyscale.
2611    ///
2612    /// *C style function: [ncplane_greyscale()][c_api::ncplane_greyscale].*
2613    pub fn greyscale(&mut self) {
2614        unsafe {
2615            c_api::ncplane_greyscale(self);
2616        }
2617    }
2618}
2619
2620// -----------------------------------------------------------------------------
2621/// ## NcPlane methods: other
2622impl NcPlane {
2623    /// Draws a QR code at the current position on the plane.
2624    ///
2625    /// A tuple of 3 elements will be returned: `(version, max_y, max_x)`.
2626    ///
2627    /// - The QR code size is (`version` * 4 + 17) columns wide, and
2628    /// ⌈`version` * 4 + 17⌉ rows tall.
2629    /// - The properly-scaled values are returned as `max_y` and `max_x`.
2630    ///
2631    /// It is an error not to have sufficient room to draw the qrcode.
2632    ///
2633    /// *C style function: [ncplane_qrcode()][c_api::ncplane_qrcode].*
2634    pub fn qrcode(&mut self, data: &mut [u8]) -> NcResult<(u32, u32, u32)> {
2635        let (mut max_y, mut max_x) = (0, 0);
2636        let len = data.len();
2637        let data_ptr = data.as_ptr() as *const c_void;
2638        let res = unsafe { c_api::ncplane_qrcode(self, &mut max_y, &mut max_x, data_ptr, len) };
2639        error![
2640            res,
2641            &format!("NcPlane.qrcode(data:{:?})", data),
2642            (res as u32, max_y, max_x)
2643        ]
2644    }
2645}