Finished mouse handling for tile map

This commit is contained in:
Jonathan Johnson 2023-11-26 19:31:03 -08:00
parent 273aac65bb
commit 66fd9ba766
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
3 changed files with 98 additions and 40 deletions

View file

@ -67,7 +67,7 @@ fn main() -> gooey::Result {
let one_second_movement = direction * TILE_SIZE.into_float();
let cursor_pos = input.mouse.pos;
let cursor_pos = input.mouse.as_ref().map(|mouse| mouse.position);
layers.map_mut(|layers| {
let pos = &mut layers.1[myself].position;
@ -76,21 +76,16 @@ fn main() -> gooey::Result {
one_second_movement.y * elapsed.as_secs_f32(),
);
let rect = Rect::new(*pos, Size::new(16., 16.));
let color = match rect.cast().contains(cursor_pos) {
true => Color::RED,
false => Color::BLUE,
};
let rect = Rect::new(*pos - Size::squared(8.), Size::squared(16.));
layers.1[myself].color =
match cursor_pos.map_or(false, |cursor_pos| rect.cast().contains(cursor_pos)) {
true => Color::RED,
false => Color::BLUE,
};
});
}));
Stack::rows(
tilemap
.debug_output(debug_message.clone())
.expand()
.and(Label::new(debug_message)),
)
.run()
Stack::rows(tilemap.expand().and(Label::new(debug_message))).run()
}
#[derive(Debug)]

View file

@ -3,10 +3,11 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, MutexGuard};
use std::time::{Duration, Instant};
use kludgine::app::winit::event::KeyEvent;
use intentional::Assert;
use kludgine::app::winit::event::{ElementState, KeyEvent, MouseButton};
use kludgine::app::winit::keyboard::Key;
use kludgine::figures::Point;
use kludgine::figures::units::Px;
use kludgine::figures::Point;
use crate::context::WidgetContext;
use crate::utils::{IgnorePoison, UnwindsafeCondvar};
@ -51,9 +52,38 @@ impl Tick {
}
}
pub fn set_cursor_position(&self, pos: Point<Px>) {
/// Sets the cursor position.
pub fn set_cursor_position(&self, pos: Option<Point<Px>>) {
let mut state = self.data.state();
state.input.mouse.pos = pos;
match pos {
Some(pos) => {
if state.input.mouse.is_none() {
state.input.mouse = Some(Mouse::default());
}
state
.input
.mouse
.as_mut()
.assert("always initialized")
.position = pos;
}
None => {
state.input.mouse = None;
}
}
}
/// Processes a mouse button event.
pub fn mouse_button(&self, button: MouseButton, button_state: ElementState) {
let mut state = self.data.state();
if let Some(mouse) = &mut state.input.mouse {
if button_state.is_pressed() {
mouse.buttons.insert(button);
} else {
mouse.buttons.remove(&button);
}
}
}
/// Returns a new tick that invokes `tick`, aiming to repeat at the given
@ -70,7 +100,6 @@ impl Tick {
keep_running: true,
frame: 0,
input: InputState::default(),
mouse: None,
}),
period: tick_every,
sync: UnwindsafeCondvar::new(),
@ -119,15 +148,16 @@ impl Tick {
pub struct InputState {
/// A collection of all keys currently pressed.
pub keys: HashSet<Key>,
pub mouse: Mouse,
/// The state of the mouse cursor and any buttons pressed.
pub mouse: Option<Mouse>,
}
#[derive(Debug, Default)]
pub struct Mouse {
pub pos: Point<Px>,
pub position: Point<Px>,
pub buttons: HashSet<MouseButton>,
}
#[derive(Debug)]
struct TickData {
state: Mutex<TickState>,
@ -150,7 +180,6 @@ struct TickState {
keep_running: bool,
frame: usize,
input: InputState,
mouse: Option<Mouse>,
}
fn tick_loop<F>(data: &TickData, mut tick: F)

View file

@ -1,6 +1,8 @@
use std::fmt::Debug;
use intentional::Cast;
use kludgine::app::winit::event::ElementState;
use kludgine::app::winit::window::CursorIcon;
use kludgine::figures::units::Px;
use kludgine::figures::Point;
@ -23,7 +25,6 @@ pub struct TileMap<Layers> {
focus: Value<TileMapFocus>,
zoom: f32,
tick: Option<Tick>,
debug_output: Option<Dynamic<String>>,
}
impl<Layers> TileMap<Layers> {
@ -33,15 +34,9 @@ impl<Layers> TileMap<Layers> {
focus: Value::default(),
zoom: 1.,
tick: None,
debug_output: None,
}
}
pub fn debug_output(mut self, message: Dynamic<String>) -> Self {
self.debug_output = Some(message);
self
}
/// Returns a new tilemap that contains dynamic layers.
pub fn dynamic(layers: Dynamic<Layers>) -> Self {
Self::construct(Value::Dynamic(layers))
@ -126,20 +121,32 @@ where
HANDLED
}
fn hover(&mut self, local: Point<Px>, context: &mut EventContext<'_, '_>) {
let Some(size) = context.last_layout().map(|rect| rect.size) else { return };
let offset = self.layers.map(|layers| self.focus.get().world_coordinate(layers));
let scale = context.kludgine.scale();
let zoom = self.zoom;
let world = tilemap::translate_coordinates(local, offset, scale, zoom, size);
fn hover(
&mut self,
local: Point<Px>,
context: &mut EventContext<'_, '_>,
) -> Option<CursorIcon> {
if let Some(tick) = &self.tick {
tick.set_cursor_position(world);
let Some(size) = context.last_layout().map(|rect| rect.size) else {
return None;
};
let world =
tilemap::translate_coordinates(local, context.kludgine.scale(), self.zoom, size);
let offset = self
.layers
.map(|layers| self.focus.get().world_coordinate(layers));
tick.set_cursor_position(Some(world + offset));
}
self.debug_output.as_ref().unwrap().set(format!("world: {world:?} | local: {local:?}"));
None
}
fn unhover(&mut self, _context: &mut EventContext<'_, '_>) {
if let Some(tick) = &self.tick {
tick.set_cursor_position(None);
}
}
fn keyboard_input(
@ -155,4 +162,31 @@ where
IGNORED
}
fn mouse_down(
&mut self,
_location: Point<Px>,
_device_id: DeviceId,
button: kludgine::app::winit::event::MouseButton,
_context: &mut EventContext<'_, '_>,
) -> EventHandling {
if let Some(tick) = &self.tick {
tick.mouse_button(button, ElementState::Pressed);
HANDLED
} else {
IGNORED
}
}
fn mouse_up(
&mut self,
_location: Option<Point<Px>>,
_device_id: DeviceId,
button: kludgine::app::winit::event::MouseButton,
_context: &mut EventContext<'_, '_>,
) {
if let Some(tick) = &self.tick {
tick.mouse_button(button, ElementState::Released);
}
}
}