1mod input;
5pub mod config;
6pub mod state;
7
8use std::char;
9use colors::Color;
10use geometry::{Rect, Point, Size};
11use self::config::{ConfigPart, Window};
12use bear_lib_terminal_sys as ffi;
13use bear_lib_terminal_sys::ColorT;
14
15pub use self::input::{Event, KeyCode};
16
17
18pub fn open(title: &str, width: u32, height: u32) {
24 ffi::open();
25 set(Window::empty().size(Size::new(width as i32, height as i32)).title(title.to_string()));
26}
27
28pub fn close() {
32 ffi::close();
33}
34
35pub fn set<T: ConfigPart>(cfg: T) -> bool {
41 ffi::set(&*&cfg.to_config_str())
42}
43
44pub fn refresh() {
48 ffi::refresh();
49}
50
51pub fn clear(area: Option<Rect>) {
59 match area {
60 Some(rect) => ffi::clear_area(rect.top_left.x, rect.top_left.y, rect.size.width, rect.size.height),
61 None => ffi::clear(),
62 }
63}
64
65pub fn crop(rect: Rect) {
69 ffi::crop(rect.top_left.x, rect.top_left.y, rect.size.width, rect.size.height);
70}
71
72pub fn layer(index: i32) {
77 ffi::layer(index);
78}
79
80pub fn set_foreground(color: Color) {
84 ffi::color(to_color_t(color));
85}
86
87pub fn with_foreground<F: FnOnce()>(color: Color, callback: F) {
89 let current = ffi::state_color(ffi::TK_COLOR);
90 set_foreground(color);
91 callback();
92 ffi::color(current);
93}
94
95pub fn set_background(color: Color) {
99 ffi::bkcolor(to_color_t(color));
100}
101
102pub fn with_background<F: FnOnce()>(color: Color, callback: F) {
104 let current = ffi::state_color(ffi::TK_BKCOLOR);
105 set_background(color);
106 callback();
107 ffi::bkcolor(current);
108}
109
110pub fn set_colors(fg: Color, bg: Color) {
114 set_foreground(fg);
115 set_background(bg);
116}
117
118pub fn with_colors<F: FnOnce()>(fg: Color, bg: Color, callback: F) {
120 with_foreground(fg, ||
121 with_background(bg, ||
122 callback()
123 )
124 );
125}
126
127pub fn composition(enable: bool) {
132 ffi::composition(enable);
133}
134
135pub fn put(point: Point, cell: char) {
139 ffi::put(point.x, point.y, cell as i32);
140}
141
142pub fn put_xy(x: i32, y: i32, cell: char) {
144 ffi::put(x, y, cell as i32);
145}
146
147pub fn put_ext(pos: Point, offset: Point, cell: char, corners: &Vec<Color>) {
151 ffi::put_ext(pos.x, pos.y, offset.x, offset.y, cell as i32, &corners.iter().cloned().map(to_color_t).collect::<Vec<_>>()[..]);
152}
153
154pub fn pick(point: Point, index: i32) -> char {
160 char::from_u32(ffi::pick(point.x, point.y, index) as u32).unwrap()
161}
162
163pub fn pick_foreground_color(point: Point, index: i32) -> Color {
168 from_color_t(ffi::pick_color(point.x, point.y, index))
169}
170
171pub fn pick_background_color(point: Point) -> Color {
176 from_color_t(ffi::pick_bkcolor(point.x, point.y))
177}
178
179pub fn print(point: Point, value: &str) {
183 let _ = ffi::print(point.x, point.y, value);
184}
185
186pub fn print_xy(x: i32, y: i32, value: &str) {
188 print(Point::new(x, y), value);
189}
190
191pub fn measure(value: &str) -> i32 {
198 ffi::measure(value)
199}
200
201pub fn has_input() -> bool {
205 ffi::has_input()
206}
207
208pub fn wait_event() -> Option<Event> {
212 to_event(ffi::read())
213}
214
215pub fn events() -> EventIterator {
217 EventIterator
218}
219
220pub fn read_event() -> Option<Event> {
227 if !has_input() {
228 None
229 } else {
230 wait_event()
231 }
232}
233
234pub fn peek_event() -> Option<Event> {
244 match ffi::peek() {
245 0 => None,
246 event => to_event(event),
247 }
248}
249
250pub fn read_str(point: Point, max: i32) -> Option<String> {
262 ffi::read_str(point.x, point.y, max)
263}
264
265pub fn delay(period: i32) {
269 ffi::delay(period)
270}
271
272
273pub struct EventIterator;
295
296impl Iterator for EventIterator {
297 type Item = Event;
298
299 fn next(&mut self) -> Option<Event> {
300 wait_event()
301 }
302}
303
304
305fn from_color_t(color: ColorT) -> Color {
306 let alpha = ((color >> 24) & 0xFF) as u8;
307 let red = ((color >> 16) & 0xFF) as u8;
308 let green = ((color >> 8) & 0xFF) as u8;
309 let blue = (color & 0xFF) as u8;
310
311 Color::from_rgba(red, green, blue, alpha)
312}
313
314fn to_color_t(color: Color) -> ColorT {
315 (
316 ((color.alpha as ColorT) << 24) |
317 ((color.red as ColorT) << 16) |
318 ((color.green as ColorT) << 8) |
319 (color.blue as ColorT)
320 )
321}
322
323fn to_keycode(code: i32) -> Option<KeyCode> {
324 match code {
325 ffi::TK_A => Some(KeyCode::A),
326 ffi::TK_B => Some(KeyCode::B),
327 ffi::TK_C => Some(KeyCode::C),
328 ffi::TK_D => Some(KeyCode::D),
329 ffi::TK_E => Some(KeyCode::E),
330 ffi::TK_F => Some(KeyCode::F),
331 ffi::TK_G => Some(KeyCode::G),
332 ffi::TK_H => Some(KeyCode::H),
333 ffi::TK_I => Some(KeyCode::I),
334 ffi::TK_J => Some(KeyCode::J),
335 ffi::TK_K => Some(KeyCode::K),
336 ffi::TK_L => Some(KeyCode::L),
337 ffi::TK_M => Some(KeyCode::M),
338 ffi::TK_N => Some(KeyCode::N),
339 ffi::TK_O => Some(KeyCode::O),
340 ffi::TK_P => Some(KeyCode::P),
341 ffi::TK_Q => Some(KeyCode::Q),
342 ffi::TK_R => Some(KeyCode::R),
343 ffi::TK_S => Some(KeyCode::S),
344 ffi::TK_T => Some(KeyCode::T),
345 ffi::TK_U => Some(KeyCode::U),
346 ffi::TK_V => Some(KeyCode::V),
347 ffi::TK_W => Some(KeyCode::W),
348 ffi::TK_X => Some(KeyCode::X),
349 ffi::TK_Y => Some(KeyCode::Y),
350 ffi::TK_Z => Some(KeyCode::Z),
351 ffi::TK_1 => Some(KeyCode::Row1),
352 ffi::TK_2 => Some(KeyCode::Row2),
353 ffi::TK_3 => Some(KeyCode::Row3),
354 ffi::TK_4 => Some(KeyCode::Row4),
355 ffi::TK_5 => Some(KeyCode::Row5),
356 ffi::TK_6 => Some(KeyCode::Row6),
357 ffi::TK_7 => Some(KeyCode::Row7),
358 ffi::TK_8 => Some(KeyCode::Row8),
359 ffi::TK_9 => Some(KeyCode::Row9),
360 ffi::TK_0 => Some(KeyCode::Row0),
361 ffi::TK_ENTER => Some(KeyCode::Enter),
362 ffi::TK_ESCAPE => Some(KeyCode::Escape),
363 ffi::TK_BACKSPACE => Some(KeyCode::Backspace),
364 ffi::TK_TAB => Some(KeyCode::Tab),
365 ffi::TK_SPACE => Some(KeyCode::Space),
366 ffi::TK_MINUS => Some(KeyCode::Minus),
367 ffi::TK_EQUALS => Some(KeyCode::Equals),
368 ffi::TK_LBRACKET => Some(KeyCode::LeftBracket),
369 ffi::TK_RBRACKET => Some(KeyCode::RightBracket),
370 ffi::TK_BACKSLASH => Some(KeyCode::Backslash),
371 ffi::TK_SEMICOLON => Some(KeyCode::Semicolon),
372 ffi::TK_APOSTROPHE => Some(KeyCode::Apostrophe),
373 ffi::TK_GRAVE => Some(KeyCode::Grave),
374 ffi::TK_COMMA => Some(KeyCode::Comma),
375 ffi::TK_PERIOD => Some(KeyCode::Period),
376 ffi::TK_SLASH => Some(KeyCode::Slash),
377 ffi::TK_F1 => Some(KeyCode::F1),
378 ffi::TK_F2 => Some(KeyCode::F2),
379 ffi::TK_F3 => Some(KeyCode::F3),
380 ffi::TK_F4 => Some(KeyCode::F4),
381 ffi::TK_F5 => Some(KeyCode::F5),
382 ffi::TK_F6 => Some(KeyCode::F6),
383 ffi::TK_F7 => Some(KeyCode::F7),
384 ffi::TK_F8 => Some(KeyCode::F8),
385 ffi::TK_F9 => Some(KeyCode::F9),
386 ffi::TK_F10 => Some(KeyCode::F10),
387 ffi::TK_F11 => Some(KeyCode::F11),
388 ffi::TK_F12 => Some(KeyCode::F12),
389 ffi::TK_PAUSE => Some(KeyCode::Pause),
390 ffi::TK_INSERT => Some(KeyCode::Insert),
391 ffi::TK_HOME => Some(KeyCode::Home),
392 ffi::TK_PAGEUP => Some(KeyCode::PageUp),
393 ffi::TK_DELETE => Some(KeyCode::Delete),
394 ffi::TK_END => Some(KeyCode::End),
395 ffi::TK_PAGEDOWN => Some(KeyCode::PageDown),
396 ffi::TK_RIGHT => Some(KeyCode::Right),
397 ffi::TK_LEFT => Some(KeyCode::Left),
398 ffi::TK_DOWN => Some(KeyCode::Down),
399 ffi::TK_UP => Some(KeyCode::Up),
400 ffi::TK_KP_DIVIDE => Some(KeyCode::NumDivide),
401 ffi::TK_KP_MULTIPLY => Some(KeyCode::NumMultiply),
402 ffi::TK_KP_MINUS => Some(KeyCode::NumMinus),
403 ffi::TK_KP_PLUS => Some(KeyCode::NumPlus),
404 ffi::TK_KP_ENTER => Some(KeyCode::NumEnter),
405 ffi::TK_KP_1 => Some(KeyCode::Num1),
406 ffi::TK_KP_2 => Some(KeyCode::Num2),
407 ffi::TK_KP_3 => Some(KeyCode::Num3),
408 ffi::TK_KP_4 => Some(KeyCode::Num4),
409 ffi::TK_KP_5 => Some(KeyCode::Num5),
410 ffi::TK_KP_6 => Some(KeyCode::Num6),
411 ffi::TK_KP_7 => Some(KeyCode::Num7),
412 ffi::TK_KP_8 => Some(KeyCode::Num8),
413 ffi::TK_KP_9 => Some(KeyCode::Num9),
414 ffi::TK_KP_0 => Some(KeyCode::Num0),
415 ffi::TK_KP_PERIOD => Some(KeyCode::NumPeriod),
416 ffi::TK_MOUSE_LEFT => Some(KeyCode::MouseLeft),
417 ffi::TK_MOUSE_RIGHT => Some(KeyCode::MouseRight),
418 ffi::TK_MOUSE_MIDDLE => Some(KeyCode::MouseMiddle),
419 ffi::TK_MOUSE_X1 => Some(KeyCode::MouseFourth),
420 ffi::TK_MOUSE_X2 => Some(KeyCode::MouseFifth),
421 _ => None,
422 }
423}
424
425fn to_event(code: i32) -> Option<Event> {
426 match code {
427 ffi::TK_CLOSE => Some(Event::Close),
428 ffi::TK_RESIZED => Some(get_window_resize()),
429 ffi::TK_MOUSE_MOVE => Some(get_mouse_move()),
430 ffi::TK_MOUSE_SCROLL => Some(get_mouse_scroll()),
431 _ => to_key_event(code),
432 }
433}
434
435fn to_key_event(code: i32) -> Option<Event> {
436 let key = code & !ffi::TK_KEY_RELEASED;
437 let released = (code & ffi::TK_KEY_RELEASED) == ffi::TK_KEY_RELEASED;
438
439 match key {
440 ffi::TK_SHIFT => Some(if released {Event::ShiftReleased} else {Event::ShiftPressed}),
441 ffi::TK_CONTROL => Some(if released {Event::ControlReleased} else {Event::ControlPressed}),
442 ffi::TK_ALT => Some(if released {Event::AltReleased} else {Event::AltPressed}),
443 key => {
444 let ctrl = ffi::check(ffi::TK_CONTROL);
445 let shift = ffi::check(ffi::TK_SHIFT);
446
447 match to_keycode(key) {
448 Some(converted) => Some(get_key(released, converted, ctrl, shift)),
449 None => None,
450 }
451 }
452 }
453}
454
455fn get_window_resize() -> Event {
456 Event::Resize{
457 width: ffi::state(ffi::TK_WIDTH),
458 height: ffi::state(ffi::TK_HEIGHT),
459 }
460}
461
462fn get_mouse_move() -> Event {
463 Event::MouseMove{
464 x: ffi::state(ffi::TK_MOUSE_X),
465 y: ffi::state(ffi::TK_MOUSE_Y),
466 }
467}
468
469fn get_mouse_scroll() -> Event {
470 Event::MouseScroll{
471 delta: ffi::state(ffi::TK_MOUSE_WHEEL),
472 }
473}
474
475fn get_key(released: bool, key: KeyCode, ctrl: bool, shift: bool) -> Event {
476 if released {
477 Event::KeyReleased{
478 key: key,
479 ctrl: ctrl,
480 shift: shift,
481 }
482 } else {
483 Event::KeyPressed{
484 key: key,
485 ctrl: ctrl,
486 shift: shift,
487 }
488 }
489}