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