Refactored core event sources to use our own events too.
Calling then "raw-events", this removes the winit events from all public APIs and enable event faking by default.
This commit is contained in:
parent
3853b971c2
commit
eda29d2af4
|
@ -1606,7 +1606,7 @@ impl TestApp {
|
|||
}
|
||||
|
||||
pub fn just_release_alt(&mut self) {
|
||||
self.app.on_keyboard_input(self.window_id, Key::LAlt, ElementState::Released);
|
||||
self.app.on_keyboard_input(self.window_id, Key::LAlt, KeyState::Released);
|
||||
self.app.update(false);
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -76,7 +76,7 @@
|
|||
//! Focus information exists as metadata associated with a window frame. This metadata can be manually queried by
|
||||
//! creating a [`FrameFocusInfo`] or directly from a widget info by using the [`WidgetInfoFocusExt`] extension methods.
|
||||
|
||||
use crate::app::{AppEventSender, AppExtension, DeviceEvent, DeviceId};
|
||||
use crate::app::{AppEventSender, AppExtension};
|
||||
use crate::context::*;
|
||||
use crate::event::*;
|
||||
use crate::gesture::{shortcut, ShortcutEvent};
|
||||
|
@ -546,6 +546,8 @@ impl AppExtension for FocusManager {
|
|||
ReturnFocusChangedEvent.notify(ctx.events, args);
|
||||
}
|
||||
}
|
||||
} else if let Some(args) = crate::app::raw_device_events::KeyEvent.update(args) {
|
||||
self.last_keyboard_event = args.timestamp;
|
||||
}
|
||||
|
||||
if let Some(request) = request {
|
||||
|
@ -569,12 +571,6 @@ impl AppExtension for FocusManager {
|
|||
}
|
||||
}
|
||||
|
||||
fn device_event(&mut self, _: &mut AppContext, _: DeviceId, event: &DeviceEvent) {
|
||||
if let DeviceEvent::Key(_) = event {
|
||||
self.last_keyboard_event = Instant::now();
|
||||
}
|
||||
}
|
||||
|
||||
fn new_frame_ready(&mut self, ctx: &mut AppContext, window_id: WindowId) {
|
||||
let (focus, windows) = ctx.services.req_multi::<(Focus, Windows)>();
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Aggregate events.
|
||||
|
||||
use super::{service::Service, units::LayoutPoint, WidgetId};
|
||||
use crate::app::*;
|
||||
use crate::app::{raw_events::RawWindowFocusEvent, *};
|
||||
use crate::command::Command;
|
||||
use crate::context::*;
|
||||
use crate::event::*;
|
||||
|
@ -10,7 +10,7 @@ use crate::keyboard::*;
|
|||
use crate::mouse::*;
|
||||
use crate::render::*;
|
||||
use crate::var::RcVar;
|
||||
use crate::window::{WindowEvent, WindowId, Windows};
|
||||
use crate::window::{WindowId, Windows};
|
||||
use std::num::NonZeroU32;
|
||||
use std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
|
@ -559,7 +559,7 @@ impl KeyInputArgs {
|
|||
/// See also [`ShortcutArgs`].
|
||||
#[inline]
|
||||
pub fn gesture(&self) -> Option<KeyGesture> {
|
||||
if self.state == ElementState::Released {
|
||||
if self.state == KeyState::Released {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -718,9 +718,11 @@ impl AppExtension for GestureManager {
|
|||
r.services.register(Gestures::new());
|
||||
}
|
||||
|
||||
fn window_event(&mut self, _: &mut AppContext, _: WindowId, event: &WindowEvent) {
|
||||
if let WindowEvent::Focused(false) = event {
|
||||
self.pressed_modifier = None;
|
||||
fn event_preview<EV: EventUpdateArgs>(&mut self, _: &mut AppContext, args: &EV) {
|
||||
if let Some(args) = RawWindowFocusEvent.update(args) {
|
||||
if !args.focused {
|
||||
self.pressed_modifier = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -735,7 +737,7 @@ impl AppExtension for GestureManager {
|
|||
if !args.stop_propagation_requested() {
|
||||
if let Some(key) = args.key {
|
||||
match args.state {
|
||||
ElementState::Pressed => {
|
||||
KeyState::Pressed => {
|
||||
if let Ok(gesture_key) = GestureKey::try_from(key) {
|
||||
let s_args = ShortcutArgs::new(
|
||||
args.timestamp,
|
||||
|
@ -755,7 +757,7 @@ impl AppExtension for GestureManager {
|
|||
self.pressed_modifier = None;
|
||||
}
|
||||
}
|
||||
ElementState::Released => {
|
||||
KeyState::Released => {
|
||||
if let Ok(mod_gesture) = ModifierGesture::try_from(key) {
|
||||
if Some(mod_gesture) == self.pressed_modifier.take() && args.modifiers.is_empty() {
|
||||
let s_args = ShortcutArgs::new(
|
||||
|
|
|
@ -4,32 +4,31 @@
|
|||
//! is included in the [default app](crate::app::App::default) and provides the [`Keyboard`] service
|
||||
//! and keyboard input events.
|
||||
|
||||
use crate::app::*;
|
||||
use crate::app::{raw_events::*, *};
|
||||
use crate::context::*;
|
||||
use crate::event::*;
|
||||
use crate::focus::{Focus, FocusExt};
|
||||
use crate::focus::FocusExt;
|
||||
use crate::render::WidgetPath;
|
||||
use crate::service::*;
|
||||
use crate::window::{WindowEvent, WindowId, Windows};
|
||||
use crate::var::{RcVar, ReadOnlyRcVar, Var, Vars};
|
||||
use crate::window::WindowId;
|
||||
|
||||
pub use glutin::event::{KeyboardInput, ModifiersState, ScanCode};
|
||||
|
||||
event_args! {
|
||||
/// Keyboard event args.
|
||||
/// Arguments for [`KeyInputEvent`].
|
||||
pub struct KeyInputArgs {
|
||||
/// Id of window that received the event.
|
||||
/// Window that received the event.
|
||||
pub window_id: WindowId,
|
||||
|
||||
/// Id of device that generated the event.
|
||||
///
|
||||
/// Is `None` if the event was generated programmatically.
|
||||
pub device_id: Option<DeviceId>,
|
||||
/// Device that generated the event.
|
||||
pub device_id: DeviceId,
|
||||
|
||||
/// Raw code of key.
|
||||
pub scan_code: ScanCode,
|
||||
|
||||
/// If the key was pressed or released.
|
||||
pub state: ElementState,
|
||||
pub state: KeyState,
|
||||
|
||||
/// Symbolic name of [`scan_code`](KeyInputArgs::scan_code).
|
||||
pub key: Option<Key>,
|
||||
|
@ -45,45 +44,18 @@ event_args! {
|
|||
|
||||
..
|
||||
|
||||
/// If the widget is focused or contains the focused widget.
|
||||
/// Returns `true` if the widget is the [`target`](Self::target) or is a parent of the target.
|
||||
fn concerns_widget(&self, ctx: &mut WidgetContext) -> bool {
|
||||
self.target.contains(ctx.path.widget_id())
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw keyboard event args.
|
||||
pub struct RawKeyInputArgs {
|
||||
/// Id of window that received the event.
|
||||
pub window_id: WindowId,
|
||||
|
||||
/// Id of device that generated the event.
|
||||
///
|
||||
/// Is `None` if the event was generated programmatically.
|
||||
pub device_id: Option<DeviceId>,
|
||||
|
||||
/// Raw code of key.
|
||||
pub scan_code: ScanCode,
|
||||
|
||||
/// If the key was pressed or released.
|
||||
pub state: ElementState,
|
||||
|
||||
/// Symbolic name of [`scan_code`](KeyInputArgs::scan_code).
|
||||
pub key: Option<Key>,
|
||||
|
||||
..
|
||||
|
||||
/// Always `false`
|
||||
fn concerns_widget(&self, _ctx: &mut WidgetContext) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Character received event args.
|
||||
/// Arguments for [`CharInputEvent`].
|
||||
pub struct CharInputArgs {
|
||||
/// Id of window that received the event.
|
||||
/// Window that received the event.
|
||||
pub window_id: WindowId,
|
||||
|
||||
/// The character.
|
||||
/// Unicode character.
|
||||
pub character: char,
|
||||
|
||||
/// The focused element at the time of the key input.
|
||||
|
@ -91,13 +63,13 @@ event_args! {
|
|||
|
||||
..
|
||||
|
||||
/// If the widget is focused or contains the focused widget.
|
||||
/// Returns `true` if the widget is the [`target`](Self::target) or is a parent of the target.
|
||||
fn concerns_widget(&self, ctx: &mut WidgetContext) -> bool {
|
||||
self.target.contains(ctx.path.widget_id())
|
||||
}
|
||||
}
|
||||
|
||||
/// Keyboard modifiers changed event args.
|
||||
/// Arguments for [`ModifiersChangedEvent`].
|
||||
pub struct ModifiersChangedArgs {
|
||||
/// Previous modifiers state.
|
||||
pub prev_modifiers: ModifiersState,
|
||||
|
@ -105,35 +77,24 @@ event_args! {
|
|||
/// Current modifiers state.
|
||||
pub modifiers: ModifiersState,
|
||||
|
||||
/// The focused element at the time of the update.
|
||||
pub target: WidgetPath,
|
||||
|
||||
..
|
||||
|
||||
/// If the widget is focused or contains the focused widget.
|
||||
fn concerns_widget(&self, ctx: &mut WidgetContext) -> bool {
|
||||
self.target.contains(ctx.path.widget_id())
|
||||
/// Returns `true` for all widgets.
|
||||
fn concerns_widget(&self, _ctx: &mut WidgetContext) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event! {
|
||||
/// Key pressed or released event.
|
||||
/// Key pressed, repeat pressed or released event.
|
||||
///
|
||||
/// # Provider
|
||||
///
|
||||
/// This event is provided by the [`KeyboardManager`] extension.
|
||||
pub KeyInputEvent: KeyInputArgs;
|
||||
|
||||
/// Key pressed or released without focus target.
|
||||
/// You can invoke this event to fake a key-press that [`Keyboard`] accepts.
|
||||
///
|
||||
/// # Provider
|
||||
///
|
||||
/// This event is provided by the [`KeyboardManager`] extension.
|
||||
pub RawKeyInputEvent: RawKeyInputArgs;
|
||||
|
||||
/// Key pressed or repeat event.
|
||||
/// Key pressed or repeat pressed event.
|
||||
///
|
||||
/// # Provider
|
||||
///
|
||||
|
@ -147,7 +108,7 @@ event! {
|
|||
/// This event is provided by the [`KeyboardManager`] extension.
|
||||
pub KeyUpEvent: KeyInputArgs;
|
||||
|
||||
/// Modifiers state changed event.
|
||||
/// Modifiers key state changed event.
|
||||
///
|
||||
/// # Provider
|
||||
///
|
||||
|
@ -162,7 +123,9 @@ event! {
|
|||
pub CharInputEvent: CharInputArgs;
|
||||
}
|
||||
|
||||
/// Application extension that provides keyboard events.
|
||||
/// Application extension that provides keyboard events targeting the focused widget.
|
||||
///
|
||||
/// This [extension] processes the raw keyboard events retargeting then to the focused widget, generating derived events and variables.
|
||||
///
|
||||
/// # Events
|
||||
///
|
||||
|
@ -182,87 +145,38 @@ event! {
|
|||
///
|
||||
/// # Default
|
||||
///
|
||||
/// This extension is included in the [default app](crate::app::App::default), events provided by it
|
||||
/// This extension is included in the [default app], events provided by it
|
||||
/// are required by multiple other extensions.
|
||||
///
|
||||
/// # Dependencies
|
||||
///
|
||||
/// This extension requires the [`Focus`] and [`Windows`] services before the first window event. It does not
|
||||
/// This extension requires the [`Focus`] and [`Windows`] services before the first raw key input event. It does not
|
||||
/// require anything for initialization.
|
||||
///
|
||||
/// [extension]: AppExtension
|
||||
/// [default app]: crate::app::App::default
|
||||
/// [`Focus`]: crate::focus::Focus
|
||||
/// [`Windows`]: crate::window::Windows
|
||||
#[derive(Default)]
|
||||
pub struct KeyboardManager;
|
||||
impl KeyboardManager {
|
||||
fn target(window_id: WindowId, services: &mut Services) -> Option<WidgetPath> {
|
||||
if let Some(focused) = services.get::<Focus>().and_then(|f| f.focused().cloned()) {
|
||||
Some(focused)
|
||||
} else {
|
||||
services
|
||||
.get::<Windows>()
|
||||
.and_then(|f| f.window(window_id).ok())
|
||||
.map(|w| w.frame_info().root().path())
|
||||
}
|
||||
}
|
||||
}
|
||||
impl AppExtension for KeyboardManager {
|
||||
fn init(&mut self, r: &mut AppContext) {
|
||||
r.services.register(Keyboard::default());
|
||||
}
|
||||
|
||||
fn window_event(&mut self, ctx: &mut AppContext, window_id: WindowId, event: &WindowEvent) {
|
||||
match *event {
|
||||
WindowEvent::KeyboardInput {
|
||||
device_id,
|
||||
input:
|
||||
KeyboardInput {
|
||||
scancode,
|
||||
state,
|
||||
virtual_keycode: key,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
RawKeyInputEvent.notify(
|
||||
ctx.events,
|
||||
RawKeyInputArgs::now(window_id, Some(device_id), scancode, state, key.map(Into::into)),
|
||||
);
|
||||
}
|
||||
|
||||
WindowEvent::ModifiersChanged(m) => {
|
||||
if let Some(target) = Self::target(window_id, ctx.services) {
|
||||
ctx.services.keyboard().set_modifiers(m, target, ctx.events);
|
||||
}
|
||||
}
|
||||
|
||||
WindowEvent::ReceivedCharacter(c) => {
|
||||
if let Some(target) = Self::target(window_id, ctx.services) {
|
||||
ctx.services.keyboard().char_input(c, target, ctx.events);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn event<EV: EventUpdateArgs>(&mut self, ctx: &mut AppContext, args: &EV) {
|
||||
fn event_preview<EV: EventUpdateArgs>(&mut self, ctx: &mut AppContext, args: &EV) {
|
||||
if let Some(args) = RawKeyInputEvent.update(args) {
|
||||
if let Some(target) = ctx.services.focus().focused() {
|
||||
let args = KeyInputArgs::new(
|
||||
args.timestamp,
|
||||
args.window_id,
|
||||
args.device_id,
|
||||
args.scan_code,
|
||||
args.state,
|
||||
args.key,
|
||||
// TODO
|
||||
ModifiersState::empty(),
|
||||
false,
|
||||
target.clone(),
|
||||
);
|
||||
|
||||
KeyInputEvent.notify(ctx.events, args.clone());
|
||||
match args.state {
|
||||
ElementState::Pressed => KeyDownEvent.notify(ctx.events, args),
|
||||
ElementState::Released => KeyUpEvent.notify(ctx.events, args),
|
||||
let focused = ctx.services.focus().focused().cloned();
|
||||
let keyboard = ctx.services.keyboard();
|
||||
keyboard.key_input(ctx.events, ctx.vars, args, focused);
|
||||
} else if let Some(args) = RawModifiersChangedEvent.update(args) {
|
||||
let keyboard = ctx.services.keyboard();
|
||||
keyboard.set_modifiers(ctx.events, ctx.vars, args.modifiers);
|
||||
} else if let Some(args) = RawCharInputEvent.update(args) {
|
||||
let focused = ctx.services.focus().focused().cloned();
|
||||
if let Some(target) = focused {
|
||||
if target.window_id() == args.window_id {
|
||||
CharInputEvent.notify(ctx, CharInputArgs::now(args.window_id, args.character, target));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -277,76 +191,142 @@ impl AppExtension for KeyboardManager {
|
|||
#[derive(Service, Default)]
|
||||
pub struct Keyboard {
|
||||
modifiers: ModifiersState,
|
||||
last_key_down: Option<(Option<DeviceId>, ScanCode)>,
|
||||
modifiers_var: RcVar<ModifiersState>,
|
||||
|
||||
codes: Vec<ScanCode>,
|
||||
codes_var: RcVar<Vec<ScanCode>>,
|
||||
|
||||
keys: Vec<Key>,
|
||||
keys_var: RcVar<Vec<Key>>,
|
||||
|
||||
last_key_down: Option<(DeviceId, ScanCode)>,
|
||||
}
|
||||
impl Keyboard {
|
||||
/// Process a software keyboard input.
|
||||
#[inline]
|
||||
pub fn input(&mut self, key: Key, state: ElementState, target: WidgetPath, events: &mut Events) {
|
||||
self.do_input(None, key as ScanCode, Some(key), state, target, events);
|
||||
}
|
||||
fn set_modifiers(&mut self, events: &mut Events, vars: &Vars, modifiers: ModifiersState) {
|
||||
if self.modifiers_var.set_ne(vars, modifiers) {
|
||||
let prev_modifiers = self.modifiers;
|
||||
self.modifiers = modifiers;
|
||||
|
||||
/// Process a external keyboard input.
|
||||
#[inline]
|
||||
pub fn device_input(
|
||||
&mut self,
|
||||
device_id: DeviceId,
|
||||
scan_code: ScanCode,
|
||||
key: Option<Key>,
|
||||
state: ElementState,
|
||||
target: WidgetPath,
|
||||
events: &mut Events,
|
||||
) {
|
||||
self.do_input(Some(device_id), scan_code, key, state, target, events);
|
||||
}
|
||||
|
||||
/// Set the keyboard modifiers state.
|
||||
pub fn set_modifiers(&mut self, modifiers: ModifiersState, target: WidgetPath, events: &mut Events) {
|
||||
if self.modifiers != modifiers {
|
||||
let prev_modifiers = std::mem::replace(&mut self.modifiers, modifiers);
|
||||
let args = ModifiersChangedArgs::now(prev_modifiers, modifiers, target);
|
||||
ModifiersChangedEvent.notify(events, args);
|
||||
ModifiersChangedEvent.notify(events, ModifiersChangedArgs::now(prev_modifiers, modifiers));
|
||||
}
|
||||
}
|
||||
|
||||
/// Character input.
|
||||
pub fn char_input(&mut self, character: char, target: WidgetPath, events: &mut Events) {
|
||||
let args = CharInputArgs::now(target.window_id(), character, target);
|
||||
CharInputEvent.notify(events, args);
|
||||
fn key_input(&mut self, events: &mut Events, vars: &Vars, args: &RawKeyInputArgs, focused: Option<WidgetPath>) {
|
||||
let mut repeat = false;
|
||||
|
||||
// update state and vars
|
||||
match args.state {
|
||||
KeyState::Pressed => {
|
||||
repeat = self
|
||||
.last_key_down
|
||||
.map(|(d, s)| args.device_id == d && args.scan_code == s)
|
||||
.unwrap_or_default();
|
||||
if !repeat {
|
||||
self.last_key_down = Some((args.device_id, args.scan_code));
|
||||
}
|
||||
|
||||
if !self.codes.contains(&args.scan_code) {
|
||||
self.codes.push(args.scan_code);
|
||||
self.codes_var.set(vars, self.codes.clone());
|
||||
}
|
||||
|
||||
if let Some(key) = args.key {
|
||||
if !self.keys.contains(&key) {
|
||||
self.keys.push(key);
|
||||
self.keys_var.set(vars, self.keys.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
KeyState::Released => {
|
||||
self.last_key_down = None;
|
||||
|
||||
if let Some(i) = self.codes.iter().position(|&c| c == args.scan_code) {
|
||||
self.codes.swap_remove(i);
|
||||
self.codes_var.set(vars, self.codes.clone());
|
||||
}
|
||||
|
||||
if let Some(key) = args.key {
|
||||
if let Some(i) = self.keys.iter().position(|&c| c == key) {
|
||||
self.keys.swap_remove(i);
|
||||
self.keys_var.set(vars, self.keys.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// notify events
|
||||
if let Some(target) = focused {
|
||||
if target.window_id() == args.window_id {
|
||||
let args = KeyInputArgs::now(
|
||||
args.window_id,
|
||||
args.device_id,
|
||||
args.scan_code,
|
||||
args.state,
|
||||
args.key,
|
||||
self.modifiers,
|
||||
repeat,
|
||||
target,
|
||||
);
|
||||
KeyInputEvent.notify(events, args.clone());
|
||||
|
||||
match args.state {
|
||||
KeyState::Pressed => KeyDownEvent.notify(events, args),
|
||||
KeyState::Released => KeyUpEvent.notify(events, args),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Current modifiers pressed.
|
||||
/// Returns the currently pressed modifier keys.
|
||||
#[inline]
|
||||
pub fn modifiers(&self) -> ModifiersState {
|
||||
self.modifiers
|
||||
}
|
||||
|
||||
fn do_input(
|
||||
&mut self,
|
||||
device_id: Option<DeviceId>,
|
||||
scan_code: ScanCode,
|
||||
key: Option<Key>,
|
||||
state: ElementState,
|
||||
target: WidgetPath,
|
||||
events: &mut Events,
|
||||
) {
|
||||
let mut repeat = false;
|
||||
if state == ElementState::Pressed {
|
||||
repeat = self.last_key_down == Some((device_id, scan_code));
|
||||
if !repeat {
|
||||
self.last_key_down = Some((device_id, scan_code));
|
||||
}
|
||||
} else {
|
||||
self.last_key_down = None;
|
||||
}
|
||||
/// Returns a read-only variable that updates when the [`modifiers`](Self::modifiers) change.
|
||||
#[inline]
|
||||
pub fn modifiers_var(&self) -> ReadOnlyRcVar<ModifiersState> {
|
||||
self.modifiers_var.clone().into_read_only()
|
||||
}
|
||||
|
||||
let args = KeyInputArgs::now(target.window_id(), device_id, scan_code, state, key, self.modifiers, repeat, target);
|
||||
/// Returns the [`ScanCode`] of the keys currently pressed.
|
||||
#[inline]
|
||||
pub fn codes(&self) -> &[ScanCode] {
|
||||
&self.codes
|
||||
}
|
||||
|
||||
KeyInputEvent.notify(events, args.clone());
|
||||
/// Returns a read-only variable that updates when the [`codes`](Self::codes) change.
|
||||
#[inline]
|
||||
pub fn codes_var(&self) -> ReadOnlyRcVar<Vec<ScanCode>> {
|
||||
self.codes_var.clone().into_read_only()
|
||||
}
|
||||
|
||||
match args.state {
|
||||
ElementState::Pressed => KeyDownEvent.notify(events, args),
|
||||
ElementState::Released => KeyUpEvent.notify(events, args),
|
||||
/// Returns the [`Key`] identifier of the keys currently pressed.
|
||||
#[inline]
|
||||
pub fn keys(&self) -> &[Key] {
|
||||
&self.keys
|
||||
}
|
||||
|
||||
/// Returns a read-only variable that updates when the [`keys`](Self::keys) change.
|
||||
#[inline]
|
||||
pub fn keys_var(&self) -> ReadOnlyRcVar<Vec<Key>> {
|
||||
self.keys_var.clone().into_read_only()
|
||||
}
|
||||
}
|
||||
|
||||
/// State a keyboard [`Key`] has entered.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum KeyState {
|
||||
/// The key was pressed.
|
||||
Pressed,
|
||||
/// The key was released.
|
||||
Released,
|
||||
}
|
||||
impl From<glutin::event::ElementState> for KeyState {
|
||||
fn from(s: glutin::event::ElementState) -> Self {
|
||||
match s {
|
||||
glutin::event::ElementState::Pressed => KeyState::Pressed,
|
||||
glutin::event::ElementState::Released => KeyState::Released,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -774,10 +754,12 @@ impl From<Key> for VKey {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO refactor this.
|
||||
|
||||
/// Extension trait that adds keyboard simulation methods to [`HeadlessApp`].
|
||||
pub trait HeadlessAppKeyboardExt {
|
||||
/// Does a keyboard input event.
|
||||
fn on_keyboard_input(&mut self, window_id: WindowId, key: Key, state: ElementState);
|
||||
fn on_keyboard_input(&mut self, window_id: WindowId, key: Key, state: KeyState);
|
||||
|
||||
/// Does a keyboard modifiers changed event.
|
||||
fn on_modifiers_changed(&mut self, window_id: WindowId, modifiers: ModifiersState);
|
||||
|
@ -789,13 +771,16 @@ pub trait HeadlessAppKeyboardExt {
|
|||
fn press_modified_key(&mut self, window_id: WindowId, modifiers: ModifiersState, key: Key);
|
||||
}
|
||||
impl HeadlessAppKeyboardExt for HeadlessApp {
|
||||
fn on_keyboard_input(&mut self, window_id: WindowId, key: Key, state: ElementState) {
|
||||
fn on_keyboard_input(&mut self, window_id: WindowId, key: Key, state: KeyState) {
|
||||
#[allow(deprecated)]
|
||||
let raw_event = WindowEvent::KeyboardInput {
|
||||
device_id: unsafe { DeviceId::dummy() },
|
||||
let raw_event = glutin::event::WindowEvent::KeyboardInput {
|
||||
device_id: unsafe { glutin::event::DeviceId::dummy() },
|
||||
input: KeyboardInput {
|
||||
scancode: 0,
|
||||
state,
|
||||
state: match state {
|
||||
KeyState::Pressed => glutin::event::ElementState::Pressed,
|
||||
KeyState::Released => glutin::event::ElementState::Released,
|
||||
},
|
||||
virtual_keycode: Some(key.into()),
|
||||
|
||||
// what can we
|
||||
|
@ -808,13 +793,13 @@ impl HeadlessAppKeyboardExt for HeadlessApp {
|
|||
}
|
||||
|
||||
fn on_modifiers_changed(&mut self, window_id: WindowId, modifiers: ModifiersState) {
|
||||
let raw_event = WindowEvent::ModifiersChanged(modifiers);
|
||||
let raw_event = glutin::event::WindowEvent::ModifiersChanged(modifiers);
|
||||
self.window_event(window_id, &raw_event);
|
||||
}
|
||||
|
||||
fn press_key(&mut self, window_id: WindowId, key: Key) {
|
||||
self.on_keyboard_input(window_id, key, ElementState::Pressed);
|
||||
self.on_keyboard_input(window_id, key, ElementState::Released);
|
||||
self.on_keyboard_input(window_id, key, KeyState::Pressed);
|
||||
self.on_keyboard_input(window_id, key, KeyState::Released);
|
||||
self.update(false);
|
||||
}
|
||||
|
||||
|
@ -823,40 +808,40 @@ impl HeadlessAppKeyboardExt for HeadlessApp {
|
|||
self.press_key(window_id, key);
|
||||
} else {
|
||||
if modifiers.logo() {
|
||||
self.on_keyboard_input(window_id, Key::LLogo, ElementState::Pressed);
|
||||
self.on_keyboard_input(window_id, Key::LLogo, KeyState::Pressed);
|
||||
}
|
||||
if modifiers.ctrl() {
|
||||
self.on_keyboard_input(window_id, Key::LCtrl, ElementState::Pressed);
|
||||
self.on_keyboard_input(window_id, Key::LCtrl, KeyState::Pressed);
|
||||
}
|
||||
if modifiers.shift() {
|
||||
self.on_keyboard_input(window_id, Key::LShift, ElementState::Pressed);
|
||||
self.on_keyboard_input(window_id, Key::LShift, KeyState::Pressed);
|
||||
}
|
||||
if modifiers.alt() {
|
||||
self.on_keyboard_input(window_id, Key::LAlt, ElementState::Pressed);
|
||||
self.on_keyboard_input(window_id, Key::LAlt, KeyState::Pressed);
|
||||
}
|
||||
self.on_modifiers_changed(window_id, modifiers);
|
||||
|
||||
// pressed the modifiers.
|
||||
self.update(false);
|
||||
|
||||
self.on_keyboard_input(window_id, key, ElementState::Pressed);
|
||||
self.on_keyboard_input(window_id, key, ElementState::Released);
|
||||
self.on_keyboard_input(window_id, key, KeyState::Pressed);
|
||||
self.on_keyboard_input(window_id, key, KeyState::Released);
|
||||
|
||||
// pressed the key.
|
||||
self.update(false);
|
||||
|
||||
self.on_modifiers_changed(window_id, ModifiersState::default());
|
||||
if modifiers.logo() {
|
||||
self.on_keyboard_input(window_id, Key::LLogo, ElementState::Released);
|
||||
self.on_keyboard_input(window_id, Key::LLogo, KeyState::Released);
|
||||
}
|
||||
if modifiers.ctrl() {
|
||||
self.on_keyboard_input(window_id, Key::LCtrl, ElementState::Released);
|
||||
self.on_keyboard_input(window_id, Key::LCtrl, KeyState::Released);
|
||||
}
|
||||
if modifiers.shift() {
|
||||
self.on_keyboard_input(window_id, Key::LShift, ElementState::Released);
|
||||
self.on_keyboard_input(window_id, Key::LShift, KeyState::Released);
|
||||
}
|
||||
if modifiers.alt() {
|
||||
self.on_keyboard_input(window_id, Key::LAlt, ElementState::Released);
|
||||
self.on_keyboard_input(window_id, Key::LAlt, KeyState::Released);
|
||||
}
|
||||
|
||||
// released the modifiers.
|
||||
|
|
|
@ -4,18 +4,16 @@
|
|||
|
||||
use super::units::{LayoutPoint, LayoutRect, LayoutSize};
|
||||
use super::WidgetId;
|
||||
use crate::app::*;
|
||||
use crate::app::{raw_events::*, *};
|
||||
use crate::context::*;
|
||||
use crate::event::*;
|
||||
use crate::keyboard::ModifiersState;
|
||||
use crate::render::*;
|
||||
use crate::service::*;
|
||||
use crate::window::{WindowEvent, WindowId, Windows, WindowsExt};
|
||||
use crate::window::{WindowId, Windows, WindowsExt};
|
||||
use std::{fmt, time::*};
|
||||
use std::{mem, num::NonZeroU8};
|
||||
|
||||
type WPos = glutin::dpi::PhysicalPosition<f64>;
|
||||
|
||||
pub use glutin::event::MouseButton;
|
||||
|
||||
event_args! {
|
||||
|
@ -70,7 +68,7 @@ event_args! {
|
|||
pub modifiers: ModifiersState,
|
||||
|
||||
/// The state the [`button`](MouseInputArgs::button) was changed to.
|
||||
pub state: ElementState,
|
||||
pub state: ButtonState,
|
||||
|
||||
/// Hit-test result for the mouse point in the window.
|
||||
pub hits: FrameHitInfo,
|
||||
|
@ -407,9 +405,25 @@ impl Default for MouseManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
/// State a mouse button has entered.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ButtonState {
|
||||
/// The button was pressed.
|
||||
Pressed,
|
||||
/// The button was released.
|
||||
Released,
|
||||
}
|
||||
impl From<glutin::event::ElementState> for ButtonState {
|
||||
fn from(s: glutin::event::ElementState) -> Self {
|
||||
match s {
|
||||
glutin::event::ElementState::Pressed => ButtonState::Pressed,
|
||||
glutin::event::ElementState::Released => ButtonState::Released,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MouseManager {
|
||||
fn on_mouse_input(&mut self, window_id: WindowId, device_id: DeviceId, state: ElementState, button: MouseButton, ctx: &mut AppContext) {
|
||||
fn on_mouse_input(&mut self, window_id: WindowId, device_id: DeviceId, state: ButtonState, button: MouseButton, ctx: &mut AppContext) {
|
||||
let position = if self.pos_window == Some(window_id) {
|
||||
self.pos
|
||||
} else {
|
||||
|
@ -427,7 +441,7 @@ impl MouseManager {
|
|||
(frame_info.root().path(), position)
|
||||
};
|
||||
|
||||
if state == ElementState::Pressed {
|
||||
if state == ButtonState::Pressed {
|
||||
self.capture_count += 1;
|
||||
if self.capture_count == 1 {
|
||||
mouse.start_window_capture(target.clone(), ctx.events);
|
||||
|
@ -465,7 +479,7 @@ impl MouseManager {
|
|||
MouseInputEvent.notify(ctx.events, args.clone());
|
||||
|
||||
match state {
|
||||
ElementState::Pressed => {
|
||||
ButtonState::Pressed => {
|
||||
// on_mouse_down
|
||||
MouseDownEvent.notify(ctx.events, args);
|
||||
|
||||
|
@ -500,7 +514,7 @@ impl MouseManager {
|
|||
}
|
||||
self.last_pressed = now;
|
||||
}
|
||||
ElementState::Released => {
|
||||
ButtonState::Released => {
|
||||
// on_mouse_up
|
||||
MouseUpEvent.notify(ctx.events, args);
|
||||
|
||||
|
@ -534,7 +548,7 @@ impl MouseManager {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_cursor_moved(&mut self, window_id: WindowId, device_id: DeviceId, position: WPos, ctx: &mut AppContext) {
|
||||
fn on_cursor_moved(&mut self, window_id: WindowId, device_id: DeviceId, position: (i32, i32), ctx: &mut AppContext) {
|
||||
let mut moved = Some(window_id) != self.pos_window;
|
||||
|
||||
if moved {
|
||||
|
@ -546,7 +560,7 @@ impl MouseManager {
|
|||
self.pos_dpi = windows.window(window_id).unwrap().scale_factor();
|
||||
}
|
||||
|
||||
let pos = LayoutPoint::new(position.x as f32 / self.pos_dpi, position.y as f32 / self.pos_dpi);
|
||||
let pos = LayoutPoint::new(position.0 as f32 / self.pos_dpi, position.1 as f32 / self.pos_dpi);
|
||||
|
||||
moved |= pos != self.pos;
|
||||
|
||||
|
@ -705,17 +719,21 @@ impl AppExtension for MouseManager {
|
|||
r.services.register(Mouse::new(r.updates.sender()));
|
||||
}
|
||||
|
||||
fn window_event(&mut self, ctx: &mut AppContext, window_id: WindowId, event: &WindowEvent) {
|
||||
match *event {
|
||||
WindowEvent::CursorMoved { device_id, position, .. } => self.on_cursor_moved(window_id, device_id, position, ctx),
|
||||
WindowEvent::MouseInput {
|
||||
state, device_id, button, ..
|
||||
} => self.on_mouse_input(window_id, device_id, state, button, ctx),
|
||||
WindowEvent::ModifiersChanged(m) => self.modifiers = m,
|
||||
WindowEvent::CursorLeft { device_id } => self.on_cursor_left(window_id, device_id, ctx),
|
||||
WindowEvent::Focused(false) => self.on_window_blur(window_id, ctx),
|
||||
WindowEvent::Destroyed => self.on_window_closed(window_id, ctx),
|
||||
_ => {}
|
||||
fn event_preview<EV: EventUpdateArgs>(&mut self, ctx: &mut AppContext, args: &EV) {
|
||||
if let Some(args) = RawCursorMovedEvent.update(args) {
|
||||
self.on_cursor_moved(args.window_id, args.device_id, args.position, ctx);
|
||||
} else if let Some(args) = RawMouseInputEvent.update(args) {
|
||||
self.on_mouse_input(args.window_id, args.device_id, args.state, args.button, ctx);
|
||||
} else if let Some(args) = RawModifiersChangedEvent.update(args) {
|
||||
self.modifiers = args.modifiers;
|
||||
} else if let Some(args) = RawCursorLeftEvent.update(args) {
|
||||
self.on_cursor_left(args.window_id, args.device_id, ctx);
|
||||
} else if let Some(args) = RawWindowFocusEvent.update(args) {
|
||||
if !args.focused {
|
||||
self.on_window_blur(args.window_id, ctx);
|
||||
}
|
||||
} else if let Some(args) = RawWindowClosedEvent.update(args) {
|
||||
self.on_window_closed(args.window_id, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,6 @@ impl std::fmt::Display for VarIsReadOnly {
|
|||
/// A value type using [`IntoVar`] twice to support a shorthand initialization syntax:
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() { }
|
||||
/// # use zero_ui_core::var::*;
|
||||
/// # use zero_ui_core::*;
|
||||
/// #[derive(Debug, Clone)]
|
||||
|
@ -121,7 +120,7 @@ impl std::fmt::Display for VarIsReadOnly {
|
|||
/// type Var = OwnedVar<Size>;
|
||||
///
|
||||
/// fn into_var(self) -> Self::Var {
|
||||
/// OwnedVar(Size { width: self.0, height: self.1 })
|
||||
/// OwnedVar(Size { width: self.0 as f32, height: self.1 as f32 })
|
||||
/// }
|
||||
/// }
|
||||
/// impl IntoVar<Size> for (f32, f32) {
|
||||
|
@ -134,31 +133,31 @@ impl std::fmt::Display for VarIsReadOnly {
|
|||
/// #[property(size)]
|
||||
/// pub fn size(child: impl UiNode, size: impl IntoVar<Size>) -> impl UiNode {
|
||||
/// // ...
|
||||
/// # todo!()
|
||||
/// # child
|
||||
/// }
|
||||
/// # #[widget($crate::blank)]
|
||||
/// # mod blank { }
|
||||
///
|
||||
/// # fn main() {
|
||||
/// // shorthand #1:
|
||||
/// blank! {
|
||||
/// let wgt = blank! {
|
||||
/// size = (800, 600);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // shorthand #2:
|
||||
/// blank! {
|
||||
/// let wgt = blank! {
|
||||
/// size = (800.1, 600.2);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // blanket impl:
|
||||
/// blank! {
|
||||
/// let wgt = blank! {
|
||||
/// size = Size { width: 800.0, height: 600.0 };
|
||||
/// }
|
||||
/// };
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// A property implemented using [`IntoVar`]:
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() { }
|
||||
/// # use zero_ui_core::var::*;
|
||||
/// # use zero_ui_core::text::*;
|
||||
/// # use zero_ui_core::context::*;
|
||||
|
@ -170,7 +169,7 @@ impl std::fmt::Display for VarIsReadOnly {
|
|||
/// bar: V
|
||||
/// }
|
||||
/// #[impl_ui_node(child)]
|
||||
/// impl<C: UiNode, V: Var<Text>> UiNode for FooNode<C, V> {
|
||||
/// impl<C: UiNode, V: Var<u32>> UiNode for FooNode<C, V> {
|
||||
/// fn init(&mut self, ctx: &mut WidgetContext) {
|
||||
/// self.child.init(ctx);
|
||||
/// println!("init: {}", self.bar.get(ctx));
|
||||
|
@ -189,26 +188,27 @@ impl std::fmt::Display for VarIsReadOnly {
|
|||
///
|
||||
/// # #[widget($crate::blank)]
|
||||
/// # pub mod blank { }
|
||||
///
|
||||
/// # fn main() {
|
||||
/// // literal assign:
|
||||
/// blank! {
|
||||
/// let wgt = blank! {
|
||||
/// foo = 42;
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // variable assign:
|
||||
/// let variable = var(42);
|
||||
/// blank! {
|
||||
/// let wgt = blank! {
|
||||
/// foo = variable;
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // widget when:
|
||||
/// blank! {
|
||||
/// let wgt = blank! {
|
||||
/// foo = 42;
|
||||
///
|
||||
/// when !self.enabled {
|
||||
/// foo = 32;
|
||||
/// }
|
||||
/// }
|
||||
/// };
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// The property implementation is minimal and yet it supports a variety of different inputs that
|
||||
|
|
|
@ -502,3 +502,6 @@ impl<T: VarValue> ResponderVar<T> {
|
|||
self.clone().into_read_only()
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub type ReadOnlyRcVar<T> = ReadOnlyVar<T, RcVar<T>>;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! App windows manager.
|
||||
use crate::{
|
||||
app::{self, AppEventSender, AppExtended, AppExtension, AppProcessExt, ShutdownRequestedArgs, WindowTarget},
|
||||
app::{self, raw_events::*, AppEventSender, AppExtended, AppExtension, AppProcessExt, ShutdownRequestedArgs, WindowTarget},
|
||||
context::*,
|
||||
event::*,
|
||||
profiler::profile_scope,
|
||||
|
@ -22,7 +22,7 @@ use std::{
|
|||
};
|
||||
use webrender::api::{Epoch, PipelineId, RenderApi};
|
||||
|
||||
pub use glutin::{event::WindowEvent, window::CursorIcon};
|
||||
pub use glutin::window::{CursorIcon, Theme as WindowTheme};
|
||||
|
||||
unique_id! {
|
||||
/// Unique identifier of a headless window.
|
||||
|
@ -203,16 +203,16 @@ impl HeadlessAppWindowExt for app::HeadlessApp {
|
|||
|
||||
if let Some(focused) = focused {
|
||||
// blur_window
|
||||
let event = WindowEvent::Focused(false);
|
||||
let event = glutin::event::WindowEvent::Focused(false);
|
||||
self.window_event(focused, &event);
|
||||
}
|
||||
let event = WindowEvent::Focused(true);
|
||||
let event = glutin::event::WindowEvent::Focused(true);
|
||||
self.window_event(window_id, &event);
|
||||
self.update(false);
|
||||
}
|
||||
|
||||
fn blur_window(&mut self, window_id: WindowId) {
|
||||
let event = WindowEvent::Focused(false);
|
||||
let event = glutin::event::WindowEvent::Focused(false);
|
||||
self.window_event(window_id, &event);
|
||||
self.update(false);
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ impl HeadlessAppWindowExt for app::HeadlessApp {
|
|||
}
|
||||
|
||||
fn close_window(&mut self, window_id: WindowId) -> bool {
|
||||
let event = WindowEvent::CloseRequested;
|
||||
let event = glutin::event::WindowEvent::CloseRequested;
|
||||
self.window_event(window_id, &event);
|
||||
|
||||
let mut requested = false;
|
||||
|
@ -456,82 +456,69 @@ impl AppExtension for WindowManager {
|
|||
ctx.services.register(Windows::new(ctx.updates.sender()));
|
||||
}
|
||||
|
||||
fn window_event(&mut self, ctx: &mut AppContext, window_id: WindowId, event: &WindowEvent) {
|
||||
match event {
|
||||
WindowEvent::Focused(focused) => {
|
||||
if let Some(window) = ctx.services.windows().windows.iter_mut().find(|w| w.id == window_id) {
|
||||
window.is_focused = *focused;
|
||||
fn event_preview<EV: EventUpdateArgs>(&mut self, ctx: &mut AppContext, args: &EV) {
|
||||
if let Some(args) = RawWindowFocusEvent.update(args) {
|
||||
if let Some(window) = ctx.services.windows().windows.iter_mut().find(|w| w.id == args.window_id) {
|
||||
window.is_focused = args.focused;
|
||||
|
||||
let args = WindowIsFocusedArgs::now(window_id, window.is_focused, false);
|
||||
self.notify_focus(args, ctx.events);
|
||||
let args = WindowIsFocusedArgs::now(args.window_id, window.is_focused, false);
|
||||
self.notify_focus(args, ctx.events);
|
||||
}
|
||||
} else if let Some(args) = RawWindowResizedEvent.update(args) {
|
||||
if let Some(window) = ctx.services.windows().windows.iter_mut().find(|w| w.id == args.window_id) {
|
||||
let new_size = window.size();
|
||||
|
||||
// set the window size variable.
|
||||
if window.vars.size().set_ne(ctx.vars, new_size) {
|
||||
// is new size:
|
||||
ctx.updates.layout();
|
||||
window.expect_layout_update();
|
||||
window.resize_renderer();
|
||||
|
||||
// raise window_resize
|
||||
WindowResizeEvent.notify(ctx.events, WindowResizeArgs::now(args.window_id, new_size));
|
||||
}
|
||||
}
|
||||
WindowEvent::Resized(_) => {
|
||||
if let Some(window) = ctx.services.windows().windows.iter_mut().find(|w| w.id == window_id) {
|
||||
let new_size = window.size();
|
||||
} else if let Some(args) = RawWindowMovedEvent.update(args) {
|
||||
if let Some(window) = ctx.services.windows().windows.iter().find(|w| w.id == args.window_id) {
|
||||
let new_position = window.position();
|
||||
|
||||
// set the window size variable.
|
||||
if window.vars.size().set_ne(ctx.vars, new_size) {
|
||||
// is new size:
|
||||
ctx.updates.layout();
|
||||
window.expect_layout_update();
|
||||
window.resize_renderer();
|
||||
// TODO check if in new monitor.
|
||||
|
||||
// raise window_resize
|
||||
WindowResizeEvent.notify(ctx.events, WindowResizeArgs::now(window_id, new_size));
|
||||
// set the window position variable if it is not read-only.
|
||||
window.vars.position().set_ne(ctx.vars, new_position);
|
||||
|
||||
// raise window_move
|
||||
WindowMoveEvent.notify(ctx.events, WindowMoveArgs::now(args.window_id, new_position));
|
||||
}
|
||||
} else if let Some(args) = RawWindowCloseRequestedEvent.update(args) {
|
||||
if let Some(win) = ctx.services.windows().windows.iter().find(|w| w.id == args.window_id) {
|
||||
*win.close_response.borrow_mut() = Some(response_var().0);
|
||||
ctx.updates.update();
|
||||
}
|
||||
} else if let Some(args) = RawWindowScaleFactorChangedEvent.update(args) {
|
||||
if let Some(window) = ctx.services.windows().windows.iter_mut().find(|w| w.id == args.window_id) {
|
||||
let scale_factor = args.scale_factor as f32;
|
||||
let new_size = LayoutSize::new(args.size.0 as f32 / scale_factor, args.size.1 as f32 / scale_factor);
|
||||
|
||||
// winit has not set the new_inner_size yet, so
|
||||
// we can determinate if the system only changed the size
|
||||
// to visually match the new scale_factor or if the window was
|
||||
// really resized.
|
||||
if window.vars.size().copy(ctx.vars) == new_size.into() {
|
||||
// if it only changed to visually match, the WindowEvent::Resized
|
||||
// will not cause a re-layout, so we need to do it here, but window.resize_renderer()
|
||||
// calls window.size(), so we need to set the new_inner_size before winit.
|
||||
if let Some(w) = &window.window {
|
||||
w.set_inner_size(glutin::dpi::PhysicalSize::new(args.size.0, args.size.1));
|
||||
}
|
||||
ctx.updates.layout();
|
||||
window.expect_layout_update();
|
||||
window.resize_renderer();
|
||||
}
|
||||
|
||||
WindowScaleChangedEvent.notify(ctx.events, WindowScaleChangedArgs::now(args.window_id, scale_factor, new_size));
|
||||
}
|
||||
WindowEvent::Moved(_) => {
|
||||
if let Some(window) = ctx.services.windows().windows.iter().find(|w| w.id == window_id) {
|
||||
let new_position = window.position();
|
||||
|
||||
// TODO check if in new monitor.
|
||||
|
||||
// set the window position variable if it is not read-only.
|
||||
window.vars.position().set_ne(ctx.vars, new_position);
|
||||
|
||||
// raise window_move
|
||||
WindowMoveEvent.notify(ctx.events, WindowMoveArgs::now(window_id, new_position));
|
||||
}
|
||||
}
|
||||
WindowEvent::CloseRequested => {
|
||||
if let Some(win) = ctx.services.windows().windows.iter().find(|w| w.id == window_id) {
|
||||
*win.close_response.borrow_mut() = Some(response_var().0);
|
||||
ctx.updates.update();
|
||||
}
|
||||
}
|
||||
WindowEvent::ScaleFactorChanged {
|
||||
scale_factor,
|
||||
new_inner_size,
|
||||
} => {
|
||||
if let Some(window) = ctx.services.windows().windows.iter_mut().find(|w| w.id == window_id) {
|
||||
let scale_factor = *scale_factor as f32;
|
||||
let new_size = LayoutSize::new(
|
||||
new_inner_size.width as f32 / scale_factor,
|
||||
new_inner_size.height as f32 / scale_factor,
|
||||
);
|
||||
|
||||
// winit has not set the new_inner_size yet, so
|
||||
// we can determinate if the system only changed the size
|
||||
// to visually match the new scale_factor or if the window was
|
||||
// really resized.
|
||||
if window.vars.size().copy(ctx.vars) == new_size.into() {
|
||||
// if it only changed to visually match, the WindowEvent::Resized
|
||||
// will not cause a re-layout, so we need to do it here, but window.resize_renderer()
|
||||
// calls window.size(), so we need to set the new_inner_size before winit.
|
||||
if let Some(w) = &window.window {
|
||||
w.set_inner_size(**new_inner_size);
|
||||
}
|
||||
ctx.updates.layout();
|
||||
window.expect_layout_update();
|
||||
window.resize_renderer();
|
||||
}
|
||||
|
||||
WindowScaleChangedEvent.notify(ctx.events, WindowScaleChangedArgs::now(window_id, scale_factor, new_size));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2587,13 +2574,13 @@ impl OpenWindow {
|
|||
|
||||
/// Sets a window subclass that calls a raw event handler.
|
||||
///
|
||||
/// Use this to receive Windows OS events not covered in [`WindowEvent`].
|
||||
/// Use this to receive Windows OS events not covered in [`raw_events`].
|
||||
///
|
||||
/// Returns if adding a subclass handler succeeded.
|
||||
///
|
||||
/// # Handler
|
||||
///
|
||||
/// The handler inputs are the first 4 arguments of a [`SUBCLASSPROC`](https://docs.microsoft.com/en-us/windows/win32/api/commctrl/nc-commctrl-subclassproc).
|
||||
/// The handler inputs are the first 4 arguments of a [`SUBCLASSPROC`].
|
||||
/// You can use closure capture to include extra data.
|
||||
///
|
||||
/// The handler must return `Some(LRESULT)` to stop the propagation of a specific message.
|
||||
|
@ -2603,6 +2590,9 @@ impl OpenWindow {
|
|||
/// # Panics
|
||||
///
|
||||
/// Panics in headless mode.
|
||||
///
|
||||
/// [`raw_events`]: crate::app::raw_events
|
||||
/// [`SUBCLASSPROC`]: https://docs.microsoft.com/en-us/windows/win32/api/commctrl/nc-commctrl-subclassproc
|
||||
pub fn set_raw_windows_event_handler<
|
||||
H: FnMut(
|
||||
winapi::shared::windef::HWND,
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
//! content = text("Click Me!");
|
||||
//! font_size = 28;
|
||||
//! }
|
||||
//! # ;
|
||||
//! ```
|
||||
//!
|
||||
//! The example demonstrates the [`button!`] widget, you may thing the [`on_click`] and [`font_size`] are implemented in the widget,
|
||||
|
@ -114,7 +115,7 @@
|
|||
//!
|
||||
//! #[widget($crate::red_button)]
|
||||
//! mod red_button {
|
||||
// use super::*;
|
||||
//! use super::*;
|
||||
//! inherit!(zero_ui::widgets::button);
|
||||
//!
|
||||
//! properties! {
|
||||
|
@ -262,10 +263,10 @@
|
|||
//! let moving_btn = button! {
|
||||
//! margin = offset.clone();
|
||||
//! on_click = hn!(|ctx, _| {
|
||||
//! offset.modify(ctx, |m|n.left += 50.0);
|
||||
//! offset.modify(ctx, |m|m.left += 50.0);
|
||||
//! });
|
||||
//! content = text("Click to Move!")
|
||||
//! }
|
||||
//! };
|
||||
//! ```
|
||||
//!
|
||||
//! The button moves to the right when clicked, the `margin` starts at `10` and every click the variable is modified, this causes
|
||||
|
@ -312,7 +313,7 @@
|
|||
//! // 3 methods doing the same thing.
|
||||
//! flag.set(ctx.vars, new_value);
|
||||
//! flag.set_ne(ctx.vars, new_value);
|
||||
//! flag.modify(ctx.vars, |f| *f = new_value);
|
||||
//! flag.modify(ctx.vars, |f| **f = new_value);
|
||||
//! });
|
||||
//! };
|
||||
//! ```
|
||||
|
@ -367,7 +368,7 @@
|
|||
//! content = button! {
|
||||
//! content = text(count_text);
|
||||
//! on_click = hn!(|ctx, _| {
|
||||
//! count.modify(ctx, |c| *c += 1);
|
||||
//! count.modify(ctx, |c| **c += 1);
|
||||
//! });
|
||||
//! }
|
||||
//! }
|
||||
|
@ -388,7 +389,7 @@
|
|||
//!
|
||||
//! ```
|
||||
//! # use zero_ui::prelude::*;
|
||||
//! #[derive(Clone, Copy, Debug)]
|
||||
//! #[derive(Clone, Debug)]
|
||||
//! enum Status {
|
||||
//! Idle,
|
||||
//! Info(Text)
|
||||
|
@ -1397,7 +1398,7 @@ pub mod widgets;
|
|||
pub mod prelude {
|
||||
#[doc(no_inline)]
|
||||
pub use crate::core::{
|
||||
app::{App, ElementState},
|
||||
app::App,
|
||||
async_clone_move,
|
||||
border::{BorderSides, BorderStyle, LineOrientation},
|
||||
clone_move,
|
||||
|
@ -1412,8 +1413,8 @@ pub mod prelude {
|
|||
gesture::{shortcut, ClickArgs, CommandShortcutExt, GestureKey, Shortcut, ShortcutArgs, Shortcuts},
|
||||
gradient::{stops, ExtendMode, GradientStop, GradientStops},
|
||||
handler::*,
|
||||
keyboard::{CharInputArgs, Key, KeyInputArgs, ModifiersChangedArgs, ModifiersState},
|
||||
mouse::{MouseButton, MouseMoveArgs},
|
||||
keyboard::{CharInputArgs, Key, KeyInputArgs, KeyState, ModifiersChangedArgs, ModifiersState},
|
||||
mouse::{ButtonState, MouseButton, MouseMoveArgs},
|
||||
node_vec, nodes,
|
||||
render::WidgetPath,
|
||||
service::Services,
|
||||
|
@ -1498,8 +1499,6 @@ pub mod prelude {
|
|||
/// }
|
||||
/// ```
|
||||
pub mod new_property {
|
||||
#[doc(no_inline)]
|
||||
pub use crate::core::app::ElementState;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::core::border::*;
|
||||
#[doc(no_inline)]
|
||||
|
@ -1513,6 +1512,10 @@ pub mod prelude {
|
|||
#[doc(no_inline)]
|
||||
pub use crate::core::handler::*;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::core::keyboard::KeyState;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::core::mouse::ButtonState;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::core::render::*;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::core::task::{self, AppTask, WidgetTask};
|
||||
|
|
|
@ -169,12 +169,12 @@ pub fn is_pressed(child: impl UiNode, state: StateVar) -> impl UiNode {
|
|||
} else if let Some(args) = MouseInputEvent.update(args) {
|
||||
if IsEnabled::get(ctx) && args.is_primary() {
|
||||
match args.state {
|
||||
ElementState::Pressed => {
|
||||
ButtonState::Pressed => {
|
||||
if args.concerns_capture(ctx) {
|
||||
self.is_down = true;
|
||||
}
|
||||
}
|
||||
ElementState::Released => {
|
||||
ButtonState::Released => {
|
||||
self.is_down = false;
|
||||
}
|
||||
}
|
||||
|
@ -254,12 +254,12 @@ pub fn is_cap_pressed(child: impl UiNode, state: StateVar) -> impl UiNode {
|
|||
if let Some(args) = MouseInputEvent.update(args) {
|
||||
if IsEnabled::get(ctx) && args.is_primary() {
|
||||
match args.state {
|
||||
ElementState::Pressed => {
|
||||
ButtonState::Pressed => {
|
||||
if args.concerns_capture(ctx) {
|
||||
self.is_down = true;
|
||||
}
|
||||
}
|
||||
ElementState::Released => {
|
||||
ButtonState::Released => {
|
||||
self.is_down = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -288,8 +288,9 @@ pub mod window {
|
|||
#[cfg(windows)]
|
||||
fn setup_alt_f4_block(&self, ctx: &mut WidgetContext, opened_window: WindowId) {
|
||||
use zero_ui_core::{
|
||||
app::ElementState,
|
||||
keyboard::{Key, RawKeyInputArgs, RawKeyInputEvent},
|
||||
app::raw_events::{RawKeyInputArgs, RawKeyInputEvent},
|
||||
app::DeviceId,
|
||||
keyboard::{Key, KeyState},
|
||||
};
|
||||
|
||||
let window_id = ctx.path.window_id();
|
||||
|
@ -298,17 +299,18 @@ pub mod window {
|
|||
}
|
||||
|
||||
let sender = ctx.events.sender(RawKeyInputEvent);
|
||||
let sender_device_id = DeviceId::new_unique();
|
||||
|
||||
let window = ctx.services.windows().window(window_id).unwrap();
|
||||
if let WindowMode::Headed = window.mode() {
|
||||
let allow_alt_f4 = self.allow_alt_f4.clone();
|
||||
window.set_raw_windows_event_handler(move |_, msg, wparam, _| {
|
||||
if msg == winapi::um::winuser::WM_SYSKEYDOWN && wparam as i32 == winapi::um::winuser::VK_F4 && !allow_alt_f4.get() {
|
||||
sender.send(RawKeyInputArgs::now(
|
||||
let _ = sender.send(RawKeyInputArgs::now(
|
||||
window_id,
|
||||
None,
|
||||
sender_device_id,
|
||||
wparam as u32,
|
||||
ElementState::Pressed,
|
||||
KeyState::Pressed,
|
||||
Some(Key::F4),
|
||||
));
|
||||
return Some(0);
|
||||
|
|
Loading…
Reference in New Issue