Skip to content

Commit

Permalink
Merge pull request #15 from jn-albert/feature/additional-events
Browse files Browse the repository at this point in the history
Add numerous events and input display example
  • Loading branch information
hecrj committed Apr 27, 2019
2 parents f59b8f4 + 36be311 commit 3e8fd0d
Show file tree
Hide file tree
Showing 4 changed files with 337 additions and 1 deletion.
256 changes: 256 additions & 0 deletions examples/input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
//! A simple example that demonstrates capturing window and input events.
use coffee::graphics::{
Batch, Color, Font, Gpu, Image, Point, Rectangle, Sprite, Text, Window,
WindowSettings,
};
use coffee::input;
use coffee::load::{loading_screen, Join, LoadingScreen, Task};
use coffee::{Game, Result, Timer};

use std::collections::HashMap;

fn main() -> Result<()> {
InputExample::run(WindowSettings {
title: String::from("Input Example - Coffee"),
size: (720, 240),
resizable: false,
})
}

struct Input {
cursor_position: Point,
mouse_wheel: Point,
key_state: HashMap<input::KeyCode, bool>,
mouse_state: HashMap<input::MouseButton, bool>,
text_buffer: String,
}

impl Input {
fn new() -> Input {
Input {
cursor_position: Point::new(0.0, 0.0),
mouse_wheel: Point::new(0.0, 0.0),
key_state: HashMap::new(),
mouse_state: HashMap::new(),
text_buffer: String::new(),
}
}
}

struct View {
palette: Image,
font: Font,
}

impl View {
const COLORS: [Color; 1] = [Color {
r: 1.0,
g: 0.0,
b: 0.0,
a: 1.0,
}];

fn load() -> Task<View> {
(
Task::using_gpu(|gpu| Image::from_colors(gpu, &Self::COLORS)),
Font::load(include_bytes!(
"../resources/font/Inconsolata-Regular.ttf"
)),
)
.join()
.map(|(palette, font)| View { palette, font })
}
}

struct InputExample {
mouse_x: f32,
mouse_y: f32,
wheel_x: f32,
wheel_y: f32,
text_buffer: String,
keys_down: String,
mousebuttons_down: String,
}

impl InputExample {
const MAX_TEXTSIZE: usize = 40;
}

impl Game for InputExample {
type View = View;
type Input = Input;

const TICKS_PER_SECOND: u16 = 10;

fn new(
window: &mut Window,
) -> Result<(InputExample, Self::View, Self::Input)> {
let task = Task::stage("Loading font...", View::load());

let mut loading_screen = loading_screen::ProgressBar::new(window.gpu());
let view = loading_screen.run(task, window)?;

Ok((
InputExample {
mouse_x: 0.0,
mouse_y: 0.0,
wheel_x: 0.0,
wheel_y: 0.0,
text_buffer: String::with_capacity(Self::MAX_TEXTSIZE),
keys_down: String::new(),
mousebuttons_down: String::new(),
},
view,
Input::new(),
))
}

fn on_input(&self, input: &mut Input, event: input::Event) {
match event {
input::Event::CursorMoved { x, y } => {
input.cursor_position = Point::new(x, y);
}
input::Event::TextInput { character } => {
input.text_buffer.push(character);
}
input::Event::MouseWheel { delta_x, delta_y } => {
input.mouse_wheel = Point::new(delta_x, delta_y);
}
input::Event::KeyboardInput { key_code, state } => {
input.key_state.insert(
key_code,
match state {
input::ButtonState::Pressed => true,
input::ButtonState::Released => false,
},
);
}
input::Event::MouseInput { state, button } => {
input.mouse_state.insert(
button,
match state {
input::ButtonState::Pressed => true,
input::ButtonState::Released => false,
},
);
}
_ => {}
}
}

fn update(&mut self, _view: &Self::View, _window: &Window) {}

fn interact(
&mut self,
input: &mut Input,
_view: &mut View,
_gpu: &mut Gpu,
) {
self.mouse_x = input.cursor_position.x;
self.mouse_y = input.cursor_position.y;

self.wheel_x = input.mouse_wheel.x;
self.wheel_y = input.mouse_wheel.y;

if !input.text_buffer.is_empty() {
for c in input.text_buffer.chars() {
match c {
// Match ASCII backspace and delete from the text buffer
'\u{0008}' => {
self.text_buffer.pop();
}
_ => {
if self.text_buffer.chars().count() < Self::MAX_TEXTSIZE
{
self.text_buffer.push_str(&input.text_buffer);
}
}
}
}
input.text_buffer.clear();
}

self.keys_down = input
.key_state
.iter()
.filter(|(_, &v)| v == true)
.map(|(k, _)| format!("{:?}", k))
.collect::<Vec<_>>()
.join(", ");

self.mousebuttons_down = input
.mouse_state
.iter()
.filter(|(_, &v)| v == true)
.map(|(k, _)| format!("{:?}", k))
.collect::<Vec<_>>()
.join(", ");
}

fn draw(&self, view: &mut Self::View, window: &mut Window, _timer: &Timer) {
let mut frame = window.frame();
frame.clear(Color::BLACK);

// This closure simplifies some of the boilerplate.
let mut add_aligned_text =
|label: String, content: String, x: f32, y: f32| {
view.font.add(Text {
content: label,
position: Point::new(x, y),
bounds: (frame.width(), frame.height()),
size: 20.0,
color: Color::WHITE,
});
view.font.add(Text {
content: content,
position: Point::new(x + 260.0, y),
bounds: (frame.width(), frame.height()),
size: 20.0,
color: Color::WHITE,
});
};

add_aligned_text(
String::from("Pressed keys:"),
self.keys_down.clone(),
20.0,
20.0,
);

add_aligned_text(
String::from("Text Buffer (type):"),
self.text_buffer.clone(),
20.0,
50.0,
);

add_aligned_text(
String::from("Pressed mouse buttons:"),
self.mousebuttons_down.clone(),
20.0,
80.0,
);

add_aligned_text(
String::from("Last mouse wheel scroll:"),
format!("{}, {}", self.wheel_x, self.wheel_y),
20.0,
110.0,
);

view.font.draw(&mut frame);

let mut batch = Batch::new(view.palette.clone());
// Draw a small square at the mouse cursor's position.
batch.add(Sprite {
source: Rectangle {
x: 0,
y: 0,
width: 6,
height: 6,
},
position: Point::new(self.mouse_x - 3.0, self.mouse_y - 3.0),
});
batch.draw(Point::new(0.0, 0.0), &mut frame.as_target());
}
}
35 changes: 34 additions & 1 deletion src/graphics/window/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub(crate) enum Event {
Resized(winit::dpi::LogicalSize),
Input(input::Event),
CursorMoved(winit::dpi::LogicalPosition),
Moved(winit::dpi::LogicalPosition),
}

pub struct EventLoop(winit::EventsLoop);
Expand Down Expand Up @@ -46,15 +47,47 @@ impl EventLoop {
state,
button,
})),
winit::WindowEvent::MouseWheel { delta, .. } => match delta
{
winit::MouseScrollDelta::LineDelta(x, y) => {
f(Event::Input(input::Event::MouseWheel {
delta_x: x,
delta_y: y,
}))
}
_ => {}
},

winit::WindowEvent::ReceivedCharacter(codepoint) => {
f(Event::Input(input::Event::TextInput {
character: codepoint,
}))
}
winit::WindowEvent::CursorMoved { position, .. } => {
f(Event::CursorMoved(position))
}
winit::WindowEvent::CloseRequested => {
winit::WindowEvent::CursorEntered { .. } => {
f(Event::Input(input::Event::CursorEntered))
}
winit::WindowEvent::CursorLeft { .. } => {
f(Event::Input(input::Event::CursorLeft))
}
winit::WindowEvent::CloseRequested { .. } => {
f(Event::CloseRequested)
}
winit::WindowEvent::Resized(logical_size) => {
f(Event::Resized(logical_size))
}
winit::WindowEvent::Focused(focus) => {
f(Event::Input(if focus == true {
input::Event::WindowFocused
} else {
input::Event::WindowUnfocused
}))
}
winit::WindowEvent::Moved(position) => {
f(Event::Moved(position))
}
_ => {}
},
_ => (),
Expand Down
36 changes: 36 additions & 0 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ pub enum Event {
key_code: KeyCode,
},

/// Text was entered.
TextInput {
/// The character entered
character: char,
},

/// The mouse cursor was moved
CursorMoved {
/// The X coordinate of the mouse position
Expand All @@ -38,6 +44,12 @@ pub enum Event {
y: f32,
},

/// The mouse cursor entered the game window.
CursorEntered,

/// The mouse cursor left the game window.
CursorLeft,

/// A mouse button was pressed or released.
MouseInput {
/// The state of the button
Expand All @@ -46,4 +58,28 @@ pub enum Event {
/// The button identifier
button: MouseButton,
},

/// The mouse wheel was scrolled.
MouseWheel {
/// The number of horizontal lines scrolled
delta_x: f32,

/// The number of vertical lines scrolled
delta_y: f32,
},

/// The game window gained focus.
WindowFocused,

/// The game window lost focus.
WindowUnfocused,

/// The game window was moved.
WindowMoved {
/// The new X coordinate of the window
x: f32,

/// The new Y coordinate of the window
y: f32,
},
}
11 changes: 11 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,17 @@ pub trait Game {
},
)
}
window::Event::Moved(logical_position) => {
let position = logical_position.to_physical(window.dpi());

game.on_input(
input,
input::Event::WindowMoved {
x: position.x as f32,
y: position.y as f32,
},
)
}
window::Event::CloseRequested => {
if game.on_close_request(input) {
*alive = false;
Expand Down

0 comments on commit 3e8fd0d

Please sign in to comment.