1 #![allow(non_camel_case_types, non_snake_case)]
2 
3 #[macro_use]
4 extern crate log;
5 
6 extern crate libc;
7 
8 #[cfg(unix)]
9 extern crate ncurses;
10 #[cfg(windows)]
11 extern crate pdcurses;
12 
13 use std::ffi::CString;
14 use std::ptr;
15 
16 #[cfg(windows)]
17 use pdcurses as curses;
18 #[cfg(windows)]
19 pub use pdcurses::{chtype, mmask_t, MEVENT, SCREEN};
20 #[cfg(windows)]
21 type ScrPtr = *mut SCREEN;
22 #[cfg(windows)]
23 type FILE = *mut curses::FILE;
24 
25 #[cfg(unix)]
26 use ncurses::ll as curses;
27 #[cfg(unix)]
28 pub use ncurses::ll::{chtype, mmask_t, MEVENT, SCREEN};
29 #[cfg(unix)]
30 type ScrPtr = SCREEN;
31 #[cfg(unix)]
32 type FILE = curses::FILE_p;
33 
34 mod input;
35 pub use self::input::*;
36 
37 mod attributes;
38 pub use self::attributes::*;
39 
40 pub mod colorpair;
41 pub use crate::colorpair::ColorPair;
42 
43 #[cfg(windows)]
44 mod windows;
45 #[cfg(windows)]
46 pub use self::windows::constants::*;
47 #[cfg(windows)]
48 use self::windows as platform_specific;
49 
50 #[cfg(unix)]
51 mod unix;
52 #[cfg(unix)]
53 pub use self::unix::constants::*;
54 #[cfg(unix)]
55 use self::unix as platform_specific;
56 
57 pub const OK: i32 = 0;
58 pub const ERR: i32 = -1;
59 
60 mod window;
61 pub use crate::window::Window;
62 
63 pub trait ToChtype {
64     fn to_chtype(&self) -> chtype;
65 }
66 
67 impl ToChtype for char {
68     fn to_chtype(&self) -> chtype {
69         *self as chtype
70     }
71 }
72 
73 impl ToChtype for chtype {
74     fn to_chtype(&self) -> chtype {
75         *self
76     }
77 }
78 
79 /// Return the output speed of the terminal. On Windows it simply returns `INT_MAX`
80 pub fn baudrate() -> i32 {
81     unsafe { curses::baudrate() }
82 }
83 
84 /// Sounds the audible bell on the terminal, if possible; if not, it calls flash().
85 pub fn beep() -> i32 {
86     unsafe { curses::beep() }
87 }
88 
89 /// Indicates if the terminal has the capability to change the definition of its colors.
90 pub fn can_change_color() -> bool {
91     unsafe { curses::can_change_color() != 0 }
92 }
93 
94 /// Set cbreak mode.
95 ///
96 /// In cbreak mode, characters typed by the user are made available immediately, and erase/kill
97 /// character processing is not performed.  In nocbreak mode, typed characters are buffered until
98 /// a newline or carriage return. Interrupt and flow control characters are unaffected by this
99 /// mode.
100 pub fn cbreak() -> i32 {
101     unsafe { curses::cbreak() }
102 }
103 
104 /// Maximum number of colors the terminal is capable of displaying.
105 pub fn COLORS() -> i32 {
106     platform_specific::_COLORS()
107 }
108 
109 /// Maximum number of color-pairs the terminal is capable of displaying.
110 pub fn COLOR_PAIRS() -> i32 {
111     platform_specific::_COLOR_PAIRS()
112 }
113 
114 /// This routine gives programmers a way to find the intensity of the red, green, and blue (RGB)
115 /// components in a color. It takes the color number as an argument and returns three values
116 /// that tell you the amounts of red, green, and blue components in the given color. The argument
117 /// must be a legal color value, i.e., 0 through COLORS()-1, inclusive. The values that are returned
118 /// are in the range 0 (no component) through 1000 (maximum amount of component), inclusive.
119 ///
120 /// ```rust
121 /// use pancurses::{can_change_color, color_content, endwin, init_color, initscr, start_color};
122 ///
123 /// initscr();
124 /// start_color();
125 /// if can_change_color() {
126 ///     init_color(8, 35, 502, 1000);
127 ///     let (r, g, b) = color_content(8);
128 ///     assert_eq!(35, r);
129 ///     assert_eq!(502, g);
130 ///     assert_eq!(1000, b);
131 /// }
132 /// endwin();
133 /// ```
134 pub fn color_content(color_number: i16) -> (i16, i16, i16) {
135     let mut r: i16 = 0;
136     let mut g: i16 = 0;
137     let mut b: i16 = 0;
138     unsafe {
139         curses::color_content(color_number, &mut r, &mut g, &mut b);
140     }
141     (r, g, b)
142 }
143 
144 /// Alters the appearance of the cursor.
145 ///
146 /// A visibility of 0 makes it disappear; 1 makes it appear "normal" (usually an underline) and 2
147 /// makes it "highly visible" (usually a block).
148 pub fn curs_set(visibility: i32) -> i32 {
149     unsafe { curses::curs_set(visibility) }
150 }
151 
152 /// Save the current terminal modes as the "program" (in curses) state for use by the
153 /// `reset_prog_mode()` and `reset_shell_mode()` functions.  This is done automatically by initscr().
154 pub fn def_prog_mode() -> i32 {
155     unsafe { curses::def_prog_mode() }
156 }
157 
158 /// Save the current terminal modes as the "shell" (not in curses) state for use by the
159 /// `reset_prog_mode()` and `reset_shell_mode()` functions.  This is done automatically by initscr().
160 pub fn def_shell_mode() -> i32 {
161     unsafe { curses::def_shell_mode() }
162 }
163 
164 /// Inserts an 'milliseconds' millisecond pause in output. This routine should not be used extensively
165 /// because padding characters are used rather than a CPU pause. If no padding character is
166 /// specified, this uses napms to perform the delay.
167 pub fn delay_output(milliseconds: i32) -> i32 {
168     unsafe { curses::delay_output(milliseconds) }
169 }
170 
171 /// Frees storage associated with the SCREEN data structure.
172 ///
173 /// The endwin routine does not do this, so delscreen should be called after endwin if a particular
174 /// SCREEN is no longer needed.
175 ///
176 /// In PDCurses, the parameter must be the value of SP, and delscreen() sets SP to NULL.
177 pub fn delscreen(screen: ScrPtr) {
178     unsafe { curses::delscreen(screen) }
179 }
180 
181 /// Compares the virtual screen to the physical screen and performs an update of the physical
182 /// screen.
183 pub fn doupdate() -> i32 {
184     unsafe { curses::doupdate() }
185 }
186 
187 /// Enabled echoing typed characters.
188 ///
189 /// Initially, input characters are echoed. Subsequent calls to echo() and noecho() do not flush
190 /// type-ahead.
191 pub fn echo() -> i32 {
192     unsafe { curses::echo() }
193 }
194 
195 /// Should be called before exiting or escaping from curses mode temporarily.
196 ///
197 /// It will restore tty modes, move the cursor to the lower left corner of the screen and reset the
198 /// terminal into the proper non-visual mode.  To resume curses after a temporary escape, call
199 /// refresh() or doupdate().
200 pub fn endwin() -> i32 {
201     unsafe { curses::endwin() }
202 }
203 
204 /// Flashes the screen, if possible; if not, it calls beep().
205 pub fn flash() -> i32 {
206     unsafe { curses::flash() }
207 }
208 
209 /// Throws away any type-ahead that has been typed by the user and has not yet been read by the
210 /// program.
211 pub fn flushinp() -> i32 {
212     unsafe { curses::flushinp() }
213 }
214 
215 /// Returns the current mouse status in an MEVENT struct.
216 pub fn getmouse() -> Result<MEVENT, i32> {
217     platform_specific::_getmouse()
218 }
219 
220 /// Similar to cbreak(), but allows for a time limit to be specified, in tenths of a second.
221 ///
222 /// This causes getch() to block for that period before returning None if no key has been received.
223 /// tenths must be between 1 and 255.
224 pub fn half_delay(tenths: i32) -> i32 {
225     unsafe { curses::halfdelay(tenths) }
226 }
227 
228 /// Indicates if the terminal supports, and can maniplulate color.
229 pub fn has_colors() -> bool {
230     unsafe { curses::has_colors() > 0 }
231 }
232 
233 /// Initialize the curses system, this must be the first function that is called.
234 ///
235 /// Returns a Window struct that is used to access Window specific functions.
236 pub fn initscr() -> Window {
237     platform_specific::pre_init();
238     let window_pointer = unsafe { curses::initscr() };
239     window::new_window(window_pointer, true)
240 }
241 
242 /// Changes the definition of a color. It takes four arguments: the number of the color to be
243 /// changed followed by three RGB values (for the amounts of red, green, and blue components).
244 /// The first argument must be a legal color value; default colors are not allowed here.
245 /// Each of the last three arguments must be a value in the range 0 through 1000. When `init_color`
246 /// is used, all occurrences of that color on the screen immediately change to the new definition.
247 pub fn init_color(color_number: i16, red: i16, green: i16, blue: i16) -> i32 {
248     unsafe { curses::init_color(color_number, red, green, blue) }
249 }
250 
251 /// Changes the definition of a color-pair.
252 ///
253 /// It takes three arguments: the number of the color-pair to be redefined, and the new values of
254 /// the foreground and background colors. The pair number must be between 0 and `COLOR_PAIRS` - 1,
255 /// inclusive. The foreground and background must be between 0 and `COLORS()` - 1, inclusive. If the
256 /// color pair was previously initialized, the screen is refreshed, and all occurrences of that
257 /// color-pair are changed to the new definition.
258 pub fn init_pair(pair_index: i16, foreground_color: i16, background_color: i16) -> i32 {
259     unsafe { curses::init_pair(pair_index, foreground_color, background_color) as i32 }
260 }
261 
262 /// Sets the timeout for a mouse click.
263 ///
264 /// Sets the maximum time (in thousands of a second) that can elapse between press and release
265 /// events for them to be recognized as aclick. Use mouseinterval(0) to disable click resolution.
266 /// This function returns the previous interval value. Use mouseinterval(-1) to obtain the interval
267 /// without altering it. The default is one sixth of a second.
268 pub fn mouseinterval(interval: i32) -> i32 {
269     unsafe { curses::mouseinterval(interval) }
270 }
271 
272 /// Set the mouse events to be reported.
273 ///
274 /// By default, no mouse events are reported. The function will return a mask to indicate which of
275 /// the specified mouse events can be reported; on complete failure it returns 0. If oldmask is
276 /// non-NULL, this function fills the indicated location with the previous value of the given
277 /// window's mouse event mask.
278 ///
279 /// As a side effect, setting a zero mousemask may turn off the mouse pointer; setting a nonzero
280 /// mask may turn it on. Whether this happens is device-dependent.
281 pub fn mousemask(newmask: mmask_t, oldmask: Option<&mut mmask_t>) -> mmask_t {
282     let oldmask_ptr = oldmask.map(|x| x as *mut _).unwrap_or(std::ptr::null_mut());
283     unsafe { curses::mousemask(newmask, oldmask_ptr) }
284 }
285 
286 /// Returns a character string corresponding to the key `code`.
287 ///
288 /// * Printable characters are displayed as themselves, e.g., a one-character string containing the
289 ///   key.
290 /// * Control characters are displayed in the ^X notation.
291 /// * DEL (character 127) is displayed as ^?.
292 /// * Values above 128 are either meta characters (if the screen has not been initialized, or if
293 ///   meta has been called with a TRUE parameter), shown in the M-X notation, or are displayed as
294 ///   themselves. In the latter case, the values may not be printable; this follows the X/Open
295 ///   specification.
296 /// * Values above 256 may be the names of the names of function keys.
297 /// * Otherwise (if there is no corresponding name) the function returns `None`, to denote an
298 ///   error. X/Open also lists an "UNKNOWN KEY" return value, which some implementations return
299 ///   rather than `None`.
300 pub fn keyname(code: i32) -> Option<String> {
301     platform_specific::_keyname(code)
302 }
303 
304 /// Suspends the program for the specified number of milliseconds.
305 pub fn napms(ms: i32) -> i32 {
306     unsafe { curses::napms(ms) }
307 }
308 
309 /// A program that outputs to more than one terminal should use the newterm routine for each
310 /// terminal instead of initscr.
311 ///
312 /// A program that needs to inspect capabilities, so it can continue to
313 /// run in a line-oriented mode if the terminal cannot support a screen-oriented program, would also
314 /// use newterm. The routine newterm should be called once for each terminal. It returns a variable
315 /// of type `ScrPtr` which should be saved as a reference to that terminal.
316 ///
317 /// (For the PDCurses backend it's just an alternative interface for initscr(). It always returns
318 /// SP, or NULL.)
319 pub fn newterm(t: Option<&str>, output: FILE, input: FILE) -> ScrPtr {
320     let term_type = t.map(|x| CString::new(x).unwrap());
321     let type_ptr = match term_type {
322         Some(ref s) => s.as_ptr(),
323         _ => std::ptr::null(),
324     };
325     unsafe { curses::newterm(type_ptr, output, input) }
326 }
327 
328 /// Creates a new window with the given number of lines, nlines and columns, ncols.
329 ///
330 /// The upper left corner of the window is at line begy, column begx. If nlines is zero, it
331 /// defaults to LINES - begy; ncols to COLS - begx. Create a new full-screen window by calling
332 /// newwin(0, 0, 0, 0).
333 pub fn newwin(nlines: i32, ncols: i32, begy: i32, begx: i32) -> Window {
334     let window_pointer = unsafe { curses::newwin(nlines, ncols, begy, begx) };
335     window::new_window(window_pointer, false)
336 }
337 
338 /// Enables the translation of a carriage return into a newline on input.
339 ///
340 /// nonl() disables this. Initially, the translation does occur.
341 pub fn nl() -> i32 {
342     unsafe { curses::nl() }
343 }
344 
345 /// Set nocbreak mode.
346 ///
347 /// In cbreak mode, characters typed by the user are made available immediately, and erase/kill
348 /// character processing is not performed.  In nocbreak mode, typed characters are buffered until
349 /// a newline or carriage return. Interrupt and flow control characters are unaffected by this
350 /// mode.
351 pub fn nocbreak() -> i32 {
352     unsafe { curses::nocbreak() }
353 }
354 
355 /// Disables echoing typed characters.
356 ///
357 /// Initially, input characters are echoed. Subsequent calls to echo() and noecho() do not flush
358 /// type-ahead.
359 pub fn noecho() -> i32 {
360     unsafe { curses::noecho() }
361 }
362 
363 /// Disables the translation of a carriage return into a newline on input.
364 ///
365 /// nl() enables this. Initially, the translation does occur.
366 pub fn nonl() -> i32 {
367     unsafe { curses::nonl() }
368 }
369 
370 /// Disable raw mode.
371 ///
372 /// Raw mode is similar to cbreak mode, in that characters typed are immediately passed through to
373 /// the user program. The difference is that in raw mode, the INTR, QUIT, SUSP, and STOP characters
374 /// are passed through without being interpreted, and without generating a signal.
375 pub fn noraw() -> i32 {
376     unsafe { curses::noraw() }
377 }
378 
379 /// Enable raw mode.
380 ///
381 /// Raw mode is similar to cbreak mode, in that characters typed are immediately passed through to
382 /// the user program. The difference is that in raw mode, the INTR, QUIT, SUSP, and STOP characters
383 /// are passed through without being interpreted, and without generating a signal.
384 pub fn raw() -> i32 {
385     unsafe { curses::raw() }
386 }
387 
388 /// Restore the terminal to "program" (in curses) state. This is done
389 /// automatically by endwin() and doupdate() after an endwin(), so this would normally not be
390 /// called before.
391 pub fn reset_prog_mode() -> i32 {
392     unsafe { curses::reset_prog_mode() }
393 }
394 
395 /// Restore the terminal to "shell" (not in curses) state. This is done automatically by
396 /// endwin() and doupdate() after an endwin(), so this would normally not be called before.
397 pub fn reset_shell_mode() -> i32 {
398     unsafe { curses::reset_shell_mode() }
399 }
400 
401 /// Attempts to resize the screen to the given size.
402 ///
403 /// `resize_term()` is effectively two functions: When called with nonzero values for nlines and
404 /// ncols, it attempts to resize the screen to the given size. When called with (0, 0), it merely
405 /// adjusts the internal structures to match the current size after the screen is resized by the
406 /// user. If you want to support user resizing, you should check for getch() returning `KEY_RESIZE`,
407 /// and/or call `is_termresized()` at appropriate times; if either condition occurs, call
408 /// `resize_term(0, 0)`. Then, with either user or programmatic resizing, you'll have to resize any
409 /// windows you've created.
410 pub fn resize_term(nlines: i32, ncols: i32) -> i32 {
411     platform_specific::_resize_term(nlines, ncols)
412 }
413 
414 /// Toggles whether the `A_BLINK` attribute sets an actual blink mode (TRUE), or sets the background
415 /// color to high intensity (FALSE).
416 ///
417 /// The default is platform-dependent (FALSE in most cases). It returns OK if it could set the
418 /// state to match the given parameter, ERR otherwise. Current platforms also adjust the value
419 /// of COLORS() according to this function -- 16 for FALSE, and 8 for TRUE.
420 /// (Only supported on Windows)
421 pub fn set_blink(enabled: bool) -> i32 {
422     platform_specific::_set_blink(enabled)
423 }
424 
425 /// Switches between different terminals.
426 ///
427 /// The screen reference new becomes the new current terminal. The previous terminal is returned by
428 /// the routine. This is the only routine which manipulates ScrPtr's; all other routines  affect
429 /// only the current terminal.
430 ///
431 /// (Does nothing meaningful in PDCurses, but is included for compatibility with other curses
432 /// implementations.)
433 pub fn set_term(new: ScrPtr) -> ScrPtr {
434     unsafe { curses::set_term(new) }
435 }
436 
437 /// Sets the title of the window in which the curses program is running. This function may not do
438 /// anything on some platforms. (Only supported on Windows)
439 pub fn set_title(title: &str) {
440     platform_specific::_set_title(title);
441 }
442 
443 /// Initializes eight basic colors (black, red, green, yellow, blue, magenta, cyan,
444 /// and white), and two global variables accessed through `COLORS()` and `COLOR_PAIRS()` (respectively defining the
445 /// maximum number of colors and color-pairs the terminal is capable of displaying).
446 pub fn start_color() -> i32 {
447     unsafe { curses::start_color() as i32 }
448 }
449 
450 /// Allows the use of -1 as a foreground or background color with `init_pair()`.
451 ///
452 /// Calls `assume_default_colors(-1, -1);` -1 represents the foreground or background color that
453 /// the terminal had at startup.
454 pub fn use_default_colors() -> i32 {
455     unsafe { curses::use_default_colors() }
456 }
457