libnotcurses_sys/direct/methods.rs
1//! `NcDirect` methods and associated functions.
2
3use core::ptr::{null, null_mut};
4
5use crate::{
6 c_api::{self, ffi::wchar_t},
7 cstring, error, error_ref_mut, rstring_free, NcAlign, NcBlitter, NcCapabilities, NcChannels,
8 NcDirect, NcDirectFlag, NcError, NcFd, NcInput, NcPaletteIndex, NcPlane, NcResult, NcRgb,
9 NcScale, NcStyle, NcTime,
10};
11
12#[cfg(not(feature = "std"))]
13use alloc::{format, string::String};
14
15/// # `NcDirect` constructors and destructors
16impl NcDirect {
17 /// New NcDirect with the default options.
18 ///
19 /// Initializes a direct-mode notcurses context on the tty.
20 ///
21 /// Direct mode supports a limited subset of notcurses routines,
22 /// and neither supports nor requires
23 /// [`notcurses_render`][c_api::notcurses_render]. This can be used to add
24 /// color and styling to text in the standard output paradigm.
25 ///
26 /// # Safety
27 /// You must not create multiple `NcDirect` instances at the same time, on
28 /// the same thread. You must [`stop`][NcDirect#method.stop] the current one
29 /// before creating a new one.
30 ///
31 /// *C style function: [ncdirect_init()][c_api::ncdirect_init].*
32 pub unsafe fn new<'a>() -> NcResult<&'a mut NcDirect> {
33 Self::with_flags(NcDirectFlag::None)
34 }
35
36 /// New `NcDirect` with optional flags.
37 ///
38 /// # Safety
39 /// You must not create multiple `NcDirect` instances at the same time, on
40 /// the same thread. You must [`stop`][NcDirect#method.stop] the current one
41 /// before creating a new one.
42 ///
43 /// *C style function: [ncdirect_init()][c_api::ncdirect_init].*
44 pub unsafe fn with_flags<'a>(flags: impl Into<NcDirectFlag>) -> NcResult<&'a mut NcDirect> {
45 let res = c_api::ncdirect_init(null(), null_mut(), flags.into().into());
46 error_ref_mut![res, "Initializing NcDirect"]
47 }
48
49 /// Releases this `NcDirect` and any associated resources.
50 ///
51 /// # Safety
52 /// You must not call this method repeatedly on the same `NcDirect` instance.
53 ///
54 /// *C style function: [ncdirect_stop()][c_api::ncdirect_stop].*
55 pub unsafe fn stop(&mut self) -> NcResult<()> {
56 error![c_api::ncdirect_stop(self), "NcDirect.stop()"]
57 }
58}
59
60/// ## NcDirect methods: clear, flush, render
61impl NcDirect {
62 /// Clears the screen.
63 ///
64 /// *C style function: [ncdirect_clear()][c_api::ncdirect_clear].*
65 pub fn clear(&mut self) -> NcResult<()> {
66 error![unsafe { c_api::ncdirect_clear(self) }, "NcDirect.clear()"]
67 }
68
69 /// Forces a flush.
70 ///
71 /// *C style function: [ncdirect_flush()][c_api::ncdirect_flush].*
72 pub fn flush(&self) -> NcResult<()> {
73 error![unsafe { c_api::ncdirect_flush(self) }, "NcDirect.clear()"]
74 }
75
76 /// Takes the result of [`render_frame`][NcDirect#method.render_frame]
77 /// and writes it to the output.
78 ///
79 /// *C style function: [ncdirect_raster_frame()][c_api::ncdirect_raster_frame].*
80 pub fn raster_frame(&mut self, frame: &mut NcPlane, align: impl Into<NcAlign>) -> NcResult<()> {
81 error![
82 unsafe { c_api::ncdirect_raster_frame(self, frame, align.into().into()) },
83 "NcDirect.raster_frame()"
84 ]
85 }
86
87 /// Renders an image using the specified blitter and scaling,
88 /// but doesn't write the result.
89 ///
90 /// The image may be arbitrarily many rows -- the output will scroll --
91 /// but will only occupy the column of the cursor, and those to the right.
92 ///
93 /// To actually write (and free) this, invoke ncdirect_raster_frame().
94 ///
95 /// `max_y' and 'max_x` (cell geometry, *not* pixel), if greater than 0,
96 /// are used for scaling; the terminal's geometry is otherwise used.
97 ///
98 /// *C style function: [ncdirect_render_frame()][c_api::ncdirect_render_frame].*
99 pub fn render_frame<'a>(
100 &mut self,
101 filename: &str,
102 blitter: impl Into<NcBlitter>,
103 scale: impl Into<NcScale>,
104 max_y: u32,
105 max_x: u32,
106 ) -> NcResult<&'a mut NcPlane> {
107 let (blitter, scale) = (blitter.into(), scale.into());
108 let cs = cstring![filename];
109 let res = unsafe {
110 c_api::ncdirect_render_frame(
111 self,
112 cs.as_ptr(),
113 blitter.into(),
114 scale.into(),
115 max_y as i32,
116 max_x as i32,
117 )
118 };
119 error_ref_mut![
120 res,
121 &format!(
122 "NcDirect.render_frame({:?}, {:?}, {:?})",
123 filename, blitter, scale
124 )
125 ]
126 }
127
128 /// Displays an image using the specified blitter and scaling.
129 ///
130 /// The image may be arbitrarily many rows -- the output will scroll -- but
131 /// will only occupy the column of the cursor, and those to the right.
132 ///
133 /// The render/raster process can be split by using
134 /// [`render_frame`][#method.render_frame] and
135 /// [`raster_frame`][#method.raster_frame].
136 ///
137 /// *C style function: [ncdirect_render_image()][c_api::ncdirect_render_image].*
138 pub fn render_image(
139 &mut self,
140 filename: &str,
141 align: impl Into<NcAlign>,
142 blitter: impl Into<NcBlitter>,
143 scale: impl Into<NcScale>,
144 ) -> NcResult<()> {
145 let (align, blitter, scale) = (align.into(), blitter.into(), scale.into());
146 let cs = cstring![filename];
147 error![
148 unsafe {
149 c_api::ncdirect_render_image(
150 self,
151 cs.as_ptr(),
152 align.into(),
153 blitter.into(),
154 scale.into(),
155 )
156 },
157 &format!(
158 "NcDirect.render_image({:?}, {:?}, {:?}, {:?})",
159 filename, align, blitter, scale
160 )
161 ]
162 }
163}
164
165/// ## NcDirect methods: `NcPaletteIndex`, `NcRgb`, `NcStyle` & default color
166impl NcDirect {
167 /// Sets the foreground [`NcPaletteIndex`].
168 ///
169 /// *C style function: [ncdirect_set_fg_palindex()][c_api::ncdirect_set_fg_palindex].*
170 pub fn set_fg_palindex(&mut self, index: impl Into<NcPaletteIndex>) -> NcResult<()> {
171 let index = index.into();
172 error![
173 unsafe { c_api::ncdirect_set_fg_palindex(self, index as i32) },
174 &format!("NcDirect.set_fg_palindex({})", index)
175 ]
176 }
177
178 /// Sets the background [`NcPaletteIndex`].
179 ///
180 /// *C style function: [ncdirect_set_bg_palindex()][c_api::ncdirect_set_bg_palindex].*
181 pub fn set_bg_palindex(&mut self, index: impl Into<NcPaletteIndex>) -> NcResult<()> {
182 let index = index.into();
183 error![
184 unsafe { c_api::ncdirect_set_bg_palindex(self, index as i32) },
185 &format!("NcDirect.set_fg_palindex({})", index)
186 ]
187 }
188
189 /// Returns the number of simultaneous colors claimed to be supported,
190 /// if there is color support.
191 ///
192 /// Note that several terminal emulators advertise more colors than they
193 /// actually support, downsampling internally.
194 ///
195 /// *C style function: [ncdirect_palette_size()][c_api::ncdirect_palette_size].*
196 pub fn palette_size(&self) -> NcResult<u32> {
197 let res = unsafe { c_api::ncdirect_palette_size(self) };
198 if res == 1 {
199 return Err(NcError::with_msg(
200 1,
201 "No color support ← NcDirect.palette_size()",
202 ));
203 }
204 Ok(res)
205 }
206
207 /// Sets the foreground [`NcRgb`].
208 ///
209 /// *C style function: [ncdirect_set_fg_rgb()][c_api::ncdirect_set_fg_rgb].*
210 pub fn set_fg_rgb(&mut self, rgb: impl Into<NcRgb>) -> NcResult<()> {
211 error![
212 unsafe { c_api::ncdirect_set_fg_rgb(self, rgb.into().into()) },
213 "NcDirect.set_fg_rgb()"
214 ]
215 }
216
217 /// Sets the background [`NcRgb`].
218 ///
219 /// *C style function: [ncdirect_set_bg_rgb()][c_api::ncdirect_set_bg_rgb].*
220 pub fn set_bg_rgb(&mut self, rgb: impl Into<NcRgb>) -> NcResult<()> {
221 error![
222 unsafe { c_api::ncdirect_set_bg_rgb(self, rgb.into().into()) },
223 "NcDirect.set_bg_rgb({:?})"
224 ]
225 }
226
227 /// Returns the current styling.
228 ///
229 /// *C style function: [ncdirect_styles()][c_api::ncdirect_styles].*
230 pub fn styles(&self) -> NcStyle {
231 unsafe { c_api::ncdirect_styles(self).into() }
232 }
233
234 /// Removes the specified `styles`.
235 ///
236 /// *C style function: [ncdirect_off_styles()][c_api::ncdirect_off_styles].*
237 pub fn styles_off(&mut self, styles: impl Into<NcStyle>) -> NcResult<()> {
238 let styles = styles.into();
239 error![
240 unsafe { c_api::ncdirect_off_styles(self, styles.into()) },
241 &format!("NcDirect.styles_off({:0X})", styles)
242 ]
243 }
244
245 /// Adds the specified `styles`.
246 ///
247 /// *C style function: [ncdirect_on_styles()][c_api::ncdirect_on_styles].*
248 pub fn styles_on(&mut self, styles: impl Into<NcStyle>) -> NcResult<()> {
249 let styles = styles.into();
250 error![
251 unsafe { c_api::ncdirect_on_styles(self, styles.into()) },
252 &format!("NcDirect.styles_on({:0X})", styles)
253 ]
254 }
255
256 /// Sets just the specified `styles`.
257 ///
258 /// *C style function: [ncdirect_set_styles()][c_api::ncdirect_set_styles].*
259 pub fn styles_set(&mut self, styles: impl Into<NcStyle>) -> NcResult<()> {
260 let styles = styles.into();
261 error![
262 unsafe { c_api::ncdirect_set_styles(self, styles.into()) },
263 &format!("NcDirect.styles_set({:0X})", styles)
264 ]
265 }
266
267 /// Returns an [`NcStyle`] with the supported curses-style attributes.
268 ///
269 /// The attribute is only indicated as supported if the terminal can support
270 /// it together with color.
271 ///
272 /// For more information, see the "ncv" capability in *terminfo(5)*.
273 ///
274 /// *C style function: [ncdirect_supported_styles()][c_api::ncdirect_supported_styles].*
275 pub fn supported_styles(&self) -> NcStyle {
276 unsafe { c_api::ncdirect_supported_styles(self).into() }
277 }
278
279 /// Indicates to use the "default color" for the foreground.
280 ///
281 /// *C style function: [ncdirect_set_fg_default()][c_api::ncdirect_set_fg_default].*
282 pub fn set_fg_default(&mut self) -> NcResult<()> {
283 error![
284 unsafe { c_api::ncdirect_set_fg_default(self) },
285 "NcDirect.set_fg_default()"
286 ]
287 }
288
289 /// Indicates to use the "default color" for the background.
290 ///
291 /// *C style function: [ncdirect_set_bg_default()][c_api::ncdirect_set_bg_default].*
292 pub fn set_bg_default(&mut self) -> NcResult<()> {
293 error![
294 unsafe { c_api::ncdirect_set_bg_default(self) },
295 "NcDirect.set_bg_default()"
296 ]
297 }
298}
299
300/// ## NcDirect methods: capabilities, cursor, dimensions
301impl NcDirect {
302 /// Is there support for acquiring the cursor's current position?
303 ///
304 /// Requires the u7 terminfo capability, and that we are connected to an
305 /// actual terminal.
306 pub fn canget_cursor(&self) -> bool {
307 unsafe { c_api::ncdirect_canget_cursor(self) }
308 }
309
310 /// Can we reliably use Unicode braille?
311 ///
312 /// *C style function: [ncdirect_canbraille()][c_api::ncdirect_canbraille].*
313 pub fn canbraille(&self) -> bool {
314 c_api::ncdirect_canbraille(self)
315 }
316
317 /// Can we set the "hardware" palette?
318 ///
319 /// Requires the "ccc" terminfo capability.
320 ///
321 /// *C style function: [ncdirect_canchangecolor()][c_api::ncdirect_canchangecolor].*
322 pub fn canchangecolor(&self) -> bool {
323 c_api::ncdirect_canchangecolor(self)
324 }
325
326 /// Can we fade?
327 ///
328 /// Requires either the "rgb" or "ccc" terminfo capability.
329 ///
330 /// *C style function: [ncdirect_canfade()][c_api::ncdirect_canfade].*
331 pub fn canfade(&self) -> bool {
332 c_api::ncdirect_canfade(self)
333 }
334
335 /// Can we reliably use Unicode halfblocks?
336 ///
337 /// *C style function: [ncdirect_canhalfblock()][c_api::ncdirect_canhalfblock].*
338 pub fn canhalfblock(&self) -> bool {
339 c_api::ncdirect_canhalfblock(self)
340 }
341
342 /// Can we load images?
343 ///
344 /// Requires being built against FFmpeg/OIIO.
345 ///
346 /// *C style function: [ncdirect_canopen_images()][c_api::ncdirect_canopen_images].*
347 pub fn canopen_images(&self) -> bool {
348 c_api::ncdirect_canopen_images(self)
349 }
350
351 /// Can we load videos?
352 ///
353 /// Requires being built against FFmpeg/OIIO.
354 ///
355 /// *C style function: [ncdirect_canopen_videos()][c_api::ncdirect_canopen_videos].*
356 pub fn canopen_videos(&self) -> bool {
357 c_api::ncdirect_canopen_videos(self)
358 }
359
360 /// Can we reliably use Unicode quadrants?
361 ///
362 /// *C style function: [ncdirect_canquadrant()][c_api::ncdirect_canquadrant].*
363 pub fn canquadrant(&self) -> bool {
364 c_api::ncdirect_canquadrant(self)
365 }
366
367 /// Can we reliably use Unicode sextants?
368 ///
369 /// *C style function: [ncdirect_cansextant()][c_api::ncdirect_cansextant].*
370 pub fn cansextant(&self) -> bool {
371 c_api::ncdirect_cansextant(self)
372 }
373
374 /// Can we directly specify RGB values per cell, or only use palettes?
375 ///
376 /// *C style function: [ncdirect_cantruecolor()][c_api::ncdirect_cantruecolor].*
377 pub fn cantruecolor(&self) -> bool {
378 c_api::ncdirect_cantruecolor(self)
379 }
380
381 /// Is our encoding UTF-8?
382 ///
383 /// Requires LANG being set to a UTF8 locale.
384 ///
385 /// *C style function: [ncdirect_canutf8()][c_api::ncdirect_canutf8].*
386 pub fn canutf8(&self) -> bool {
387 unsafe { c_api::ncdirect_canutf8(self) }
388 }
389
390 /// Returns the [`NcCapabilities`].
391 ///
392 /// *C style function: [ncdirect_capabilities()][c_api::ncdirect_capabilities].*
393 pub fn capabilities(&self) -> NcCapabilities {
394 c_api::ncdirect_capabilities(self)
395 }
396
397 /// Checks for pixel support.
398 ///
399 /// Returns `false` for no support, or `true` if pixel output is supported.
400 ///
401 /// This function must successfully return before NCBLIT_PIXEL is available.
402 ///
403 /// Must not be called concurrently with either input or rasterization.
404 ///
405 /// *C style function: [ncdirect_check_pixel_support()][c_api::ncdirect_check-pixel_support].*
406 #[allow(clippy::wildcard_in_or_patterns)]
407 pub fn check_pixel_support(&self) -> NcResult<bool> {
408 let res = unsafe { c_api::ncdirect_check_pixel_support(self) };
409 match res {
410 0 => Ok(false),
411 1 => Ok(true),
412 c_api::NCRESULT_ERR | _ => {
413 Err(NcError::with_msg(res, "NcDirect.check_pixel_support()"))
414 }
415 }
416 }
417
418 /// Disables the terminal's cursor, if supported.
419 ///
420 /// *C style function: [ncdirect_cursor_disable()][c_api::ncdirect_cursor_disable].*
421 pub fn cursor_disable(&mut self) -> NcResult<()> {
422 error![
423 unsafe { c_api::ncdirect_cursor_disable(self) },
424 "NcDirect.cursor_disable()"
425 ]
426 }
427
428 /// Enables the terminal's cursor, if supported.
429 ///
430 /// *C style function: [ncdirect_cursor_enable()][c_api::ncdirect_cursor_enable].*
431 pub fn cursor_enable(&mut self) -> NcResult<()> {
432 error![
433 unsafe { c_api::ncdirect_cursor_enable(self) },
434 "NcDirect.cursor_enable()"
435 ]
436 }
437
438 /// Moves the cursor down any number of rows.
439 ///
440 /// *C style function: [ncdirect_cursor_down()][c_api::ncdirect_cursor_down].*
441 pub fn cursor_down(&mut self, rows: i32) -> NcResult<()> {
442 error![
443 unsafe { c_api::ncdirect_cursor_down(self, rows) },
444 &format!("NcDirect.cursor_down({})", rows)
445 ]
446 }
447
448 /// Moves the cursor left any number of columns.
449 ///
450 /// *C style function: [ncdirect_cursor_left()][c_api::ncdirect_cursor_left].*
451 pub fn cursor_left(&mut self, cols: i32) -> NcResult<()> {
452 error![
453 unsafe { c_api::ncdirect_cursor_left(self, cols) },
454 &format!("NcDirect.cursor_left({})", cols)
455 ]
456 }
457
458 /// Moves the cursor right any number of columns.
459 ///
460 /// *C style function: [ncdirect_cursor_right()][c_api::ncdirect_cursor_right].*
461 pub fn cursor_right(&mut self, cols: i32) -> NcResult<()> {
462 error![
463 unsafe { c_api::ncdirect_cursor_right(self, cols) },
464 &format!("NcDirect.cursor_right({})", cols)
465 ]
466 }
467
468 /// Moves the cursor up any number of rows.
469 ///
470 /// *C style function: [ncdirect_cursor_up()][c_api::ncdirect_cursor_up].*
471 pub fn cursor_up(&mut self, rows: i32) -> NcResult<()> {
472 error![
473 unsafe { c_api::ncdirect_cursor_up(self, rows) },
474 &format!("NcDirect.cursor_up({})", rows)
475 ]
476 }
477
478 /// Sets the cursor to the specified row `y`, column `x`.
479 ///
480 /// *C style function: [ncdirect_cursor_move_yx()][c_api::ncdirect_cursor_move_yx].*
481 pub fn cursor_set_yx(&mut self, y: u32, x: u32) -> NcResult<()> {
482 error![unsafe { c_api::ncdirect_cursor_move_yx(self, y as i32, x as i32) }]
483 }
484
485 /// Sets the cursor to the specified row `y`.
486 ///
487 /// *(No equivalent C style function)*
488 pub fn cursor_set_y(&mut self, y: u32) -> NcResult<()> {
489 error![unsafe { c_api::ncdirect_cursor_move_yx(self, y as i32, -1) }]
490 }
491
492 /// Sets the cursor to the specified column `x`.
493 ///
494 /// *(No equivalent C style function)*
495 pub fn cursor_set_x(&mut self, x: u32) -> NcResult<()> {
496 error![unsafe { c_api::ncdirect_cursor_move_yx(self, -1, x as i32) }]
497 }
498
499 /// Gets the cursor (y, x) position, when supported.
500 ///
501 /// This requires writing to the terminal, and then reading from it.
502 /// If the terminal doesn't reply, or doesn't reply in a way we understand,
503 /// the results might be detrimental.
504 ///
505 /// *C style function: [ncdirect_cursor_yx()][c_api::ncdirect_cursor_yx].*
506 pub fn cursor_yx(&mut self) -> NcResult<(u32, u32)> {
507 let (mut y, mut x) = (0, 0);
508 error![
509 unsafe { c_api::ncdirect_cursor_yx(self, &mut y, &mut x) },
510 "",
511 (y, x)
512 ]
513 }
514
515 /// Pushes the cursor location to the terminal's stack.
516 ///
517 /// The depth of this stack, and indeed its existence, is terminal-dependent.
518 ///
519 /// *C style function: [ncdirect_cursor_push()][c_api::ncdirect_cursor_push].*
520 pub fn cursor_push(&mut self) -> NcResult<()> {
521 error![unsafe { c_api::ncdirect_cursor_push(self) }]
522 }
523
524 /// Pops the cursor location from the terminal's stack.
525 ///
526 /// The depth of this stack, and indeed its existence, is terminal-dependent.
527 ///
528 /// *C style function: [ncdirect_cursor_pop()][c_api::ncdirect_cursor_pop].*
529 pub fn cursor_pop(&mut self) -> NcResult<()> {
530 error![unsafe { c_api::ncdirect_cursor_pop(self) }]
531 }
532
533 /// Gets the current number of rows.
534 ///
535 /// *C style function: [ncdirect_dim_y()][c_api::ncdirect_dim_y].*
536 pub fn dim_y(&mut self) -> u32 {
537 unsafe { c_api::ncdirect_dim_y(self) }
538 }
539
540 /// Gets the current number of columns.
541 ///
542 /// *C style function: [ncdirect_dim_x()][c_api::ncdirect_dim_x].*
543 pub fn dim_x(&mut self) -> u32 {
544 unsafe { c_api::ncdirect_dim_x(self) }
545 }
546
547 /// Gets the current number of rows and columns.
548 ///
549 /// *C style function: [ncdirect_dim_y()][c_api::ncdirect_dim_y].*
550 pub fn dim_yx(&mut self) -> (u32, u32) {
551 let y = unsafe { c_api::ncdirect_dim_y(self) };
552 let x = unsafe { c_api::ncdirect_dim_x(self) };
553 (y, x)
554 }
555
556 /// Returns the name of the detected terminal.
557 ///
558 /// *C style function: [ncdirect_detected_terminal()][c_api::ncdirect_detected_terminal].*
559 pub fn detected_terminal(&self) -> String {
560 rstring_free![c_api::ncdirect_detected_terminal(self)]
561 }
562}
563
564/// ## NcDirect methods: I/O
565impl NcDirect {
566 /// Returns a [char] representing a single unicode point.
567 ///
568 /// If an event is processed, the return value is the `id` field from that
569 /// event.
570 ///
571 /// Provide a None `time` to block at length, a `time` of 0 for non-blocking
572 /// operation, and otherwise a timespec to bound blocking.
573 ///
574 /// *C style function: [ncdirect_get()][c_api::ncdirect_get].*
575 // CHECK returns 0 on a timeout.
576 pub fn get(&mut self, time: Option<NcTime>, input: Option<&mut NcInput>) -> NcResult<char> {
577 let ntime = if let Some(time) = time { &time as *const _ } else { null() };
578 let ninput = if let Some(input) = input { input as *mut _ } else { null_mut() };
579
580 let res = unsafe { c_api::ncdirect_get(self, ntime, ninput) };
581 core::char::from_u32(res)
582 .ok_or_else(|| NcError::with_msg(res as i32, &format!["Nc.get(time: {:?})", time]))
583 }
584
585 /// Reads input blocking until an event is processed or a signal is received.
586 ///
587 /// Will optionally write the event details in `input`.
588 ///
589 /// In the case of a valid read, a [`char`] is returned.
590 ///
591 /// *C style function: [ncdirect_get_blocking()][c_api::ncdirect_get_blocking].*
592 pub fn get_blocking(&mut self, input: Option<&mut NcInput>) -> NcResult<char> {
593 let res = c_api::ncdirect_get_blocking(self, input);
594 core::char::from_u32(res as u32)
595 .ok_or_else(|| NcError::with_msg(res, "NcDirect.get_blocking()"))
596 }
597
598 /// Reads input without blocking.
599 ///
600 /// In the case of a valid read, a [`char`] is returned.
601 ///
602 /// If no event is ready, returns 0.
603 ///
604 /// *C style function: [ncdirect_get_nblock()][c_api::ncdirect_get_nblock].*
605 pub fn get_nblock(&mut self, input: Option<&mut NcInput>) -> NcResult<char> {
606 let res = c_api::ncdirect_get_nblock(self, input);
607 core::char::from_u32(res as u32)
608 .ok_or_else(|| NcError::with_msg(res, "NcDirect.get_nblock()"))
609 }
610
611 /// Get a file descriptor suitable for input event poll()ing.
612 ///
613 /// When this descriptor becomes available, you can call `NcDirect.`
614 /// [`get_nblock`][NcDirect#method.get_nblock], and input ought be ready.
615 ///
616 /// This file descriptor is not necessarily the file descriptor associated
617 /// with stdin (but it might be!).
618 ///
619 /// *C style function: [ncdirect_inputready_fd()][c_api::ncdirect_inputready_fd].*
620 pub fn inputready_fd(&mut self) -> NcResult<NcFd> {
621 let res = unsafe { c_api::ncdirect_inputready_fd(self) };
622 error![res, "", res]
623 }
624
625 /// Outputs the `string` according to the `channels`, and
626 /// returns the total number of characters written on success.
627 ///
628 /// Note that it does not explicitly flush output buffers, so it will not
629 /// necessarily be immediately visible.
630 ///
631 /// It will fail if the NcDirect context and the foreground channel
632 /// are both marked as using the default color.
633 ///
634 /// *C style function: [ncdirect_putstr()][c_api::ncdirect_putstr].*
635 pub fn putstr(&mut self, channels: impl Into<NcChannels>, string: &str) -> NcResult<()> {
636 let channels = channels.into();
637 let cs = cstring![string];
638 error![
639 unsafe { c_api::ncdirect_putstr(self, channels.into(), cs.as_ptr()) },
640 &format!("NcDirect.putstr({:0X}, {:?})", channels, string)
641 ]
642 }
643
644 /// Reads a (heap-allocated) line of text using the Readline library.
645 ///
646 /// Initializes Readline the first time it's called.
647 ///
648 /// For input to be echoed to the terminal, it is necessary that the flag
649 /// [`NcDirectFlag::INHIBIT_CBREAK`][0] be provided to the constructor.
650 ///
651 /// [0]: NcDirectFlag#associatedconstant.INHIBIT_CBREAK
652 ///
653 /// *C style function: [ncdirect_readline()][c_api::ncdirect_readline].*
654 //
655 // CHECK if memory leak still reported by valgrind
656 pub fn readline(&mut self, prompt: &str) -> NcResult<String> {
657 let cs = cstring![prompt];
658 let res = unsafe { c_api::ncdirect_readline(self, cs.as_ptr()) };
659 if !res.is_null() {
660 Ok(rstring_free![res])
661 } else {
662 Err(NcError::with_msg(
663 c_api::NCRESULT_ERR,
664 &format!["NcDirect.readline({})", prompt],
665 ))
666 }
667 }
668
669 /// Draws a box with its upper-left corner at the current cursor position,
670 /// having dimensions `ylen` * `xlen`.
671 ///
672 /// See `NcPlane.`[`box`][NcPlane#method.box] for more information.
673 ///
674 /// The minimum box size is 2x2, and it cannot be drawn off-screen.
675 ///
676 /// `wchars` is an array of 6 characters: UL, UR, LL, LR, HL, VL.
677 ///
678 /// *C style function: [ncdirect_box()][c_api::ncdirect_box].*
679 //
680 // CHECK, specially wchars.
681 pub fn r#box(
682 &mut self,
683 ul: impl Into<NcChannels>,
684 ur: impl Into<NcChannels>,
685 ll: impl Into<NcChannels>,
686 lr: impl Into<NcChannels>,
687 wchars: &[char; 6],
688 len_y: u32,
689 len_x: u32,
690 ctlword: u32,
691 ) -> NcResult<()> {
692 let (ul, ur, ll, lr) = (ul.into(), ur.into(), ll.into(), lr.into());
693 error![
694 unsafe {
695 let wchars = wchars as *const [char; 6] as *const wchar_t;
696 c_api::ncdirect_box(self, ul.0, ur.0, ll.0, lr.0, wchars, len_y, len_x, ctlword)
697 },
698 &format!(
699 "NcDirect.box({:0X}, {:0X}, {:0X}, {:0X}, {:?}, {}, {}, {})",
700 ul, ur, ll, lr, wchars, len_y, len_x, ctlword
701 )
702 ]
703 }
704
705 /// `NcDirect.`[`box`][NcDirect#method.box] with the double box-drawing characters.
706 ///
707 /// *C style function: [ncdirect_double_box()][c_api::ncdirect_double_box].*
708 pub fn double_box(
709 &mut self,
710 ul: impl Into<NcChannels>,
711 ur: impl Into<NcChannels>,
712 ll: impl Into<NcChannels>,
713 lr: impl Into<NcChannels>,
714 len_y: u32,
715 len_x: u32,
716 ctlword: u32,
717 ) -> NcResult<()> {
718 error![unsafe {
719 c_api::ncdirect_double_box(
720 self,
721 ul.into().0,
722 ur.into().0,
723 ll.into().0,
724 lr.into().0,
725 len_y,
726 len_x,
727 ctlword,
728 )
729 }]
730 }
731
732 /// `NcDirect.`[`box`][NcDirect#method.box] with the rounded box-drawing characters.
733 ///
734 /// *C style function: [ncdirect_rounded_box()][c_api::ncdirect_rounded_box].*
735 pub fn rounded_box(
736 &mut self,
737 ul: impl Into<NcChannels>,
738 ur: impl Into<NcChannels>,
739 ll: impl Into<NcChannels>,
740 lr: impl Into<NcChannels>,
741 len_y: u32,
742 len_x: u32,
743 ctlword: u32,
744 ) -> NcResult<()> {
745 error![unsafe {
746 c_api::ncdirect_rounded_box(
747 self,
748 ul.into().0,
749 ur.into().0,
750 ll.into().0,
751 lr.into().0,
752 len_y,
753 len_x,
754 ctlword,
755 )
756 }]
757 }
758
759 /// Draws horizontal lines using the specified [NcChannels]s, interpolating
760 /// between them as we go.
761 ///
762 /// All lines start at the current cursor position.
763 ///
764 /// The string at `egc` may not use more than one column.
765 ///
766 /// For a horizontal line, `len` cannot exceed the screen width minus the
767 /// cursor's offset.
768 ///
769 /// *C style function: [ncdirect_hline_interp()][c_api::ncdirect_hline_interp].*
770 #[inline]
771 pub fn hline_interp(
772 &mut self,
773 egc: &str,
774 len: u32,
775 h1: impl Into<NcChannels>,
776 h2: impl Into<NcChannels>,
777 ) -> NcResult<()> {
778 error![c_api::ncdirect_hline_interp(
779 self,
780 egc,
781 len,
782 h1.into().0,
783 h2.into().0
784 )]
785 }
786
787 /// Draws horizontal lines using the specified [NcChannels]s, interpolating
788 /// between them as we go.
789 ///
790 /// All lines start at the current cursor position.
791 ///
792 /// The string at `egc` may not use more than one column.
793 ///
794 /// For a vertical line, `len` may be as long as you'd like; the screen
795 /// will scroll as necessary.
796 ///
797 /// *C style function: [ncdirect_vline_interp()][c_api::ncdirect_vline_interp].*
798 #[inline]
799 pub fn vline_interp(
800 &mut self,
801 egc: &str,
802 len: u32,
803 h1: impl Into<NcChannels>,
804 h2: impl Into<NcChannels>,
805 ) -> NcResult<()> {
806 error![c_api::ncdirect_vline_interp(
807 self,
808 egc,
809 len,
810 h1.into().0,
811 h2.into().0
812 )]
813 }
814}