1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
#![allow(non_camel_case_types, non_snake_case)]

#[macro_use]
extern crate log;

extern crate libc;

#[cfg(unix)]
extern crate ncurses;
#[cfg(windows)]
extern crate pdcurses;

use std::ffi::CString;
use std::ptr;

#[cfg(windows)]
use pdcurses as curses;
#[cfg(windows)]
pub use pdcurses::{chtype, mmask_t, MEVENT, SCREEN};
#[cfg(windows)]
type ScrPtr = *mut SCREEN;
#[cfg(windows)]
type FILE = *mut curses::FILE;

#[cfg(unix)]
use ncurses::ll as curses;
#[cfg(unix)]
pub use ncurses::ll::{chtype, mmask_t, MEVENT, SCREEN};
#[cfg(unix)]
type ScrPtr = SCREEN;
#[cfg(unix)]
type FILE = curses::FILE_p;

mod input;
pub use self::input::*;

mod attributes;
pub use self::attributes::*;

pub mod colorpair;
pub use crate::colorpair::ColorPair;

#[cfg(windows)]
mod windows;
#[cfg(windows)]
pub use self::windows::constants::*;
#[cfg(windows)]
use self::windows as platform_specific;

#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use self::unix::constants::*;
#[cfg(unix)]
use self::unix as platform_specific;

pub const OK: i32 = 0;
pub const ERR: i32 = -1;

mod window;
pub use crate::window::Window;

pub trait ToChtype {
    fn to_chtype(&self) -> chtype;
}

impl ToChtype for char {
    fn to_chtype(&self) -> chtype {
        *self as chtype
    }
}

impl ToChtype for chtype {
    fn to_chtype(&self) -> chtype {
        *self
    }
}

/// Return the output speed of the terminal. On Windows it simply returns `INT_MAX`
pub fn baudrate() -> i32 {
    unsafe { curses::baudrate() }
}

/// Sounds the audible bell on the terminal, if possible; if not, it calls flash().
pub fn beep() -> i32 {
    unsafe { curses::beep() }
}

/// Indicates if the terminal has the capability to change the definition of its colors.
pub fn can_change_color() -> bool {
    unsafe { curses::can_change_color() != 0 }
}

/// Set cbreak mode.
///
/// In cbreak mode, characters typed by the user are made available immediately, and erase/kill
/// character processing is not performed.  In nocbreak mode, typed characters are buffered until
/// a newline or carriage return. Interrupt and flow control characters are unaffected by this
/// mode.
pub fn cbreak() -> i32 {
    unsafe { curses::cbreak() }
}

/// Maximum number of colors the terminal is capable of displaying.
pub fn COLORS() -> i32 {
    platform_specific::_COLORS()
}

/// Maximum number of color-pairs the terminal is capable of displaying.
pub fn COLOR_PAIRS() -> i32 {
    platform_specific::_COLOR_PAIRS()
}

/// This routine gives programmers a way to find the intensity of the red, green, and blue (RGB)
/// components in a color. It takes the color number as an argument and returns three values
/// that tell you the amounts of red, green, and blue components in the given color. The argument
/// must be a legal color value, i.e., 0 through COLORS()-1, inclusive. The values that are returned
/// are in the range 0 (no component) through 1000 (maximum amount of component), inclusive.
///
/// ```rust
/// use crosscurses::{can_change_color, color_content, endwin, init_color, initscr, start_color};
///
/// initscr();
/// start_color();
/// if can_change_color() {
///     init_color(8, 35, 502, 1000);
///     let (r, g, b) = color_content(8);
///     assert_eq!(35, r);
///     assert_eq!(502, g);
///     assert_eq!(1000, b);
/// }
/// endwin();
/// ```
pub fn color_content(color_number: i16) -> (i16, i16, i16) {
    let mut r: i16 = 0;
    let mut g: i16 = 0;
    let mut b: i16 = 0;
    unsafe {
        curses::color_content(color_number, &mut r, &mut g, &mut b);
    }
    (r, g, b)
}

/// Alters the appearance of the cursor.
///
/// A visibility of 0 makes it disappear; 1 makes it appear "normal" (usually an underline) and 2
/// makes it "highly visible" (usually a block).
pub fn curs_set(visibility: i32) -> i32 {
    unsafe { curses::curs_set(visibility) }
}

/// Save the current terminal modes as the "program" (in curses) state for use by the
/// `reset_prog_mode()` and `reset_shell_mode()` functions.  This is done automatically by initscr().
pub fn def_prog_mode() -> i32 {
    unsafe { curses::def_prog_mode() }
}

/// Save the current terminal modes as the "shell" (not in curses) state for use by the
/// `reset_prog_mode()` and `reset_shell_mode()` functions.  This is done automatically by initscr().
pub fn def_shell_mode() -> i32 {
    unsafe { curses::def_shell_mode() }
}

/// Inserts an 'milliseconds' millisecond pause in output. This routine should not be used extensively
/// because padding characters are used rather than a CPU pause. If no padding character is
/// specified, this uses napms to perform the delay.
pub fn delay_output(milliseconds: i32) -> i32 {
    unsafe { curses::delay_output(milliseconds) }
}

/// Frees storage associated with the SCREEN data structure.
///
/// The endwin routine does not do this, so delscreen should be called after endwin if a particular
/// SCREEN is no longer needed.
///
/// In PDCurses, the parameter must be the value of SP, and delscreen() sets SP to NULL.
pub fn delscreen(screen: ScrPtr) {
    unsafe { curses::delscreen(screen) }
}

/// Compares the virtual screen to the physical screen and performs an update of the physical
/// screen.
pub fn doupdate() -> i32 {
    unsafe { curses::doupdate() }
}

/// Enabled echoing typed characters.
///
/// Initially, input characters are echoed. Subsequent calls to echo() and noecho() do not flush
/// type-ahead.
pub fn echo() -> i32 {
    unsafe { curses::echo() }
}

/// Should be called before exiting or escaping from curses mode temporarily.
///
/// It will restore tty modes, move the cursor to the lower left corner of the screen and reset the
/// terminal into the proper non-visual mode.  To resume curses after a temporary escape, call
/// refresh() or doupdate().
pub fn endwin() -> i32 {
    unsafe { curses::endwin() }
}

/// Flashes the screen, if possible; if not, it calls beep().
pub fn flash() -> i32 {
    unsafe { curses::flash() }
}

/// Throws away any type-ahead that has been typed by the user and has not yet been read by the
/// program.
pub fn flushinp() -> i32 {
    unsafe { curses::flushinp() }
}

/// Returns the current mouse status in an MEVENT struct.
pub fn getmouse() -> Result<MEVENT, i32> {
    platform_specific::_getmouse()
}

/// Similar to cbreak(), but allows for a time limit to be specified, in tenths of a second.
///
/// This causes getch() to block for that period before returning None if no key has been received.
/// tenths must be between 1 and 255.
pub fn half_delay(tenths: i32) -> i32 {
    unsafe { curses::halfdelay(tenths) }
}

/// Indicates if the terminal supports, and can maniplulate color.
pub fn has_colors() -> bool {
    unsafe { curses::has_colors() > 0 }
}

/// Initialize the curses system, this must be the first function that is called.
///
/// Returns a Window struct that is used to access Window specific functions.
pub fn initscr() -> Window {
    platform_specific::pre_init();
    let window_pointer = unsafe { curses::initscr() };
    window::new_window(window_pointer, true)
}

/// Returns the default Window.
pub fn stdscr() -> Window {
    let window_pointer = platform_specific::_stdscr();
    window::new_window(window_pointer, true)
}

/// Changes the definition of a color. It takes four arguments: the number of the color to be
/// changed followed by three RGB values (for the amounts of red, green, and blue components).
/// The first argument must be a legal color value; default colors are not allowed here.
/// Each of the last three arguments must be a value in the range 0 through 1000. When `init_color`
/// is used, all occurrences of that color on the screen immediately change to the new definition.
pub fn init_color(color_number: i16, red: i16, green: i16, blue: i16) -> i32 {
    unsafe { curses::init_color(color_number, red, green, blue) }
}

/// Changes the definition of a color-pair.
///
/// It takes three arguments: the number of the color-pair to be redefined, and the new values of
/// the foreground and background colors. The pair number must be between 0 and `COLOR_PAIRS` - 1,
/// inclusive. The foreground and background must be between 0 and `COLORS()` - 1, inclusive. If the
/// color pair was previously initialized, the screen is refreshed, and all occurrences of that
/// color-pair are changed to the new definition.
pub fn init_pair(pair_index: i16, foreground_color: i16, background_color: i16) -> i32 {
    unsafe { curses::init_pair(pair_index, foreground_color, background_color) as i32 }
}

/// Sets the timeout for a mouse click.
///
/// Sets the maximum time (in thousands of a second) that can elapse between press and release
/// events for them to be recognized as aclick. Use mouseinterval(0) to disable click resolution.
/// This function returns the previous interval value. Use mouseinterval(-1) to obtain the interval
/// without altering it. The default is one sixth of a second.
pub fn mouseinterval(interval: i32) -> i32 {
    unsafe { curses::mouseinterval(interval) }
}

/// Set the mouse events to be reported.
///
/// By default, no mouse events are reported. The function will return a mask to indicate which of
/// the specified mouse events can be reported; on complete failure it returns 0. If oldmask is
/// non-NULL, this function fills the indicated location with the previous value of the given
/// window's mouse event mask.
///
/// As a side effect, setting a zero mousemask may turn off the mouse pointer; setting a nonzero
/// mask may turn it on. Whether this happens is device-dependent.
pub fn mousemask(newmask: mmask_t, oldmask: *mut mmask_t) -> mmask_t {
    unsafe { curses::mousemask(newmask, oldmask) }
}

/// Returns a character string corresponding to the key `code`.
///
/// * Printable characters are displayed as themselves, e.g., a one-character string containing the
///   key.
/// * Control characters are displayed in the ^X notation.
/// * DEL (character 127) is displayed as ^?.
/// * Values above 128 are either meta characters (if the screen has not been initialized, or if
///   meta has been called with a TRUE parameter), shown in the M-X notation, or are displayed as
///   themselves. In the latter case, the values may not be printable; this follows the X/Open
///   specification.
/// * Values above 256 may be the names of the names of function keys.
/// * Otherwise (if there is no corresponding name) the function returns `None`, to denote an
///   error. X/Open also lists an "UNKNOWN KEY" return value, which some implementations return
///   rather than `None`.
pub fn keyname(code: i32) -> Option<String> {
    platform_specific::_keyname(code)
}

/// Suspends the program for the specified number of milliseconds.
pub fn napms(ms: i32) -> i32 {
    unsafe { curses::napms(ms) }
}

/// A program that outputs to more than one terminal should use the newterm routine for each
/// terminal instead of initscr.
///
/// A program that needs to inspect capabilities, so it can continue to
/// run in a line-oriented mode if the terminal cannot support a screen-oriented program, would also
/// use newterm. The routine newterm should be called once for each terminal. It returns a variable
/// of type `ScrPtr` which should be saved as a reference to that terminal.
///
/// (For the PDCurses backend it's just an alternative interface for initscr(). It always returns
/// SP, or NULL.)
pub fn newterm(t: Option<&str>, output: FILE, input: FILE) -> ScrPtr {
    platform_specific::pre_init();
    let term_type = t.map(|x| CString::new(x).unwrap());
    let type_ptr = match term_type {
        Some(ref s) => s.as_ptr(),
        _ => std::ptr::null(),
    };
    unsafe { curses::newterm(type_ptr, output, input) }
}

/// Creates a new window with the given number of lines, nlines and columns, ncols.
///
/// The upper left corner of the window is at line begy, column begx. If nlines is zero, it
/// defaults to LINES - begy; ncols to COLS - begx. Create a new full-screen window by calling
/// newwin(0, 0, 0, 0).
pub fn newwin(nlines: i32, ncols: i32, begy: i32, begx: i32) -> Window {
    let window_pointer = unsafe { curses::newwin(nlines, ncols, begy, begx) };
    window::new_window(window_pointer, false)
}

/// Enables the translation of a carriage return into a newline on input.
///
/// nonl() disables this. Initially, the translation does occur.
pub fn nl() -> i32 {
    unsafe { curses::nl() }
}

/// Set nocbreak mode.
///
/// In cbreak mode, characters typed by the user are made available immediately, and erase/kill
/// character processing is not performed.  In nocbreak mode, typed characters are buffered until
/// a newline or carriage return. Interrupt and flow control characters are unaffected by this
/// mode.
pub fn nocbreak() -> i32 {
    unsafe { curses::nocbreak() }
}

/// Disables echoing typed characters.
///
/// Initially, input characters are echoed. Subsequent calls to echo() and noecho() do not flush
/// type-ahead.
pub fn noecho() -> i32 {
    unsafe { curses::noecho() }
}

/// Disables the translation of a carriage return into a newline on input.
///
/// nl() enables this. Initially, the translation does occur.
pub fn nonl() -> i32 {
    unsafe { curses::nonl() }
}

/// Disable raw mode.
///
/// Raw mode is similar to cbreak mode, in that characters typed are immediately passed through to
/// the user program. The difference is that in raw mode, the INTR, QUIT, SUSP, and STOP characters
/// are passed through without being interpreted, and without generating a signal.
pub fn noraw() -> i32 {
    unsafe { curses::noraw() }
}

/// Enable raw mode.
///
/// Raw mode is similar to cbreak mode, in that characters typed are immediately passed through to
/// the user program. The difference is that in raw mode, the INTR, QUIT, SUSP, and STOP characters
/// are passed through without being interpreted, and without generating a signal.
pub fn raw() -> i32 {
    unsafe { curses::raw() }
}

/// Restore the terminal to "program" (in curses) state. This is done
/// automatically by endwin() and doupdate() after an endwin(), so this would normally not be
/// called before.
pub fn reset_prog_mode() -> i32 {
    unsafe { curses::reset_prog_mode() }
}

/// Restore the terminal to "shell" (not in curses) state. This is done automatically by
/// endwin() and doupdate() after an endwin(), so this would normally not be called before.
pub fn reset_shell_mode() -> i32 {
    unsafe { curses::reset_shell_mode() }
}

/// Attempts to resize the screen to the given size.
///
/// `resize_term()` is effectively two functions: When called with nonzero values for nlines and
/// ncols, it attempts to resize the screen to the given size. When called with (0, 0), it merely
/// adjusts the internal structures to match the current size after the screen is resized by the
/// user. If you want to support user resizing, you should check for getch() returning `KEY_RESIZE`,
/// and/or call `is_termresized()` at appropriate times; if either condition occurs, call
/// `resize_term(0, 0)`. Then, with either user or programmatic resizing, you'll have to resize any
/// windows you've created.
pub fn resize_term(nlines: i32, ncols: i32) -> i32 {
    platform_specific::_resize_term(nlines, ncols)
}

/// Toggles whether the `A_BLINK` attribute sets an actual blink mode (TRUE), or sets the background
/// color to high intensity (FALSE).
///
/// The default is platform-dependent (FALSE in most cases). It returns OK if it could set the
/// state to match the given parameter, ERR otherwise. Current platforms also adjust the value
/// of COLORS() according to this function -- 16 for FALSE, and 8 for TRUE.
/// (Only supported on Windows)
pub fn set_blink(enabled: bool) -> i32 {
    platform_specific::_set_blink(enabled)
}

/// Switches between different terminals.
///
/// The screen reference new becomes the new current terminal. The previous terminal is returned by
/// the routine. This is the only routine which manipulates ScrPtr's; all other routines  affect
/// only the current terminal.
///
/// (Does nothing meaningful in PDCurses, but is included for compatibility with other curses
/// implementations.)
pub fn set_term(new: ScrPtr) -> ScrPtr {
    unsafe { curses::set_term(new) }
}

/// Sets the title of the window in which the curses program is running. This function may not do
/// anything on some platforms. (Only supported on Windows)
pub fn set_title(title: &str) {
    platform_specific::_set_title(title);
}

/// Initializes eight basic colors (black, red, green, yellow, blue, magenta, cyan,
/// and white), and two global variables accessed through `COLORS()` and `COLOR_PAIRS()` (respectively defining the
/// maximum number of colors and color-pairs the terminal is capable of displaying).
pub fn start_color() -> i32 {
    unsafe { curses::start_color() as i32 }
}

/// Allows the use of -1 as a foreground or background color with `init_pair()`.
///
/// Calls `assume_default_colors(-1, -1);` -1 represents the foreground or background color that
/// the terminal had at startup.
pub fn use_default_colors() -> i32 {
    unsafe { curses::use_default_colors() }
}