mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-24 01:46:31 +00:00
Produce mouse events from BLT backend
This commit is contained in:
parent
acd12326e1
commit
5f3e4b1842
@ -5,147 +5,25 @@ use self::bear_lib_terminal::geometry::Size;
|
|||||||
use self::bear_lib_terminal::terminal::{self, state, Event as BltEvent,
|
use self::bear_lib_terminal::terminal::{self, state, Event as BltEvent,
|
||||||
KeyCode};
|
KeyCode};
|
||||||
use backend;
|
use backend;
|
||||||
use event::{Event, Key};
|
use event::{Event, Key, MouseButton, MouseEvent};
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use theme::{BaseColor, Color, ColorPair, Effect};
|
use theme::{BaseColor, Color, ColorPair, Effect};
|
||||||
|
use vec::Vec2;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
enum ColorRole {
|
enum ColorRole {
|
||||||
Foreground,
|
Foreground,
|
||||||
Background,
|
Background,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Concrete {}
|
pub struct Concrete {
|
||||||
|
mouse_position: Vec2,
|
||||||
impl backend::Backend for Concrete {
|
buttons_pressed: HashSet<MouseButton>,
|
||||||
fn init() -> Self {
|
|
||||||
terminal::open("Cursive", 80, 24);
|
|
||||||
terminal::set(terminal::config::Window::empty().resizeable(true));
|
|
||||||
|
|
||||||
Concrete {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finish(&mut self) {
|
|
||||||
terminal::close();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_color<F: FnOnce()>(&self, color: ColorPair, f: F) {
|
|
||||||
let fg = colour_to_blt_colour(color.front, ColorRole::Foreground);
|
|
||||||
let bg = colour_to_blt_colour(color.back, ColorRole::Background);
|
|
||||||
terminal::with_colors(fg, bg, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
|
|
||||||
match effect {
|
|
||||||
Effect::Simple => f(),
|
|
||||||
// TODO: how to do this correctly?`
|
|
||||||
// BLT itself doesn't do this kind of thing,
|
|
||||||
// we'd need the colours in our position,
|
|
||||||
// but `f()` can do whatever
|
|
||||||
Effect::Reverse => terminal::with_colors(
|
|
||||||
BltColor::from_rgb(0, 0, 0),
|
|
||||||
BltColor::from_rgb(255, 255, 255),
|
|
||||||
f,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_colors(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn screen_size(&self) -> (usize, usize) {
|
|
||||||
let Size { width, height } = terminal::state::size();
|
|
||||||
(width as usize, height as usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear(&self, color: Color) {
|
|
||||||
terminal::set_background(
|
|
||||||
colour_to_blt_colour(color, ColorRole::Background),
|
|
||||||
);
|
|
||||||
terminal::clear(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn refresh(&mut self) {
|
|
||||||
terminal::refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_at(&self, (x, y): (usize, usize), text: &str) {
|
|
||||||
terminal::print_xy(x as i32, y as i32, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_refresh_rate(&mut self, _: u32) {
|
|
||||||
// TODO: unsupported
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_event(&mut self) -> Event {
|
|
||||||
// TODO: we could add backend-specific controls here.
|
|
||||||
// Ex: ctrl+mouse wheel cause window cellsize to change
|
|
||||||
if let Some(ev) = terminal::wait_event() {
|
|
||||||
match ev {
|
|
||||||
BltEvent::Close => Event::Exit,
|
|
||||||
BltEvent::Resize { .. } => Event::WindowResize,
|
|
||||||
// TODO: mouse support
|
|
||||||
BltEvent::MouseMove { .. } => Event::Refresh,
|
|
||||||
BltEvent::MouseScroll { .. } => Event::Refresh,
|
|
||||||
BltEvent::KeyPressed { key, ctrl, shift } => {
|
|
||||||
blt_keycode_to_ev(key, shift, ctrl)
|
|
||||||
}
|
|
||||||
// TODO: there's no Key::Shift/Ctrl for w/e reason
|
|
||||||
BltEvent::ShiftPressed => Event::Refresh,
|
|
||||||
BltEvent::ControlPressed => Event::Refresh,
|
|
||||||
// TODO: what should we do here?
|
|
||||||
BltEvent::KeyReleased { .. } |
|
|
||||||
BltEvent::ShiftReleased |
|
|
||||||
BltEvent::ControlReleased => Event::Refresh,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Event::Refresh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn colour_to_blt_colour(clr: Color, role: ColorRole) -> BltColor {
|
impl Concrete {
|
||||||
let (r, g, b) = match clr {
|
fn blt_keycode_to_ev(
|
||||||
Color::TerminalDefault => {
|
&mut self, kc: KeyCode, shift: bool, ctrl: bool
|
||||||
let clr = match role {
|
) -> Event {
|
||||||
ColorRole::Foreground => state::foreground(),
|
|
||||||
ColorRole::Background => state::background(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return clr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Colours taken from
|
|
||||||
// https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
|
|
||||||
Color::Dark(BaseColor::Black) => (0, 0, 0),
|
|
||||||
Color::Dark(BaseColor::Red) => (170, 0, 0),
|
|
||||||
Color::Dark(BaseColor::Green) => (0, 170, 0),
|
|
||||||
Color::Dark(BaseColor::Yellow) => (170, 85, 0),
|
|
||||||
Color::Dark(BaseColor::Blue) => (0, 0, 170),
|
|
||||||
Color::Dark(BaseColor::Magenta) => (170, 0, 170),
|
|
||||||
Color::Dark(BaseColor::Cyan) => (0, 170, 170),
|
|
||||||
Color::Dark(BaseColor::White) => (170, 170, 170),
|
|
||||||
|
|
||||||
Color::Light(BaseColor::Black) => (85, 85, 85),
|
|
||||||
Color::Light(BaseColor::Red) => (255, 85, 85),
|
|
||||||
Color::Light(BaseColor::Green) => (85, 255, 85),
|
|
||||||
Color::Light(BaseColor::Yellow) => (255, 255, 85),
|
|
||||||
Color::Light(BaseColor::Blue) => (85, 85, 255),
|
|
||||||
Color::Light(BaseColor::Magenta) => (255, 85, 255),
|
|
||||||
Color::Light(BaseColor::Cyan) => (85, 255, 255),
|
|
||||||
Color::Light(BaseColor::White) => (255, 255, 255),
|
|
||||||
|
|
||||||
Color::Rgb(r, g, b) => (r, g, b),
|
|
||||||
Color::RgbLowRes(r, g, b) => (
|
|
||||||
(r as f32 / 5.0 * 255.0) as u8,
|
|
||||||
(g as f32 / 5.0 * 255.0) as u8,
|
|
||||||
(b as f32 / 5.0 * 255.0) as u8,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
BltColor::from_rgb(r, g, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn blt_keycode_to_ev(kc: KeyCode, shift: bool, ctrl: bool) -> Event {
|
|
||||||
match kc {
|
match kc {
|
||||||
KeyCode::F1 |
|
KeyCode::F1 |
|
||||||
KeyCode::F2 |
|
KeyCode::F2 |
|
||||||
@ -185,7 +63,16 @@ fn blt_keycode_to_ev(kc: KeyCode, shift: bool, ctrl: bool) -> Event {
|
|||||||
KeyCode::MouseRight |
|
KeyCode::MouseRight |
|
||||||
KeyCode::MouseMiddle |
|
KeyCode::MouseMiddle |
|
||||||
KeyCode::MouseFourth |
|
KeyCode::MouseFourth |
|
||||||
KeyCode::MouseFifth => Event::Refresh,
|
KeyCode::MouseFifth => blt_keycode_to_mouse_button(kc)
|
||||||
|
.map(|btn| {
|
||||||
|
self.buttons_pressed.insert(btn);
|
||||||
|
Event::Mouse {
|
||||||
|
event: MouseEvent::Press(btn),
|
||||||
|
position: self.mouse_position,
|
||||||
|
offset: Vec2::zero(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(Event::Unknown(vec![])),
|
||||||
KeyCode::A |
|
KeyCode::A |
|
||||||
KeyCode::B |
|
KeyCode::B |
|
||||||
KeyCode::C |
|
KeyCode::C |
|
||||||
@ -254,6 +141,181 @@ fn blt_keycode_to_ev(kc: KeyCode, shift: bool, ctrl: bool) -> Event {
|
|||||||
Event::Char(blt_keycode_to_char(kc, shift))
|
Event::Char(blt_keycode_to_char(kc, shift))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl backend::Backend for Concrete {
|
||||||
|
fn init() -> Self {
|
||||||
|
terminal::open("Cursive", 80, 24);
|
||||||
|
terminal::set(terminal::config::Window::empty().resizeable(true));
|
||||||
|
terminal::set(vec![
|
||||||
|
terminal::config::InputFilter::Group {
|
||||||
|
group: terminal::config::InputFilterGroup::Keyboard,
|
||||||
|
both: false,
|
||||||
|
},
|
||||||
|
terminal::config::InputFilter::Group {
|
||||||
|
group: terminal::config::InputFilterGroup::Mouse,
|
||||||
|
both: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
Concrete {
|
||||||
|
mouse_position: Vec2::zero(),
|
||||||
|
buttons_pressed: HashSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish(&mut self) {
|
||||||
|
terminal::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_color<F: FnOnce()>(&self, color: ColorPair, f: F) {
|
||||||
|
let fg = colour_to_blt_colour(color.front, ColorRole::Foreground);
|
||||||
|
let bg = colour_to_blt_colour(color.back, ColorRole::Background);
|
||||||
|
terminal::with_colors(fg, bg, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
|
||||||
|
match effect {
|
||||||
|
Effect::Simple => f(),
|
||||||
|
// TODO: how to do this correctly?`
|
||||||
|
// BLT itself doesn't do this kind of thing,
|
||||||
|
// we'd need the colours in our position,
|
||||||
|
// but `f()` can do whatever
|
||||||
|
Effect::Reverse => terminal::with_colors(
|
||||||
|
BltColor::from_rgb(0, 0, 0),
|
||||||
|
BltColor::from_rgb(255, 255, 255),
|
||||||
|
f,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_colors(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn screen_size(&self) -> (usize, usize) {
|
||||||
|
let Size { width, height } = terminal::state::size();
|
||||||
|
(width as usize, height as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&self, color: Color) {
|
||||||
|
terminal::set_background(
|
||||||
|
colour_to_blt_colour(color, ColorRole::Background),
|
||||||
|
);
|
||||||
|
terminal::clear(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn refresh(&mut self) {
|
||||||
|
terminal::refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_at(&self, (x, y): (usize, usize), text: &str) {
|
||||||
|
terminal::print_xy(x as i32, y as i32, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_refresh_rate(&mut self, _: u32) {
|
||||||
|
// TODO: unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_event(&mut self) -> Event {
|
||||||
|
// TODO: we could add backend-specific controls here.
|
||||||
|
// Ex: ctrl+mouse wheel cause window cellsize to change
|
||||||
|
if let Some(ev) = terminal::wait_event() {
|
||||||
|
match ev {
|
||||||
|
BltEvent::Close => Event::Exit,
|
||||||
|
BltEvent::Resize { .. } => Event::WindowResize,
|
||||||
|
// TODO: mouse support
|
||||||
|
BltEvent::MouseMove { x, y } => {
|
||||||
|
self.mouse_position = Vec2::new(x as usize, y as usize);
|
||||||
|
// TODO: find out if a button is pressed?
|
||||||
|
match self.buttons_pressed.iter().next() {
|
||||||
|
None => Event::Refresh,
|
||||||
|
Some(btn) => Event::Mouse {
|
||||||
|
event: MouseEvent::Hold(*btn),
|
||||||
|
position: self.mouse_position,
|
||||||
|
offset: Vec2::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BltEvent::MouseScroll { delta } => Event::Mouse {
|
||||||
|
event: if delta < 0 {
|
||||||
|
MouseEvent::WheelUp
|
||||||
|
} else {
|
||||||
|
MouseEvent::WheelDown
|
||||||
|
},
|
||||||
|
position: self.mouse_position,
|
||||||
|
offset: Vec2::zero(),
|
||||||
|
},
|
||||||
|
BltEvent::KeyPressed { key, ctrl, shift } => {
|
||||||
|
self.blt_keycode_to_ev(key, shift, ctrl)
|
||||||
|
}
|
||||||
|
// TODO: there's no Key::Shift/Ctrl for w/e reason
|
||||||
|
BltEvent::ShiftPressed => Event::Refresh,
|
||||||
|
BltEvent::ControlPressed => Event::Refresh,
|
||||||
|
// TODO: what should we do here?
|
||||||
|
BltEvent::KeyReleased { key, .. } => {
|
||||||
|
// It's probably a mouse key.
|
||||||
|
blt_keycode_to_mouse_button(key)
|
||||||
|
.map(|btn| {
|
||||||
|
self.buttons_pressed.remove(&btn);
|
||||||
|
Event::Mouse {
|
||||||
|
event: MouseEvent::Release(btn),
|
||||||
|
position: self.mouse_position,
|
||||||
|
offset: Vec2::zero(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(Event::Unknown(vec![]))
|
||||||
|
}
|
||||||
|
BltEvent::ShiftReleased | BltEvent::ControlReleased => {
|
||||||
|
Event::Refresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Event::Refresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn colour_to_blt_colour(clr: Color, role: ColorRole) -> BltColor {
|
||||||
|
let (r, g, b) = match clr {
|
||||||
|
Color::TerminalDefault => {
|
||||||
|
let clr = match role {
|
||||||
|
ColorRole::Foreground => state::foreground(),
|
||||||
|
ColorRole::Background => state::background(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return clr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Colours taken from
|
||||||
|
// https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
|
||||||
|
Color::Dark(BaseColor::Black) => (0, 0, 0),
|
||||||
|
Color::Dark(BaseColor::Red) => (170, 0, 0),
|
||||||
|
Color::Dark(BaseColor::Green) => (0, 170, 0),
|
||||||
|
Color::Dark(BaseColor::Yellow) => (170, 85, 0),
|
||||||
|
Color::Dark(BaseColor::Blue) => (0, 0, 170),
|
||||||
|
Color::Dark(BaseColor::Magenta) => (170, 0, 170),
|
||||||
|
Color::Dark(BaseColor::Cyan) => (0, 170, 170),
|
||||||
|
Color::Dark(BaseColor::White) => (170, 170, 170),
|
||||||
|
|
||||||
|
Color::Light(BaseColor::Black) => (85, 85, 85),
|
||||||
|
Color::Light(BaseColor::Red) => (255, 85, 85),
|
||||||
|
Color::Light(BaseColor::Green) => (85, 255, 85),
|
||||||
|
Color::Light(BaseColor::Yellow) => (255, 255, 85),
|
||||||
|
Color::Light(BaseColor::Blue) => (85, 85, 255),
|
||||||
|
Color::Light(BaseColor::Magenta) => (255, 85, 255),
|
||||||
|
Color::Light(BaseColor::Cyan) => (85, 255, 255),
|
||||||
|
Color::Light(BaseColor::White) => (255, 255, 255),
|
||||||
|
|
||||||
|
Color::Rgb(r, g, b) => (r, g, b),
|
||||||
|
Color::RgbLowRes(r, g, b) => (
|
||||||
|
(r as f32 / 5.0 * 255.0) as u8,
|
||||||
|
(g as f32 / 5.0 * 255.0) as u8,
|
||||||
|
(b as f32 / 5.0 * 255.0) as u8,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
BltColor::from_rgb(r, g, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blt_keycode_to_char(kc: KeyCode, shift: bool) -> char {
|
fn blt_keycode_to_char(kc: KeyCode, shift: bool) -> char {
|
||||||
@ -545,3 +607,12 @@ fn blt_keycode_to_key(kc: KeyCode) -> Key {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn blt_keycode_to_mouse_button(kc: KeyCode) -> Option<MouseButton> {
|
||||||
|
Some(match kc {
|
||||||
|
KeyCode::MouseLeft => MouseButton::Left,
|
||||||
|
KeyCode::MouseRight => MouseButton::Right,
|
||||||
|
KeyCode::MouseMiddle => MouseButton::Middle,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user