Modifiers support

Closes #162
This commit is contained in:
Jonathan Johnson 2024-09-09 06:49:04 -07:00
parent 1cb93e2af2
commit 8d653c2d6c
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
3 changed files with 50 additions and 13 deletions

View file

@ -22,6 +22,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
additional parameter controlling whether to position the window with the additional parameter controlling whether to position the window with the
initial value of the dynamic or whether to let the operating system perform initial value of the dynamic or whether to let the operating system perform
the initial positioning. the initial positioning.
- Keyboard modifiers have been added to two event structures: `ButtonClick` and
`KeyboardEvent`. Because of this change, `KeyboardEvent` no longer implements
`From<winit::event::KeyEvent>`. Instead, a new api `KeyEvent::from_winit`
allows constructing from both the modifiers and key event.
### Changed ### Changed
@ -85,6 +89,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Window::inner_position` - `Window::inner_position`
- `Window::maximized` - `Window::maximized`
- `Window::minimized` - `Window::minimized`
- `Window::modifiers`
- `Window::outer_position` - `Window::outer_position`
- `Window::outer_size` - `Window::outer_size`
- `Window::resize_increments` - `Window::resize_increments`

View file

@ -3,7 +3,7 @@ use std::time::Duration;
use figures::units::{Lp, Px, UPx}; use figures::units::{Lp, Px, UPx};
use figures::{IntoSigned, Point, Rect, Round, ScreenScale, Size}; use figures::{IntoSigned, Point, Rect, Round, ScreenScale, Size};
use kludgine::app::winit::event::MouseButton; use kludgine::app::winit::event::{Modifiers, MouseButton};
use kludgine::app::winit::window::CursorIcon; use kludgine::app::winit::window::CursorIcon;
use kludgine::shapes::{Shape, StrokeOptions}; use kludgine::shapes::{Shape, StrokeOptions};
use kludgine::Color; use kludgine::Color;
@ -40,6 +40,7 @@ pub struct Button {
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct PerWindow { struct PerWindow {
buttons_pressed: usize, buttons_pressed: usize,
modifiers: Modifiers,
cached_state: CacheState, cached_state: CacheState,
active_colors: Option<Dynamic<ButtonColors>>, active_colors: Option<Dynamic<ButtonColors>>,
color_animation: AnimationHandle, color_animation: AnimationHandle,
@ -432,7 +433,9 @@ impl Widget for Button {
_button: MouseButton, _button: MouseButton,
context: &mut EventContext<'_>, context: &mut EventContext<'_>,
) -> EventHandling { ) -> EventHandling {
self.per_window.entry(context).or_default().buttons_pressed += 1; let per_window = self.per_window.entry(context).or_default();
per_window.buttons_pressed += 1;
per_window.modifiers = context.modifiers();
context.activate(); context.activate();
HANDLED HANDLED
} }
@ -475,11 +478,13 @@ impl Widget for Button {
if Rect::from(last_layout.size).contains(location) { if Rect::from(last_layout.size).contains(location) {
context.focus(); context.focus();
let modifiers = window_local.modifiers;
self.invoke_on_click( self.invoke_on_click(
Some(ButtonClick { Some(ButtonClick {
mouse_button: button, mouse_button: button,
location, location,
window_location: location + last_layout.origin, window_location: location + last_layout.origin,
modifiers,
}), }),
context, context,
); );
@ -598,4 +603,7 @@ pub struct ButtonClick {
pub location: Point<Px>, pub location: Point<Px>,
/// The location relative to the window of the click. /// The location relative to the window of the click.
pub window_location: Point<Px>, pub window_location: Point<Px>,
/// The keyboard modifiers state when this click began.
pub modifiers: Modifiers,
} }

View file

@ -550,6 +550,7 @@ where
outer_position: Option<Dynamic<Point<Px>>>, outer_position: Option<Dynamic<Point<Px>>>,
close_requested: Option<Callback<(), bool>>, close_requested: Option<Callback<(), bool>>,
icon: Option<Value<Option<RgbaImage>>>, icon: Option<Value<Option<RgbaImage>>>,
modifiers: Option<Dynamic<Modifiers>>,
} }
impl<Behavior> Default for Window<Behavior> impl<Behavior> Default for Window<Behavior>
@ -642,6 +643,7 @@ where
inner_position: None, inner_position: None,
outer_position: None, outer_position: None,
icon: None, icon: None,
modifiers: None,
} }
} }
@ -982,6 +984,13 @@ where
self.icon = Some(icon.into_value()); self.icon = Some(icon.into_value());
self self
} }
/// Sets `modifiers` to contain the state of the keyboard modifiers when
/// this window has keyboard focus.
pub fn modifiers(mut self, modifiers: impl IntoDynamic<Modifiers>) -> Self {
self.modifiers = Some(modifiers.into_dynamic());
self
}
} }
impl<Behavior> Run for Window<Behavior> impl<Behavior> Run for Window<Behavior>
@ -1050,6 +1059,7 @@ where
outer_position: this.outer_position.unwrap_or_default(), outer_position: this.outer_position.unwrap_or_default(),
outer_size: this.outer_size.unwrap_or_default(), outer_size: this.outer_size.unwrap_or_default(),
window_icon: this.icon.unwrap_or_default(), window_icon: this.icon.unwrap_or_default(),
modifiers: this.modifiers.unwrap_or_default(),
}), }),
pending: this.pending, pending: this.pending,
}, },
@ -1207,6 +1217,7 @@ struct OpenWindow<T> {
outer_position: Tracked<Dynamic<Point<Px>>>, outer_position: Tracked<Dynamic<Point<Px>>>,
inner_position: Dynamic<Point<Px>>, inner_position: Dynamic<Point<Px>>,
window_icon: Tracked<Value<Option<RgbaImage>>>, window_icon: Tracked<Value<Option<RgbaImage>>>,
modifiers: Dynamic<Modifiers>,
} }
impl<T> OpenWindow<T> impl<T> OpenWindow<T>
@ -1643,6 +1654,7 @@ where
inner_position: settings.inner_position, inner_position: settings.inner_position,
outer_position: Tracked::from(settings.outer_position).ignoring_first(), outer_position: Tracked::from(settings.outer_position).ignoring_first(),
window_icon: Tracked::from(settings.window_icon), window_icon: Tracked::from(settings.window_icon),
modifiers: settings.modifiers,
}; };
this.synchronize_platform_window(&mut window); this.synchronize_platform_window(&mut window);
@ -2469,13 +2481,8 @@ where
input: winit::event::KeyEvent, input: winit::event::KeyEvent,
is_synthetic: bool, is_synthetic: bool,
) { ) {
self.keyboard_input( let event = KeyEvent::from_winit(input, window.modifiers());
window, self.keyboard_input(window, kludgine, device_id.into(), event, is_synthetic);
kludgine,
device_id.into(),
input.into(),
is_synthetic,
);
} }
fn mouse_wheel( fn mouse_wheel(
@ -2489,7 +2496,13 @@ where
self.mouse_wheel(window, kludgine, device_id.into(), delta, phase); self.mouse_wheel(window, kludgine, device_id.into(), delta, phase);
} }
// fn modifiers_changed(&mut self, window: kludgine::app::Window<'_, ()>) {} fn modifiers_changed(
&mut self,
window: kludgine::app::Window<'_, WindowCommand>,
_kludgine: &mut Kludgine,
) {
self.modifiers.set(window.modifiers());
}
fn ime( fn ime(
&mut self, &mut self,
@ -2673,6 +2686,7 @@ pub(crate) mod sealed {
use figures::units::{Px, UPx}; use figures::units::{Px, UPx};
use figures::{Fraction, Point, Size}; use figures::{Fraction, Point, Size};
use image::{DynamicImage, RgbaImage}; use image::{DynamicImage, RgbaImage};
use kludgine::app::winit::event::Modifiers;
use kludgine::app::winit::window::{UserAttentionType, WindowLevel}; use kludgine::app::winit::window::{UserAttentionType, WindowLevel};
use kludgine::Color; use kludgine::Color;
use parking_lot::Mutex; use parking_lot::Mutex;
@ -2731,6 +2745,7 @@ pub(crate) mod sealed {
pub outer_position: Dynamic<Point<Px>>, pub outer_position: Dynamic<Point<Px>>,
pub outer_size: Dynamic<Size<UPx>>, pub outer_size: Dynamic<Size<UPx>>,
pub window_icon: Value<Option<RgbaImage>>, pub window_icon: Value<Option<RgbaImage>>,
pub modifiers: Dynamic<Modifiers>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -3343,6 +3358,7 @@ impl StandaloneWindowBuilder {
outer_position: Dynamic::default(), outer_position: Dynamic::default(),
outer_size: Dynamic::default(), outer_size: Dynamic::default(),
window_icon: Value::Constant(None), window_icon: Value::Constant(None),
modifiers: Dynamic::default(),
}, },
); );
@ -4348,6 +4364,7 @@ where
state: ElementState::Pressed, state: ElementState::Pressed,
repeat: false, repeat: false,
location: KeyLocation::Standard, location: KeyLocation::Standard,
modifiers: Modifiers::default(),
}; };
self.recorder self.recorder
.window .window
@ -4379,6 +4396,7 @@ where
location: KeyLocation::Standard, location: KeyLocation::Standard,
state: ElementState::Pressed, state: ElementState::Pressed,
repeat: false, repeat: false,
modifiers: Modifiers::default(),
}; };
let _handled = let _handled =
self.recorder self.recorder
@ -4661,7 +4679,7 @@ impl FrameAssembler {
} }
/// Describes a keyboard input targeting a window. /// Describes a keyboard input targeting a window.
#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct KeyEvent { pub struct KeyEvent {
/// The logical key that is interpretted from the `physical_key`. /// The logical key that is interpretted from the `physical_key`.
/// ///
@ -4697,10 +4715,15 @@ pub struct KeyEvent {
/// See [`KeyEvent::logical_key`](winit::event::KeyEvent::logical_key) for /// See [`KeyEvent::logical_key`](winit::event::KeyEvent::logical_key) for
/// more information. /// more information.
pub repeat: bool, pub repeat: bool,
/// The modifiers state active for this event.
pub modifiers: Modifiers,
} }
impl From<winit::event::KeyEvent> for KeyEvent { impl KeyEvent {
fn from(event: winit::event::KeyEvent) -> Self { /// Returns a new key event from a winit key event and modifiers.
#[must_use]
pub fn from_winit(event: winit::event::KeyEvent, modifiers: Modifiers) -> Self {
Self { Self {
physical_key: event.physical_key, physical_key: event.physical_key,
logical_key: event.logical_key, logical_key: event.logical_key,
@ -4708,6 +4731,7 @@ impl From<winit::event::KeyEvent> for KeyEvent {
location: event.location, location: event.location,
state: event.state, state: event.state,
repeat: event.repeat, repeat: event.repeat,
modifiers,
} }
} }
} }