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}