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

View file

@ -3,10 +3,11 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::{Arc, Mutex, MutexGuard};
use std::time::{Duration, Instant}; 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::app::winit::keyboard::Key;
use kludgine::figures::Point;
use kludgine::figures::units::Px; use kludgine::figures::units::Px;
use kludgine::figures::Point;
use crate::context::WidgetContext; use crate::context::WidgetContext;
use crate::utils::{IgnorePoison, UnwindsafeCondvar}; 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(); 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 /// Returns a new tick that invokes `tick`, aiming to repeat at the given
@ -70,7 +100,6 @@ impl Tick {
keep_running: true, keep_running: true,
frame: 0, frame: 0,
input: InputState::default(), input: InputState::default(),
mouse: None,
}), }),
period: tick_every, period: tick_every,
sync: UnwindsafeCondvar::new(), sync: UnwindsafeCondvar::new(),
@ -119,15 +148,16 @@ impl Tick {
pub struct InputState { pub struct InputState {
/// A collection of all keys currently pressed. /// A collection of all keys currently pressed.
pub keys: HashSet<Key>, pub keys: HashSet<Key>,
pub mouse: Mouse, /// The state of the mouse cursor and any buttons pressed.
pub mouse: Option<Mouse>,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Mouse { pub struct Mouse {
pub pos: Point<Px>, pub position: Point<Px>,
pub buttons: HashSet<MouseButton>,
} }
#[derive(Debug)] #[derive(Debug)]
struct TickData { struct TickData {
state: Mutex<TickState>, state: Mutex<TickState>,
@ -150,7 +180,6 @@ struct TickState {
keep_running: bool, keep_running: bool,
frame: usize, frame: usize,
input: InputState, input: InputState,
mouse: Option<Mouse>,
} }
fn tick_loop<F>(data: &TickData, mut tick: F) fn tick_loop<F>(data: &TickData, mut tick: F)

View file

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