Merge pull request #614 from hecrj/feature/event-capturing
Event capturing
This commit is contained in:
commit
62295f554b
|
@ -69,7 +69,8 @@ impl Sandbox for Example {
|
||||||
|
|
||||||
mod bezier {
|
mod bezier {
|
||||||
use iced::{
|
use iced::{
|
||||||
canvas::{self, Canvas, Cursor, Event, Frame, Geometry, Path, Stroke},
|
canvas::event::{self, Event},
|
||||||
|
canvas::{self, Canvas, Cursor, Frame, Geometry, Path, Stroke},
|
||||||
mouse, Element, Length, Point, Rectangle,
|
mouse, Element, Length, Point, Rectangle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,41 +110,51 @@ mod bezier {
|
||||||
event: Event,
|
event: Event,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
) -> Option<Curve> {
|
) -> (event::Status, Option<Curve>) {
|
||||||
let cursor_position = cursor.position_in(&bounds)?;
|
let cursor_position =
|
||||||
|
if let Some(position) = cursor.position_in(&bounds) {
|
||||||
|
position
|
||||||
|
} else {
|
||||||
|
return (event::Status::Ignored, None);
|
||||||
|
};
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse_event) => match mouse_event {
|
Event::Mouse(mouse_event) => {
|
||||||
mouse::Event::ButtonPressed(mouse::Button::Left) => {
|
let message = match mouse_event {
|
||||||
match self.state.pending {
|
mouse::Event::ButtonPressed(mouse::Button::Left) => {
|
||||||
None => {
|
match self.state.pending {
|
||||||
self.state.pending = Some(Pending::One {
|
None => {
|
||||||
from: cursor_position,
|
self.state.pending = Some(Pending::One {
|
||||||
});
|
from: cursor_position,
|
||||||
None
|
});
|
||||||
}
|
|
||||||
Some(Pending::One { from }) => {
|
|
||||||
self.state.pending = Some(Pending::Two {
|
|
||||||
from,
|
|
||||||
to: cursor_position,
|
|
||||||
});
|
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Some(Pending::Two { from, to }) => {
|
Some(Pending::One { from }) => {
|
||||||
self.state.pending = None;
|
self.state.pending = Some(Pending::Two {
|
||||||
|
from,
|
||||||
|
to: cursor_position,
|
||||||
|
});
|
||||||
|
|
||||||
Some(Curve {
|
None
|
||||||
from,
|
}
|
||||||
to,
|
Some(Pending::Two { from, to }) => {
|
||||||
control: cursor_position,
|
self.state.pending = None;
|
||||||
})
|
|
||||||
|
Some(Curve {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
control: cursor_position,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
_ => None,
|
||||||
_ => None,
|
};
|
||||||
},
|
|
||||||
_ => None,
|
(event::Status::Captured, message)
|
||||||
|
}
|
||||||
|
_ => (event::Status::Ignored, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,9 +153,8 @@ impl Application for GameOfLife {
|
||||||
mod grid {
|
mod grid {
|
||||||
use crate::Preset;
|
use crate::Preset;
|
||||||
use iced::{
|
use iced::{
|
||||||
canvas::{
|
canvas::event::{self, Event},
|
||||||
self, Cache, Canvas, Cursor, Event, Frame, Geometry, Path, Text,
|
canvas::{self, Cache, Canvas, Cursor, Frame, Geometry, Path, Text},
|
||||||
},
|
|
||||||
mouse, Color, Element, HorizontalAlignment, Length, Point, Rectangle,
|
mouse, Color, Element, HorizontalAlignment, Length, Point, Rectangle,
|
||||||
Size, Vector, VerticalAlignment,
|
Size, Vector, VerticalAlignment,
|
||||||
};
|
};
|
||||||
|
@ -328,12 +327,18 @@ mod grid {
|
||||||
event: Event,
|
event: Event,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
) -> Option<Message> {
|
) -> (event::Status, Option<Message>) {
|
||||||
if let Event::Mouse(mouse::Event::ButtonReleased(_)) = event {
|
if let Event::Mouse(mouse::Event::ButtonReleased(_)) = event {
|
||||||
self.interaction = Interaction::None;
|
self.interaction = Interaction::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cursor_position = cursor.position_in(&bounds)?;
|
let cursor_position =
|
||||||
|
if let Some(position) = cursor.position_in(&bounds) {
|
||||||
|
position
|
||||||
|
} else {
|
||||||
|
return (event::Status::Ignored, None);
|
||||||
|
};
|
||||||
|
|
||||||
let cell = Cell::at(self.project(cursor_position, bounds.size()));
|
let cell = Cell::at(self.project(cursor_position, bounds.size()));
|
||||||
let is_populated = self.state.contains(&cell);
|
let is_populated = self.state.contains(&cell);
|
||||||
|
|
||||||
|
@ -345,28 +350,32 @@ mod grid {
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse_event) => match mouse_event {
|
Event::Mouse(mouse_event) => match mouse_event {
|
||||||
mouse::Event::ButtonPressed(button) => match button {
|
mouse::Event::ButtonPressed(button) => {
|
||||||
mouse::Button::Left => {
|
let message = match button {
|
||||||
self.interaction = if is_populated {
|
mouse::Button::Left => {
|
||||||
Interaction::Erasing
|
self.interaction = if is_populated {
|
||||||
} else {
|
Interaction::Erasing
|
||||||
Interaction::Drawing
|
} else {
|
||||||
};
|
Interaction::Drawing
|
||||||
|
};
|
||||||
|
|
||||||
populate.or(unpopulate)
|
populate.or(unpopulate)
|
||||||
}
|
}
|
||||||
mouse::Button::Right => {
|
mouse::Button::Right => {
|
||||||
self.interaction = Interaction::Panning {
|
self.interaction = Interaction::Panning {
|
||||||
translation: self.translation,
|
translation: self.translation,
|
||||||
start: cursor_position,
|
start: cursor_position,
|
||||||
};
|
};
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
};
|
||||||
|
|
||||||
|
(event::Status::Captured, message)
|
||||||
|
}
|
||||||
mouse::Event::CursorMoved { .. } => {
|
mouse::Event::CursorMoved { .. } => {
|
||||||
match self.interaction {
|
let message = match self.interaction {
|
||||||
Interaction::Drawing => populate,
|
Interaction::Drawing => populate,
|
||||||
Interaction::Erasing => unpopulate,
|
Interaction::Erasing => unpopulate,
|
||||||
Interaction::Panning { translation, start } => {
|
Interaction::Panning { translation, start } => {
|
||||||
|
@ -380,7 +389,14 @@ mod grid {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let event_status = match self.interaction {
|
||||||
|
Interaction::None => event::Status::Ignored,
|
||||||
|
_ => event::Status::Captured,
|
||||||
|
};
|
||||||
|
|
||||||
|
(event_status, message)
|
||||||
}
|
}
|
||||||
mouse::Event::WheelScrolled { delta } => match delta {
|
mouse::Event::WheelScrolled { delta } => match delta {
|
||||||
mouse::ScrollDelta::Lines { y, .. }
|
mouse::ScrollDelta::Lines { y, .. }
|
||||||
|
@ -413,12 +429,12 @@ mod grid {
|
||||||
self.grid_cache.clear();
|
self.grid_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
(event::Status::Captured, None)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => (event::Status::Ignored, None),
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => (event::Status::Ignored, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use iced::{
|
||||||
Button, Column, Command, Container, Element, HorizontalAlignment, Length,
|
Button, Column, Command, Container, Element, HorizontalAlignment, Length,
|
||||||
PaneGrid, Scrollable, Settings, Subscription, Text,
|
PaneGrid, Scrollable, Settings, Subscription, Text,
|
||||||
};
|
};
|
||||||
use iced_native::{subscription, Event};
|
use iced_native::{event, subscription, Event};
|
||||||
|
|
||||||
pub fn main() -> iced::Result {
|
pub fn main() -> iced::Result {
|
||||||
Example::run(Settings::default())
|
Example::run(Settings::default())
|
||||||
|
@ -119,12 +119,18 @@ impl Application for Example {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
subscription::events_with(|event| match event {
|
subscription::events_with(|event, status| {
|
||||||
Event::Keyboard(keyboard::Event::KeyPressed {
|
if let event::Status::Captured = status {
|
||||||
modifiers,
|
return None;
|
||||||
key_code,
|
}
|
||||||
}) if modifiers.is_command_pressed() => handle_hotkey(key_code),
|
|
||||||
_ => None,
|
match event {
|
||||||
|
Event::Keyboard(keyboard::Event::KeyPressed {
|
||||||
|
modifiers,
|
||||||
|
key_code,
|
||||||
|
}) if modifiers.is_command_pressed() => handle_hotkey(key_code),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,29 +156,33 @@ async fn run_instance<A, E, C>(
|
||||||
let mut mouse_interaction = mouse::Interaction::default();
|
let mut mouse_interaction = mouse::Interaction::default();
|
||||||
|
|
||||||
let mut events = Vec::new();
|
let mut events = Vec::new();
|
||||||
let mut external_messages = Vec::new();
|
let mut messages = Vec::new();
|
||||||
|
|
||||||
debug.startup_finished();
|
debug.startup_finished();
|
||||||
|
|
||||||
while let Some(event) = receiver.next().await {
|
while let Some(event) = receiver.next().await {
|
||||||
match event {
|
match event {
|
||||||
event::Event::MainEventsCleared => {
|
event::Event::MainEventsCleared => {
|
||||||
if events.is_empty() && external_messages.is_empty() {
|
if events.is_empty() && messages.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.event_processing_started();
|
debug.event_processing_started();
|
||||||
let mut messages = user_interface.update(
|
|
||||||
|
let statuses = user_interface.update(
|
||||||
&events,
|
&events,
|
||||||
state.cursor_position(),
|
state.cursor_position(),
|
||||||
clipboard.as_ref().map(|c| c as _),
|
clipboard.as_ref().map(|c| c as _),
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
|
&mut messages,
|
||||||
);
|
);
|
||||||
|
|
||||||
messages.extend(external_messages.drain(..));
|
|
||||||
events.clear();
|
|
||||||
debug.event_processing_finished();
|
debug.event_processing_finished();
|
||||||
|
|
||||||
|
for event in events.drain(..).zip(statuses.into_iter()) {
|
||||||
|
runtime.broadcast(event);
|
||||||
|
}
|
||||||
|
|
||||||
if !messages.is_empty() {
|
if !messages.is_empty() {
|
||||||
let cache =
|
let cache =
|
||||||
ManuallyDrop::into_inner(user_interface).into_cache();
|
ManuallyDrop::into_inner(user_interface).into_cache();
|
||||||
|
@ -188,7 +192,7 @@ async fn run_instance<A, E, C>(
|
||||||
&mut application,
|
&mut application,
|
||||||
&mut runtime,
|
&mut runtime,
|
||||||
&mut debug,
|
&mut debug,
|
||||||
messages,
|
&mut messages,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update window
|
// Update window
|
||||||
|
@ -212,7 +216,7 @@ async fn run_instance<A, E, C>(
|
||||||
context.window().request_redraw();
|
context.window().request_redraw();
|
||||||
}
|
}
|
||||||
event::Event::UserEvent(message) => {
|
event::Event::UserEvent(message) => {
|
||||||
external_messages.push(message);
|
messages.push(message);
|
||||||
}
|
}
|
||||||
event::Event::RedrawRequested(_) => {
|
event::Event::RedrawRequested(_) => {
|
||||||
debug.render_started();
|
debug.render_started();
|
||||||
|
@ -283,8 +287,7 @@ async fn run_instance<A, E, C>(
|
||||||
state.scale_factor(),
|
state.scale_factor(),
|
||||||
state.modifiers(),
|
state.modifiers(),
|
||||||
) {
|
) {
|
||||||
events.push(event.clone());
|
events.push(event);
|
||||||
runtime.broadcast(event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -7,18 +7,20 @@
|
||||||
//! [`Canvas`]: struct.Canvas.html
|
//! [`Canvas`]: struct.Canvas.html
|
||||||
//! [`Frame`]: struct.Frame.html
|
//! [`Frame`]: struct.Frame.html
|
||||||
use crate::{Backend, Defaults, Primitive, Renderer};
|
use crate::{Backend, Defaults, Primitive, Renderer};
|
||||||
|
use iced_native::layout;
|
||||||
|
use iced_native::mouse;
|
||||||
use iced_native::{
|
use iced_native::{
|
||||||
layout, mouse, Clipboard, Element, Hasher, Layout, Length, Point,
|
Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Vector,
|
||||||
Rectangle, Size, Vector, Widget,
|
Widget,
|
||||||
};
|
};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub mod event;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
|
|
||||||
mod cache;
|
mod cache;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod event;
|
|
||||||
mod fill;
|
mod fill;
|
||||||
mod frame;
|
mod frame;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
|
@ -166,7 +168,7 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
_renderer: &Renderer<B>,
|
_renderer: &Renderer<B>,
|
||||||
_clipboard: Option<&dyn Clipboard>,
|
_clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
|
||||||
let canvas_event = match event {
|
let canvas_event = match event {
|
||||||
|
@ -182,12 +184,17 @@ where
|
||||||
let cursor = Cursor::from_window_position(cursor_position);
|
let cursor = Cursor::from_window_position(cursor_position);
|
||||||
|
|
||||||
if let Some(canvas_event) = canvas_event {
|
if let Some(canvas_event) = canvas_event {
|
||||||
if let Some(message) =
|
let (event_status, message) =
|
||||||
self.program.update(canvas_event, bounds, cursor)
|
self.program.update(canvas_event, bounds, cursor);
|
||||||
{
|
|
||||||
|
if let Some(message) = message {
|
||||||
messages.push(message);
|
messages.push(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return event_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
//! Handle events of a canvas.
|
||||||
use iced_native::keyboard;
|
use iced_native::keyboard;
|
||||||
use iced_native::mouse;
|
use iced_native::mouse;
|
||||||
|
|
||||||
|
pub use iced_native::event::Status;
|
||||||
|
|
||||||
/// A [`Canvas`] event.
|
/// A [`Canvas`] event.
|
||||||
///
|
///
|
||||||
/// [`Canvas`]: struct.Event.html
|
/// [`Canvas`]: struct.Event.html
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::canvas::{Cursor, Event, Geometry};
|
use crate::canvas::event::{self, Event};
|
||||||
|
use crate::canvas::{Cursor, Geometry};
|
||||||
use iced_native::{mouse, Rectangle};
|
use iced_native::{mouse, Rectangle};
|
||||||
|
|
||||||
/// The state and logic of a [`Canvas`].
|
/// The state and logic of a [`Canvas`].
|
||||||
|
@ -27,8 +28,8 @@ pub trait Program<Message> {
|
||||||
_event: Event,
|
_event: Event,
|
||||||
_bounds: Rectangle,
|
_bounds: Rectangle,
|
||||||
_cursor: Cursor,
|
_cursor: Cursor,
|
||||||
) -> Option<Message> {
|
) -> (event::Status, Option<Message>) {
|
||||||
None
|
(event::Status::Ignored, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the state of the [`Program`], producing a bunch of [`Geometry`].
|
/// Draws the state of the [`Program`], producing a bunch of [`Geometry`].
|
||||||
|
@ -67,7 +68,7 @@ where
|
||||||
event: Event,
|
event: Event,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
) -> Option<Message> {
|
) -> (event::Status, Option<Message>) {
|
||||||
T::update(self, event, bounds, cursor)
|
T::update(self, event, bounds, cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
use crate::event::{self, Event};
|
||||||
use crate::layout;
|
use crate::layout;
|
||||||
use crate::overlay;
|
use crate::overlay;
|
||||||
use crate::{
|
use crate::{
|
||||||
Clipboard, Color, Event, Hasher, Layout, Length, Point, Rectangle, Widget,
|
Clipboard, Color, Hasher, Layout, Length, Point, Rectangle, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A generic [`Widget`].
|
/// A generic [`Widget`].
|
||||||
|
@ -240,7 +241,7 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
self.widget.on_event(
|
self.widget.on_event(
|
||||||
event,
|
event,
|
||||||
layout,
|
layout,
|
||||||
|
@ -248,7 +249,7 @@ where
|
||||||
messages,
|
messages,
|
||||||
renderer,
|
renderer,
|
||||||
clipboard,
|
clipboard,
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the [`Element`] and its children using the given [`Layout`].
|
/// Draws the [`Element`] and its children using the given [`Layout`].
|
||||||
|
@ -335,10 +336,10 @@ where
|
||||||
messages: &mut Vec<B>,
|
messages: &mut Vec<B>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
let mut original_messages = Vec::new();
|
let mut original_messages = Vec::new();
|
||||||
|
|
||||||
self.widget.on_event(
|
let status = self.widget.on_event(
|
||||||
event,
|
event,
|
||||||
layout,
|
layout,
|
||||||
cursor_position,
|
cursor_position,
|
||||||
|
@ -350,6 +351,8 @@ where
|
||||||
original_messages
|
original_messages
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.for_each(|message| messages.push((self.mapper)(message)));
|
.for_each(|message| messages.push((self.mapper)(message)));
|
||||||
|
|
||||||
|
status
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
@ -423,7 +426,7 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
self.element.widget.on_event(
|
self.element.widget.on_event(
|
||||||
event,
|
event,
|
||||||
layout,
|
layout,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//! Handle events of a user interface.
|
||||||
use crate::{keyboard, mouse, window};
|
use crate::{keyboard, mouse, window};
|
||||||
|
|
||||||
/// A user interface event.
|
/// A user interface event.
|
||||||
|
@ -6,7 +7,7 @@ use crate::{keyboard, mouse, window};
|
||||||
/// additional events, feel free to [open an issue] and share your use case!_
|
/// additional events, feel free to [open an issue] and share your use case!_
|
||||||
///
|
///
|
||||||
/// [open an issue]: https://github.com/hecrj/iced/issues
|
/// [open an issue]: https://github.com/hecrj/iced/issues
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
/// A keyboard event
|
/// A keyboard event
|
||||||
Keyboard(keyboard::Event),
|
Keyboard(keyboard::Event),
|
||||||
|
@ -17,3 +18,41 @@ pub enum Event {
|
||||||
/// A window event
|
/// A window event
|
||||||
Window(window::Event),
|
Window(window::Event),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The status of an [`Event`] after being processed.
|
||||||
|
///
|
||||||
|
/// [`Event`]: enum.Event.html
|
||||||
|
/// [`UserInterface`]: ../struct.UserInterface.html
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Status {
|
||||||
|
/// The [`Event`] was **NOT** handled by any widget.
|
||||||
|
///
|
||||||
|
/// [`Event`]: enum.Event.html
|
||||||
|
Ignored,
|
||||||
|
|
||||||
|
/// The [`Event`] was handled and processed by a widget.
|
||||||
|
///
|
||||||
|
/// [`Event`]: enum.Event.html
|
||||||
|
Captured,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Status {
|
||||||
|
/// Merges two [`Status`] into one.
|
||||||
|
///
|
||||||
|
/// `Captured` takes precedence over `Ignored`:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use iced_native::event::Status;
|
||||||
|
///
|
||||||
|
/// assert_eq!(Status::Ignored.merge(Status::Ignored), Status::Ignored);
|
||||||
|
/// assert_eq!(Status::Ignored.merge(Status::Captured), Status::Captured);
|
||||||
|
/// assert_eq!(Status::Captured.merge(Status::Ignored), Status::Captured);
|
||||||
|
/// assert_eq!(Status::Captured.merge(Status::Captured), Status::Captured);
|
||||||
|
/// ```
|
||||||
|
pub fn merge(self, b: Self) -> Self {
|
||||||
|
match self {
|
||||||
|
Status::Ignored => b,
|
||||||
|
Status::Captured => Status::Captured,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#![deny(unused_results)]
|
#![deny(unused_results)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![forbid(rust_2018_idioms)]
|
#![forbid(rust_2018_idioms)]
|
||||||
|
pub mod event;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod mouse;
|
pub mod mouse;
|
||||||
|
@ -47,7 +48,6 @@ pub mod window;
|
||||||
|
|
||||||
mod clipboard;
|
mod clipboard;
|
||||||
mod element;
|
mod element;
|
||||||
mod event;
|
|
||||||
mod hasher;
|
mod hasher;
|
||||||
mod runtime;
|
mod runtime;
|
||||||
mod user_interface;
|
mod user_interface;
|
||||||
|
|
|
@ -6,7 +6,9 @@ pub mod menu;
|
||||||
pub use element::Element;
|
pub use element::Element;
|
||||||
pub use menu::Menu;
|
pub use menu::Menu;
|
||||||
|
|
||||||
use crate::{layout, Clipboard, Event, Hasher, Layout, Point, Size};
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::{Clipboard, Hasher, Layout, Point, Size};
|
||||||
|
|
||||||
/// An interactive component that can be displayed on top of other widgets.
|
/// An interactive component that can be displayed on top of other widgets.
|
||||||
pub trait Overlay<Message, Renderer>
|
pub trait Overlay<Message, Renderer>
|
||||||
|
@ -79,6 +81,7 @@ where
|
||||||
_messages: &mut Vec<Message>,
|
_messages: &mut Vec<Message>,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
_clipboard: Option<&dyn Clipboard>,
|
_clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
pub use crate::Overlay;
|
pub use crate::Overlay;
|
||||||
|
|
||||||
use crate::{layout, Clipboard, Event, Hasher, Layout, Point, Size, Vector};
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::{Clipboard, Hasher, Layout, Point, Size, Vector};
|
||||||
|
|
||||||
/// A generic [`Overlay`].
|
/// A generic [`Overlay`].
|
||||||
///
|
///
|
||||||
|
@ -67,7 +69,7 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
self.overlay.on_event(
|
self.overlay.on_event(
|
||||||
event,
|
event,
|
||||||
layout,
|
layout,
|
||||||
|
@ -136,10 +138,10 @@ where
|
||||||
messages: &mut Vec<B>,
|
messages: &mut Vec<B>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
let mut original_messages = Vec::new();
|
let mut original_messages = Vec::new();
|
||||||
|
|
||||||
self.content.on_event(
|
let event_status = self.content.on_event(
|
||||||
event,
|
event,
|
||||||
layout,
|
layout,
|
||||||
cursor_position,
|
cursor_position,
|
||||||
|
@ -151,6 +153,8 @@ where
|
||||||
original_messages
|
original_messages
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.for_each(|message| messages.push((self.mapper)(message)));
|
.for_each(|message| messages.push((self.mapper)(message)));
|
||||||
|
|
||||||
|
event_status
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
//! Build and show dropdown menus.
|
//! Build and show dropdown menus.
|
||||||
|
use crate::container;
|
||||||
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::mouse;
|
||||||
|
use crate::overlay;
|
||||||
|
use crate::scrollable;
|
||||||
|
use crate::text;
|
||||||
use crate::{
|
use crate::{
|
||||||
container, layout, mouse, overlay, scrollable, text, Clipboard, Container,
|
Clipboard, Container, Element, Hasher, Layout, Length, Point, Rectangle,
|
||||||
Element, Event, Hasher, Layout, Length, Point, Rectangle, Scrollable, Size,
|
Scrollable, Size, Vector, Widget,
|
||||||
Vector, Widget,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A list of selectable options.
|
/// A list of selectable options.
|
||||||
|
@ -235,7 +241,7 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
self.container.on_event(
|
self.container.on_event(
|
||||||
event.clone(),
|
event.clone(),
|
||||||
layout,
|
layout,
|
||||||
|
@ -243,7 +249,7 @@ where
|
||||||
messages,
|
messages,
|
||||||
renderer,
|
renderer,
|
||||||
clipboard,
|
clipboard,
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
@ -336,7 +342,7 @@ where
|
||||||
_messages: &mut Vec<Message>,
|
_messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
_clipboard: Option<&dyn Clipboard>,
|
_clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
@ -364,6 +370,8 @@ where
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -120,14 +120,17 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
debug.event_processing_started();
|
debug.event_processing_started();
|
||||||
let mut messages = user_interface.update(
|
let mut messages = Vec::new();
|
||||||
|
|
||||||
|
let _ = user_interface.update(
|
||||||
&self.queued_events,
|
&self.queued_events,
|
||||||
cursor_position,
|
cursor_position,
|
||||||
clipboard,
|
clipboard,
|
||||||
renderer,
|
renderer,
|
||||||
|
&mut messages,
|
||||||
);
|
);
|
||||||
messages.extend(self.queued_messages.drain(..));
|
|
||||||
|
|
||||||
|
messages.extend(self.queued_messages.drain(..));
|
||||||
self.queued_events.clear();
|
self.queued_events.clear();
|
||||||
debug.event_processing_finished();
|
debug.event_processing_finished();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! Run commands and subscriptions.
|
//! Run commands and subscriptions.
|
||||||
use crate::{Event, Hasher};
|
use crate::event::{self, Event};
|
||||||
|
use crate::Hasher;
|
||||||
|
|
||||||
/// A native runtime with a generic executor and receiver of results.
|
/// A native runtime with a generic executor and receiver of results.
|
||||||
///
|
///
|
||||||
|
@ -8,5 +9,10 @@ use crate::{Event, Hasher};
|
||||||
///
|
///
|
||||||
/// [`Command`]: ../struct.Command.html
|
/// [`Command`]: ../struct.Command.html
|
||||||
/// [`Subscription`]: ../struct.Subscription.html
|
/// [`Subscription`]: ../struct.Subscription.html
|
||||||
pub type Runtime<Executor, Receiver, Message> =
|
pub type Runtime<Executor, Receiver, Message> = iced_futures::Runtime<
|
||||||
iced_futures::Runtime<Hasher, Event, Executor, Receiver, Message>;
|
Hasher,
|
||||||
|
(Event, event::Status),
|
||||||
|
Executor,
|
||||||
|
Receiver,
|
||||||
|
Message,
|
||||||
|
>;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! Listen to external events in your application.
|
//! Listen to external events in your application.
|
||||||
use crate::{Event, Hasher};
|
use crate::event::{self, Event};
|
||||||
|
use crate::Hasher;
|
||||||
use iced_futures::futures::stream::BoxStream;
|
use iced_futures::futures::stream::BoxStream;
|
||||||
|
|
||||||
/// A request to listen to external events.
|
/// A request to listen to external events.
|
||||||
|
@ -15,19 +16,21 @@ use iced_futures::futures::stream::BoxStream;
|
||||||
///
|
///
|
||||||
/// [`Command`]: ../struct.Command.html
|
/// [`Command`]: ../struct.Command.html
|
||||||
/// [`Subscription`]: struct.Subscription.html
|
/// [`Subscription`]: struct.Subscription.html
|
||||||
pub type Subscription<T> = iced_futures::Subscription<Hasher, Event, T>;
|
pub type Subscription<T> =
|
||||||
|
iced_futures::Subscription<Hasher, (Event, event::Status), T>;
|
||||||
|
|
||||||
/// A stream of runtime events.
|
/// A stream of runtime events.
|
||||||
///
|
///
|
||||||
/// It is the input of a [`Subscription`] in the native runtime.
|
/// It is the input of a [`Subscription`] in the native runtime.
|
||||||
///
|
///
|
||||||
/// [`Subscription`]: type.Subscription.html
|
/// [`Subscription`]: type.Subscription.html
|
||||||
pub type EventStream = BoxStream<'static, Event>;
|
pub type EventStream = BoxStream<'static, (Event, event::Status)>;
|
||||||
|
|
||||||
/// A native [`Subscription`] tracker.
|
/// A native [`Subscription`] tracker.
|
||||||
///
|
///
|
||||||
/// [`Subscription`]: type.Subscription.html
|
/// [`Subscription`]: type.Subscription.html
|
||||||
pub type Tracker = iced_futures::subscription::Tracker<Hasher, Event>;
|
pub type Tracker =
|
||||||
|
iced_futures::subscription::Tracker<Hasher, (Event, event::Status)>;
|
||||||
|
|
||||||
pub use iced_futures::subscription::Recipe;
|
pub use iced_futures::subscription::Recipe;
|
||||||
|
|
||||||
|
@ -37,13 +40,18 @@ use events::Events;
|
||||||
|
|
||||||
/// Returns a [`Subscription`] to all the runtime events.
|
/// Returns a [`Subscription`] to all the runtime events.
|
||||||
///
|
///
|
||||||
/// This subscription will notify your application of any [`Event`] handled by
|
/// This subscription will notify your application of any [`Event`] that was
|
||||||
/// the runtime.
|
/// not captured by any widget.
|
||||||
///
|
///
|
||||||
/// [`Subscription`]: type.Subscription.html
|
/// [`Subscription`]: type.Subscription.html
|
||||||
/// [`Event`]: ../enum.Event.html
|
/// [`Event`]: ../enum.Event.html
|
||||||
pub fn events() -> Subscription<Event> {
|
pub fn events() -> Subscription<Event> {
|
||||||
Subscription::from_recipe(Events { f: Some })
|
Subscription::from_recipe(Events {
|
||||||
|
f: |event, status| match status {
|
||||||
|
event::Status::Ignored => Some(event),
|
||||||
|
event::Status::Captured => None,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a [`Subscription`] that filters all the runtime events with the
|
/// Returns a [`Subscription`] that filters all the runtime events with the
|
||||||
|
@ -58,7 +66,7 @@ pub fn events() -> Subscription<Event> {
|
||||||
/// [`Subscription`]: type.Subscription.html
|
/// [`Subscription`]: type.Subscription.html
|
||||||
/// [`Event`]: ../enum.Event.html
|
/// [`Event`]: ../enum.Event.html
|
||||||
pub fn events_with<Message>(
|
pub fn events_with<Message>(
|
||||||
f: fn(Event) -> Option<Message>,
|
f: fn(Event, event::Status) -> Option<Message>,
|
||||||
) -> Subscription<Message>
|
) -> Subscription<Message>
|
||||||
where
|
where
|
||||||
Message: 'static + Send,
|
Message: 'static + Send,
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
use crate::{
|
use crate::event::{self, Event};
|
||||||
subscription::{EventStream, Recipe},
|
use crate::subscription::{EventStream, Recipe};
|
||||||
Event, Hasher,
|
use crate::Hasher;
|
||||||
};
|
|
||||||
use iced_futures::futures::future;
|
use iced_futures::futures::future;
|
||||||
use iced_futures::futures::StreamExt;
|
use iced_futures::futures::StreamExt;
|
||||||
use iced_futures::BoxStream;
|
use iced_futures::BoxStream;
|
||||||
|
|
||||||
pub struct Events<Message> {
|
pub struct Events<Message> {
|
||||||
pub(super) f: fn(Event) -> Option<Message>,
|
pub(super) f: fn(Event, event::Status) -> Option<Message>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message> Recipe<Hasher, Event> for Events<Message>
|
impl<Message> Recipe<Hasher, (Event, event::Status)> for Events<Message>
|
||||||
where
|
where
|
||||||
Message: 'static + Send,
|
Message: 'static + Send,
|
||||||
{
|
{
|
||||||
|
@ -29,7 +28,9 @@ where
|
||||||
event_stream: EventStream,
|
event_stream: EventStream,
|
||||||
) -> BoxStream<Self::Output> {
|
) -> BoxStream<Self::Output> {
|
||||||
event_stream
|
event_stream
|
||||||
.filter_map(move |event| future::ready((self.f)(event)))
|
.filter_map(move |(event, status)| {
|
||||||
|
future::ready((self.f)(event, status))
|
||||||
|
})
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
use crate::event::{self, Event};
|
||||||
use crate::layout;
|
use crate::layout;
|
||||||
use crate::overlay;
|
use crate::overlay;
|
||||||
use crate::{Clipboard, Element, Event, Layout, Point, Rectangle, Size};
|
use crate::{Clipboard, Element, Layout, Point, Rectangle, Size};
|
||||||
|
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
|
|
||||||
|
@ -169,9 +170,10 @@ where
|
||||||
///
|
///
|
||||||
/// // Initialize our event storage
|
/// // Initialize our event storage
|
||||||
/// let mut events = Vec::new();
|
/// let mut events = Vec::new();
|
||||||
|
/// let mut messages = Vec::new();
|
||||||
///
|
///
|
||||||
/// loop {
|
/// loop {
|
||||||
/// // Process system events...
|
/// // Obtain system events...
|
||||||
///
|
///
|
||||||
/// let mut user_interface = UserInterface::build(
|
/// let mut user_interface = UserInterface::build(
|
||||||
/// counter.view(),
|
/// counter.view(),
|
||||||
|
@ -181,17 +183,18 @@ where
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
/// // Update the user interface
|
/// // Update the user interface
|
||||||
/// let messages = user_interface.update(
|
/// let event_statuses = user_interface.update(
|
||||||
/// &events,
|
/// &events,
|
||||||
/// cursor_position,
|
/// cursor_position,
|
||||||
/// None,
|
/// None,
|
||||||
/// &renderer,
|
/// &renderer,
|
||||||
|
/// &mut messages
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
/// cache = user_interface.into_cache();
|
/// cache = user_interface.into_cache();
|
||||||
///
|
///
|
||||||
/// // Process the produced messages
|
/// // Process the produced messages
|
||||||
/// for message in messages {
|
/// for message in messages.drain(..) {
|
||||||
/// counter.update(message);
|
/// counter.update(message);
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
@ -202,10 +205,9 @@ where
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
) -> Vec<Message> {
|
messages: &mut Vec<Message>,
|
||||||
let mut messages = Vec::new();
|
) -> Vec<event::Status> {
|
||||||
|
let (base_cursor, overlay_statuses) = if let Some(mut overlay) =
|
||||||
let base_cursor = if let Some(mut overlay) =
|
|
||||||
self.root.overlay(Layout::new(&self.base.layout))
|
self.root.overlay(Layout::new(&self.base.layout))
|
||||||
{
|
{
|
||||||
let layer = Self::overlay_layer(
|
let layer = Self::overlay_layer(
|
||||||
|
@ -215,16 +217,20 @@ where
|
||||||
renderer,
|
renderer,
|
||||||
);
|
);
|
||||||
|
|
||||||
for event in events {
|
let event_statuses = events
|
||||||
overlay.on_event(
|
.iter()
|
||||||
event.clone(),
|
.cloned()
|
||||||
Layout::new(&layer.layout),
|
.map(|event| {
|
||||||
cursor_position,
|
overlay.on_event(
|
||||||
&mut messages,
|
event,
|
||||||
renderer,
|
Layout::new(&layer.layout),
|
||||||
clipboard,
|
cursor_position,
|
||||||
);
|
messages,
|
||||||
}
|
renderer,
|
||||||
|
clipboard,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let base_cursor = if layer.layout.bounds().contains(cursor_position)
|
let base_cursor = if layer.layout.bounds().contains(cursor_position)
|
||||||
{
|
{
|
||||||
|
@ -236,23 +242,28 @@ where
|
||||||
|
|
||||||
self.overlay = Some(layer);
|
self.overlay = Some(layer);
|
||||||
|
|
||||||
base_cursor
|
(base_cursor, event_statuses)
|
||||||
} else {
|
} else {
|
||||||
cursor_position
|
(cursor_position, vec![event::Status::Ignored; events.len()])
|
||||||
};
|
};
|
||||||
|
|
||||||
for event in events {
|
events
|
||||||
self.root.widget.on_event(
|
.iter()
|
||||||
event.clone(),
|
.cloned()
|
||||||
Layout::new(&self.base.layout),
|
.zip(overlay_statuses.into_iter())
|
||||||
base_cursor,
|
.map(|(event, overlay_status)| {
|
||||||
&mut messages,
|
let event_status = self.root.widget.on_event(
|
||||||
renderer,
|
event,
|
||||||
clipboard,
|
Layout::new(&self.base.layout),
|
||||||
);
|
base_cursor,
|
||||||
}
|
messages,
|
||||||
|
renderer,
|
||||||
|
clipboard,
|
||||||
|
);
|
||||||
|
|
||||||
messages
|
event_status.merge(overlay_status)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the [`UserInterface`] with the provided [`Renderer`].
|
/// Draws the [`UserInterface`] with the provided [`Renderer`].
|
||||||
|
@ -293,9 +304,10 @@ where
|
||||||
/// let mut window_size = Size::new(1024.0, 768.0);
|
/// let mut window_size = Size::new(1024.0, 768.0);
|
||||||
/// let mut cursor_position = Point::default();
|
/// let mut cursor_position = Point::default();
|
||||||
/// let mut events = Vec::new();
|
/// let mut events = Vec::new();
|
||||||
|
/// let mut messages = Vec::new();
|
||||||
///
|
///
|
||||||
/// loop {
|
/// loop {
|
||||||
/// // Process system events...
|
/// // Obtain system events...
|
||||||
///
|
///
|
||||||
/// let mut user_interface = UserInterface::build(
|
/// let mut user_interface = UserInterface::build(
|
||||||
/// counter.view(),
|
/// counter.view(),
|
||||||
|
@ -304,11 +316,13 @@ where
|
||||||
/// &mut renderer,
|
/// &mut renderer,
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
/// let messages = user_interface.update(
|
/// // Update the user interface
|
||||||
|
/// let event_statuses = user_interface.update(
|
||||||
/// &events,
|
/// &events,
|
||||||
/// cursor_position,
|
/// cursor_position,
|
||||||
/// None,
|
/// None,
|
||||||
/// &renderer,
|
/// &renderer,
|
||||||
|
/// &mut messages
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
/// // Draw the user interface
|
/// // Draw the user interface
|
||||||
|
@ -316,7 +330,7 @@ where
|
||||||
///
|
///
|
||||||
/// cache = user_interface.into_cache();
|
/// cache = user_interface.into_cache();
|
||||||
///
|
///
|
||||||
/// for message in messages {
|
/// for message in messages.drain(..) {
|
||||||
/// counter.update(message);
|
/// counter.update(message);
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
|
|
|
@ -73,9 +73,10 @@ pub use text::Text;
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use text_input::TextInput;
|
pub use text_input::TextInput;
|
||||||
|
|
||||||
use crate::{
|
use crate::event::{self, Event};
|
||||||
layout, overlay, Clipboard, Event, Hasher, Layout, Length, Point, Rectangle,
|
use crate::layout;
|
||||||
};
|
use crate::overlay;
|
||||||
|
use crate::{Clipboard, Hasher, Layout, Length, Point, Rectangle};
|
||||||
|
|
||||||
/// A component that displays information and allows interaction.
|
/// A component that displays information and allows interaction.
|
||||||
///
|
///
|
||||||
|
@ -182,7 +183,8 @@ where
|
||||||
_messages: &mut Vec<Message>,
|
_messages: &mut Vec<Message>,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
_clipboard: Option<&dyn Clipboard>,
|
_clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the overlay of the [`Element`], if there is any.
|
/// Returns the overlay of the [`Element`], if there is any.
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
//!
|
//!
|
||||||
//! [`Button`]: struct.Button.html
|
//! [`Button`]: struct.Button.html
|
||||||
//! [`State`]: struct.State.html
|
//! [`State`]: struct.State.html
|
||||||
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::mouse;
|
||||||
use crate::{
|
use crate::{
|
||||||
layout, mouse, Clipboard, Element, Event, Hasher, Layout, Length, Point,
|
Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Widget,
|
||||||
Rectangle, Widget,
|
|
||||||
};
|
};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
@ -184,31 +186,38 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
_clipboard: Option<&dyn Clipboard>,
|
_clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
||||||
if self.on_press.is_some() {
|
if self.on_press.is_some() {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
|
||||||
self.state.is_pressed = bounds.contains(cursor_position);
|
if bounds.contains(cursor_position) {
|
||||||
|
self.state.is_pressed = true;
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => {
|
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => {
|
||||||
if let Some(on_press) = self.on_press.clone() {
|
if let Some(on_press) = self.on_press.clone() {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
|
||||||
let is_clicked = self.state.is_pressed
|
if self.state.is_pressed {
|
||||||
&& bounds.contains(cursor_position);
|
self.state.is_pressed = false;
|
||||||
|
|
||||||
self.state.is_pressed = false;
|
if bounds.contains(cursor_position) {
|
||||||
|
messages.push(on_press);
|
||||||
|
}
|
||||||
|
|
||||||
if is_clicked {
|
return event::Status::Captured;
|
||||||
messages.push(on_press);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
//! Show toggle controls using checkboxes.
|
//! Show toggle controls using checkboxes.
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::mouse;
|
||||||
|
use crate::row;
|
||||||
|
use crate::text;
|
||||||
use crate::{
|
use crate::{
|
||||||
layout, mouse, row, text, Align, Clipboard, Element, Event, Hasher,
|
Align, Clipboard, Element, Hasher, HorizontalAlignment, Layout, Length,
|
||||||
HorizontalAlignment, Layout, Length, Point, Rectangle, Row, Text,
|
Point, Rectangle, Row, Text, VerticalAlignment, Widget,
|
||||||
VerticalAlignment, Widget,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A box that can be checked.
|
/// A box that can be checked.
|
||||||
|
@ -161,17 +165,21 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
_clipboard: Option<&dyn Clipboard>,
|
_clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
||||||
let mouse_over = layout.bounds().contains(cursor_position);
|
let mouse_over = layout.bounds().contains(cursor_position);
|
||||||
|
|
||||||
if mouse_over {
|
if mouse_over {
|
||||||
messages.push((self.on_toggle)(!self.is_checked));
|
messages.push((self.on_toggle)(!self.is_checked));
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
//! Distribute content vertically.
|
//! Distribute content vertically.
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
use crate::event::{self, Event};
|
||||||
use crate::layout;
|
use crate::layout;
|
||||||
use crate::overlay;
|
use crate::overlay;
|
||||||
use crate::{
|
use crate::{
|
||||||
Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, Rectangle,
|
Align, Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Widget,
|
||||||
Widget,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::u32;
|
use std::u32;
|
||||||
|
@ -162,9 +162,11 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
self.children.iter_mut().zip(layout.children()).for_each(
|
self.children
|
||||||
|(child, layout)| {
|
.iter_mut()
|
||||||
|
.zip(layout.children())
|
||||||
|
.map(|(child, layout)| {
|
||||||
child.widget.on_event(
|
child.widget.on_event(
|
||||||
event.clone(),
|
event.clone(),
|
||||||
layout,
|
layout,
|
||||||
|
@ -173,8 +175,8 @@ where
|
||||||
renderer,
|
renderer,
|
||||||
clipboard,
|
clipboard,
|
||||||
)
|
)
|
||||||
},
|
})
|
||||||
);
|
.fold(event::Status::Ignored, event::Status::merge)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
//! Decorate content and apply alignment.
|
//! Decorate content and apply alignment.
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::overlay;
|
||||||
use crate::{
|
use crate::{
|
||||||
layout, overlay, Align, Clipboard, Element, Event, Hasher, Layout, Length,
|
Align, Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Widget,
|
||||||
Point, Rectangle, Widget,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::u32;
|
use std::u32;
|
||||||
|
@ -174,7 +176,7 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
self.content.widget.on_event(
|
self.content.widget.on_event(
|
||||||
event,
|
event,
|
||||||
layout.children().next().unwrap(),
|
layout.children().next().unwrap(),
|
||||||
|
|
|
@ -28,9 +28,16 @@ pub use split::Split;
|
||||||
pub use state::{Focus, State};
|
pub use state::{Focus, State};
|
||||||
pub use title_bar::TitleBar;
|
pub use title_bar::TitleBar;
|
||||||
|
|
||||||
|
use crate::container;
|
||||||
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::mouse;
|
||||||
|
use crate::overlay;
|
||||||
|
use crate::row;
|
||||||
|
use crate::text;
|
||||||
use crate::{
|
use crate::{
|
||||||
container, layout, mouse, overlay, row, text, Clipboard, Element, Event,
|
Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Vector,
|
||||||
Hasher, Layout, Length, Point, Rectangle, Size, Vector, Widget,
|
Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A collection of panes distributed using either vertical or horizontal splits
|
/// A collection of panes distributed using either vertical or horizontal splits
|
||||||
|
@ -242,7 +249,7 @@ where
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
) {
|
) -> event::Status {
|
||||||
if let Some((_, on_resize)) = &self.on_resize {
|
if let Some((_, on_resize)) = &self.on_resize {
|
||||||
if let Some((split, _)) = self.state.picked_split() {
|
if let Some((split, _)) = self.state.picked_split() {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
@ -269,9 +276,13 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
messages.push(on_resize(ResizeEvent { split, ratio }));
|
messages.push(on_resize(ResizeEvent { split, ratio }));
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,13 +397,17 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
|
let mut event_status = event::Status::Ignored;
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse_event) => match mouse_event {
|
Event::Mouse(mouse_event) => match mouse_event {
|
||||||
mouse::Event::ButtonPressed(mouse::Button::Left) => {
|
mouse::Event::ButtonPressed(mouse::Button::Left) => {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
|
||||||
if bounds.contains(cursor_position) {
|
if bounds.contains(cursor_position) {
|
||||||
|
event_status = event::Status::Captured;
|
||||||
|
|
||||||
match self.on_resize {
|
match self.on_resize {
|
||||||
Some((leeway, _)) => {
|
Some((leeway, _)) => {
|
||||||
let relative_cursor = Point::new(
|
let relative_cursor = Point::new(
|
||||||
|
@ -456,12 +471,17 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state.idle();
|
self.state.idle();
|
||||||
|
|
||||||
|
event_status = event::Status::Captured;
|
||||||
} else if self.state.picked_split().is_some() {
|
} else if self.state.picked_split().is_some() {
|
||||||
self.state.idle();
|
self.state.idle();
|
||||||
|
|
||||||
|
event_status = event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mouse::Event::CursorMoved { .. } => {
|
mouse::Event::CursorMoved { .. } => {
|
||||||
self.trigger_resize(layout, cursor_position, messages);
|
event_status =
|
||||||
|
self.trigger_resize(layout, cursor_position, messages);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
|
@ -469,20 +489,22 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.state.picked_pane().is_none() {
|
if self.state.picked_pane().is_none() {
|
||||||
{
|
self.elements
|
||||||
self.elements.iter_mut().zip(layout.children()).for_each(
|
.iter_mut()
|
||||||
|((_, pane), layout)| {
|
.zip(layout.children())
|
||||||
pane.on_event(
|
.map(|((_, pane), layout)| {
|
||||||
event.clone(),
|
pane.on_event(
|
||||||
layout,
|
event.clone(),
|
||||||
cursor_position,
|
layout,
|
||||||
messages,
|
cursor_position,
|
||||||
renderer,
|
messages,
|
||||||
clipboard,
|
renderer,
|
||||||
)
|
clipboard,
|
||||||
},
|
)
|
||||||
);
|
})
|
||||||
}
|
.fold(event_status, event::Status::merge)
|
||||||
|
} else {
|
||||||
|
event::Status::Captured
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::container;
|
use crate::container;
|
||||||
|
use crate::event::{self, Event};
|
||||||
use crate::layout;
|
use crate::layout;
|
||||||
use crate::overlay;
|
use crate::overlay;
|
||||||
use crate::pane_grid::{self, TitleBar};
|
use crate::pane_grid::{self, TitleBar};
|
||||||
use crate::{Clipboard, Element, Event, Hasher, Layout, Point, Size};
|
use crate::{Clipboard, Element, Hasher, Layout, Point, Size};
|
||||||
|
|
||||||
/// The content of a [`Pane`].
|
/// The content of a [`Pane`].
|
||||||
///
|
///
|
||||||
|
@ -154,11 +155,13 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
|
let mut event_status = event::Status::Ignored;
|
||||||
|
|
||||||
let body_layout = if let Some(title_bar) = &mut self.title_bar {
|
let body_layout = if let Some(title_bar) = &mut self.title_bar {
|
||||||
let mut children = layout.children();
|
let mut children = layout.children();
|
||||||
|
|
||||||
title_bar.on_event(
|
event_status = title_bar.on_event(
|
||||||
event.clone(),
|
event.clone(),
|
||||||
children.next().unwrap(),
|
children.next().unwrap(),
|
||||||
cursor_position,
|
cursor_position,
|
||||||
|
@ -172,7 +175,7 @@ where
|
||||||
layout
|
layout
|
||||||
};
|
};
|
||||||
|
|
||||||
self.body.on_event(
|
let body_status = self.body.on_event(
|
||||||
event,
|
event,
|
||||||
body_layout,
|
body_layout,
|
||||||
cursor_position,
|
cursor_position,
|
||||||
|
@ -180,6 +183,8 @@ where
|
||||||
renderer,
|
renderer,
|
||||||
clipboard,
|
clipboard,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
event_status.merge(body_status)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn hash_layout(&self, state: &mut Hasher) {
|
pub(crate) fn hash_layout(&self, state: &mut Hasher) {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
|
use crate::event::{self, Event};
|
||||||
use crate::layout;
|
use crate::layout;
|
||||||
use crate::pane_grid;
|
use crate::pane_grid;
|
||||||
use crate::{
|
use crate::{Clipboard, Element, Hasher, Layout, Point, Rectangle, Size};
|
||||||
Clipboard, Element, Event, Hasher, Layout, Point, Rectangle, Size,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The title bar of a [`Pane`].
|
/// The title bar of a [`Pane`].
|
||||||
///
|
///
|
||||||
|
@ -245,7 +244,7 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
if let Some(controls) = &mut self.controls {
|
if let Some(controls) = &mut self.controls {
|
||||||
let mut children = layout.children();
|
let mut children = layout.children();
|
||||||
let padded = children.next().unwrap();
|
let padded = children.next().unwrap();
|
||||||
|
@ -261,7 +260,9 @@ where
|
||||||
messages,
|
messages,
|
||||||
renderer,
|
renderer,
|
||||||
clipboard,
|
clipboard,
|
||||||
);
|
)
|
||||||
|
} else {
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
//! Display a dropdown list of selectable values.
|
//! Display a dropdown list of selectable values.
|
||||||
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::mouse;
|
||||||
|
use crate::overlay;
|
||||||
|
use crate::overlay::menu::{self, Menu};
|
||||||
|
use crate::scrollable;
|
||||||
|
use crate::text;
|
||||||
use crate::{
|
use crate::{
|
||||||
layout, mouse, overlay,
|
Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget,
|
||||||
overlay::menu::{self, Menu},
|
|
||||||
scrollable, text, Clipboard, Element, Event, Hasher, Layout, Length, Point,
|
|
||||||
Rectangle, Size, Widget,
|
|
||||||
};
|
};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
@ -223,13 +227,15 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
_clipboard: Option<&dyn Clipboard>,
|
_clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
||||||
if *self.is_open {
|
let event_status = if *self.is_open {
|
||||||
// TODO: Encode cursor availability in the type system
|
// TODO: Encode cursor availability in the type system
|
||||||
*self.is_open =
|
*self.is_open =
|
||||||
cursor_position.x < 0.0 || cursor_position.y < 0.0;
|
cursor_position.x < 0.0 || cursor_position.y < 0.0;
|
||||||
|
|
||||||
|
event::Status::Captured
|
||||||
} else if layout.bounds().contains(cursor_position) {
|
} else if layout.bounds().contains(cursor_position) {
|
||||||
let selected = self.selected.as_ref();
|
let selected = self.selected.as_ref();
|
||||||
|
|
||||||
|
@ -238,15 +244,23 @@ where
|
||||||
.options
|
.options
|
||||||
.iter()
|
.iter()
|
||||||
.position(|option| Some(option) == selected);
|
.position(|option| Some(option) == selected);
|
||||||
}
|
|
||||||
|
event::Status::Captured
|
||||||
|
} else {
|
||||||
|
event::Status::Ignored
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(last_selection) = self.last_selection.take() {
|
if let Some(last_selection) = self.last_selection.take() {
|
||||||
messages.push((self.on_selected)(last_selection));
|
messages.push((self.on_selected)(last_selection));
|
||||||
|
|
||||||
*self.is_open = false;
|
*self.is_open = false;
|
||||||
|
|
||||||
|
event::Status::Captured
|
||||||
|
} else {
|
||||||
|
event_status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => event::Status::Ignored,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
//! Create choices using radio buttons.
|
//! Create choices using radio buttons.
|
||||||
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::mouse;
|
||||||
|
use crate::row;
|
||||||
|
use crate::text;
|
||||||
use crate::{
|
use crate::{
|
||||||
layout, mouse, row, text, Align, Clipboard, Element, Event, Hasher,
|
Align, Clipboard, Element, Hasher, HorizontalAlignment, Layout, Length,
|
||||||
HorizontalAlignment, Layout, Length, Point, Rectangle, Row, Text,
|
Point, Rectangle, Row, Text, VerticalAlignment, Widget,
|
||||||
VerticalAlignment, Widget,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
@ -166,15 +170,19 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
_clipboard: Option<&dyn Clipboard>,
|
_clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
||||||
if layout.bounds().contains(cursor_position) {
|
if layout.bounds().contains(cursor_position) {
|
||||||
messages.push(self.on_click.clone());
|
messages.push(self.on_click.clone());
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! Distribute content horizontally.
|
//! Distribute content horizontally.
|
||||||
|
use crate::event::{self, Event};
|
||||||
use crate::layout;
|
use crate::layout;
|
||||||
use crate::overlay;
|
use crate::overlay;
|
||||||
use crate::{
|
use crate::{
|
||||||
Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, Rectangle,
|
Align, Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Widget,
|
||||||
Widget,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
@ -162,9 +162,11 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
self.children.iter_mut().zip(layout.children()).for_each(
|
self.children
|
||||||
|(child, layout)| {
|
.iter_mut()
|
||||||
|
.zip(layout.children())
|
||||||
|
.map(|(child, layout)| {
|
||||||
child.widget.on_event(
|
child.widget.on_event(
|
||||||
event.clone(),
|
event.clone(),
|
||||||
layout,
|
layout,
|
||||||
|
@ -173,8 +175,8 @@ where
|
||||||
renderer,
|
renderer,
|
||||||
clipboard,
|
clipboard,
|
||||||
)
|
)
|
||||||
},
|
})
|
||||||
);
|
.fold(event::Status::Ignored, event::Status::merge)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
//! Navigate an endless amount of content with a scrollbar.
|
//! Navigate an endless amount of content with a scrollbar.
|
||||||
|
use crate::column;
|
||||||
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::mouse;
|
||||||
|
use crate::overlay;
|
||||||
use crate::{
|
use crate::{
|
||||||
column, layout, mouse, overlay, Align, Clipboard, Column, Element, Event,
|
Align, Clipboard, Column, Element, Hasher, Layout, Length, Point,
|
||||||
Hasher, Layout, Length, Point, Rectangle, Size, Vector, Widget,
|
Rectangle, Size, Vector, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{f32, hash::Hash, u32};
|
use std::{f32, hash::Hash, u32};
|
||||||
|
@ -184,31 +189,13 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
let is_mouse_over = bounds.contains(cursor_position);
|
let is_mouse_over = bounds.contains(cursor_position);
|
||||||
|
|
||||||
let content = layout.children().next().unwrap();
|
let content = layout.children().next().unwrap();
|
||||||
let content_bounds = content.bounds();
|
let content_bounds = content.bounds();
|
||||||
|
|
||||||
// TODO: Event capture. Nested scrollables should capture scroll events.
|
|
||||||
if is_mouse_over {
|
|
||||||
match event {
|
|
||||||
Event::Mouse(mouse::Event::WheelScrolled { delta }) => {
|
|
||||||
match delta {
|
|
||||||
mouse::ScrollDelta::Lines { y, .. } => {
|
|
||||||
// TODO: Configurable speed (?)
|
|
||||||
self.state.scroll(y * 60.0, bounds, content_bounds);
|
|
||||||
}
|
|
||||||
mouse::ScrollDelta::Pixels { y, .. } => {
|
|
||||||
self.state.scroll(y, bounds, content_bounds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let offset = self.state.offset(bounds, content_bounds);
|
let offset = self.state.offset(bounds, content_bounds);
|
||||||
let scrollbar = renderer.scrollbar(
|
let scrollbar = renderer.scrollbar(
|
||||||
bounds,
|
bounds,
|
||||||
|
@ -223,12 +210,62 @@ where
|
||||||
.map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
|
.map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
let event_status = {
|
||||||
|
let cursor_position = if is_mouse_over && !is_mouse_over_scrollbar {
|
||||||
|
Point::new(
|
||||||
|
cursor_position.x,
|
||||||
|
cursor_position.y
|
||||||
|
+ self.state.offset(bounds, content_bounds) as f32,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// TODO: Make `cursor_position` an `Option<Point>` so we can encode
|
||||||
|
// cursor availability.
|
||||||
|
// This will probably happen naturally once we add multi-window
|
||||||
|
// support.
|
||||||
|
Point::new(cursor_position.x, -1.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.content.on_event(
|
||||||
|
event.clone(),
|
||||||
|
content,
|
||||||
|
cursor_position,
|
||||||
|
messages,
|
||||||
|
renderer,
|
||||||
|
clipboard,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let event::Status::Captured = event_status {
|
||||||
|
return event::Status::Captured;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_mouse_over {
|
||||||
|
match event {
|
||||||
|
Event::Mouse(mouse::Event::WheelScrolled { delta }) => {
|
||||||
|
match delta {
|
||||||
|
mouse::ScrollDelta::Lines { y, .. } => {
|
||||||
|
// TODO: Configurable speed (?)
|
||||||
|
self.state.scroll(y * 60.0, bounds, content_bounds);
|
||||||
|
}
|
||||||
|
mouse::ScrollDelta::Pixels { y, .. } => {
|
||||||
|
self.state.scroll(y, bounds, content_bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if self.state.is_scroller_grabbed() {
|
if self.state.is_scroller_grabbed() {
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse::Event::ButtonReleased(
|
Event::Mouse(mouse::Event::ButtonReleased(
|
||||||
mouse::Button::Left,
|
mouse::Button::Left,
|
||||||
)) => {
|
)) => {
|
||||||
self.state.scroller_grabbed_at = None;
|
self.state.scroller_grabbed_at = None;
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
Event::Mouse(mouse::Event::CursorMoved { .. }) => {
|
Event::Mouse(mouse::Event::CursorMoved { .. }) => {
|
||||||
if let (Some(scrollbar), Some(scroller_grabbed_at)) =
|
if let (Some(scrollbar), Some(scroller_grabbed_at)) =
|
||||||
|
@ -242,6 +279,8 @@ where
|
||||||
bounds,
|
bounds,
|
||||||
content_bounds,
|
content_bounds,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -266,6 +305,8 @@ where
|
||||||
|
|
||||||
self.state.scroller_grabbed_at =
|
self.state.scroller_grabbed_at =
|
||||||
Some(scroller_grabbed_at);
|
Some(scroller_grabbed_at);
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,28 +314,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let cursor_position = if is_mouse_over && !is_mouse_over_scrollbar {
|
event::Status::Ignored
|
||||||
Point::new(
|
|
||||||
cursor_position.x,
|
|
||||||
cursor_position.y
|
|
||||||
+ self.state.offset(bounds, content_bounds) as f32,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// TODO: Make `cursor_position` an `Option<Point>` so we can encode
|
|
||||||
// cursor availability.
|
|
||||||
// This will probably happen naturally once we add multi-window
|
|
||||||
// support.
|
|
||||||
Point::new(cursor_position.x, -1.0)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.content.on_event(
|
|
||||||
event,
|
|
||||||
content,
|
|
||||||
cursor_position,
|
|
||||||
messages,
|
|
||||||
renderer,
|
|
||||||
clipboard,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
//!
|
//!
|
||||||
//! [`Slider`]: struct.Slider.html
|
//! [`Slider`]: struct.Slider.html
|
||||||
//! [`State`]: struct.State.html
|
//! [`State`]: struct.State.html
|
||||||
|
use crate::event::{self, Event};
|
||||||
|
use crate::layout;
|
||||||
|
use crate::mouse;
|
||||||
use crate::{
|
use crate::{
|
||||||
layout, mouse, Clipboard, Element, Event, Hasher, Layout, Length, Point,
|
Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget,
|
||||||
Rectangle, Size, Widget,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{hash::Hash, ops::RangeInclusive};
|
use std::{hash::Hash, ops::RangeInclusive};
|
||||||
|
@ -202,7 +204,7 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
_clipboard: Option<&dyn Clipboard>,
|
_clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
let mut change = || {
|
let mut change = || {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
if cursor_position.x <= bounds.x {
|
if cursor_position.x <= bounds.x {
|
||||||
|
@ -232,6 +234,8 @@ where
|
||||||
if layout.bounds().contains(cursor_position) {
|
if layout.bounds().contains(cursor_position) {
|
||||||
change();
|
change();
|
||||||
self.state.is_dragging = true;
|
self.state.is_dragging = true;
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mouse::Event::ButtonReleased(mouse::Button::Left) => {
|
mouse::Event::ButtonReleased(mouse::Button::Left) => {
|
||||||
|
@ -240,17 +244,23 @@ where
|
||||||
messages.push(on_release);
|
messages.push(on_release);
|
||||||
}
|
}
|
||||||
self.state.is_dragging = false;
|
self.state.is_dragging = false;
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mouse::Event::CursorMoved { .. } => {
|
mouse::Event::CursorMoved { .. } => {
|
||||||
if self.state.is_dragging {
|
if self.state.is_dragging {
|
||||||
change();
|
change();
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -14,11 +14,13 @@ pub use value::Value;
|
||||||
|
|
||||||
use editor::Editor;
|
use editor::Editor;
|
||||||
|
|
||||||
|
use crate::event::{self, Event};
|
||||||
|
use crate::keyboard;
|
||||||
|
use crate::layout;
|
||||||
|
use crate::mouse::{self, click};
|
||||||
|
use crate::text;
|
||||||
use crate::{
|
use crate::{
|
||||||
keyboard, layout,
|
Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget,
|
||||||
mouse::{self, click},
|
|
||||||
text, Clipboard, Element, Event, Hasher, Layout, Length, Point, Rectangle,
|
|
||||||
Size, Widget,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::u32;
|
use std::u32;
|
||||||
|
@ -218,11 +220,14 @@ where
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
clipboard: Option<&dyn Clipboard>,
|
clipboard: Option<&dyn Clipboard>,
|
||||||
) {
|
) -> event::Status {
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
|
||||||
let is_clicked = layout.bounds().contains(cursor_position);
|
let is_clicked = layout.bounds().contains(cursor_position);
|
||||||
|
|
||||||
|
self.state.is_dragging = is_clicked;
|
||||||
|
self.state.is_focused = is_clicked;
|
||||||
|
|
||||||
if is_clicked {
|
if is_clicked {
|
||||||
let text_layout = layout.children().next().unwrap();
|
let text_layout = layout.children().next().unwrap();
|
||||||
let target = cursor_position.x - text_layout.bounds().x;
|
let target = cursor_position.x - text_layout.bounds().x;
|
||||||
|
@ -280,10 +285,9 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state.last_click = Some(click);
|
self.state.last_click = Some(click);
|
||||||
}
|
|
||||||
|
|
||||||
self.state.is_dragging = is_clicked;
|
return event::Status::Captured;
|
||||||
self.state.is_focused = is_clicked;
|
}
|
||||||
}
|
}
|
||||||
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => {
|
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => {
|
||||||
self.state.is_dragging = false;
|
self.state.is_dragging = false;
|
||||||
|
@ -314,6 +318,8 @@ where
|
||||||
position,
|
position,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Keyboard(keyboard::Event::CharacterReceived(c))
|
Event::Keyboard(keyboard::Event::CharacterReceived(c))
|
||||||
|
@ -328,167 +334,203 @@ where
|
||||||
|
|
||||||
let message = (self.on_change)(editor.contents());
|
let message = (self.on_change)(editor.contents());
|
||||||
messages.push(message);
|
messages.push(message);
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
Event::Keyboard(keyboard::Event::KeyPressed {
|
Event::Keyboard(keyboard::Event::KeyPressed {
|
||||||
key_code,
|
key_code,
|
||||||
modifiers,
|
modifiers,
|
||||||
}) if self.state.is_focused => match key_code {
|
}) if self.state.is_focused => {
|
||||||
keyboard::KeyCode::Enter => {
|
match key_code {
|
||||||
if let Some(on_submit) = self.on_submit.clone() {
|
keyboard::KeyCode::Enter => {
|
||||||
messages.push(on_submit);
|
if let Some(on_submit) = self.on_submit.clone() {
|
||||||
}
|
messages.push(on_submit);
|
||||||
}
|
|
||||||
keyboard::KeyCode::Backspace => {
|
|
||||||
if platform::is_jump_modifier_pressed(modifiers)
|
|
||||||
&& self.state.cursor.selection(&self.value).is_none()
|
|
||||||
{
|
|
||||||
if self.is_secure {
|
|
||||||
let cursor_pos = self.state.cursor.end(&self.value);
|
|
||||||
self.state.cursor.select_range(0, cursor_pos);
|
|
||||||
} else {
|
|
||||||
self.state.cursor.select_left_by_words(&self.value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
keyboard::KeyCode::Backspace => {
|
||||||
let mut editor =
|
if platform::is_jump_modifier_pressed(modifiers)
|
||||||
Editor::new(&mut self.value, &mut self.state.cursor);
|
&& self
|
||||||
|
.state
|
||||||
editor.backspace();
|
|
||||||
|
|
||||||
let message = (self.on_change)(editor.contents());
|
|
||||||
messages.push(message);
|
|
||||||
}
|
|
||||||
keyboard::KeyCode::Delete => {
|
|
||||||
if platform::is_jump_modifier_pressed(modifiers)
|
|
||||||
&& self.state.cursor.selection(&self.value).is_none()
|
|
||||||
{
|
|
||||||
if self.is_secure {
|
|
||||||
let cursor_pos = self.state.cursor.end(&self.value);
|
|
||||||
self.state
|
|
||||||
.cursor
|
.cursor
|
||||||
.select_range(cursor_pos, self.value.len());
|
.selection(&self.value)
|
||||||
} else {
|
.is_none()
|
||||||
self.state
|
{
|
||||||
.cursor
|
if self.is_secure {
|
||||||
.select_right_by_words(&self.value);
|
let cursor_pos =
|
||||||
|
self.state.cursor.end(&self.value);
|
||||||
|
self.state.cursor.select_range(0, cursor_pos);
|
||||||
|
} else {
|
||||||
|
self.state
|
||||||
|
.cursor
|
||||||
|
.select_left_by_words(&self.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mut editor =
|
let mut editor = Editor::new(
|
||||||
Editor::new(&mut self.value, &mut self.state.cursor);
|
&mut self.value,
|
||||||
|
&mut self.state.cursor,
|
||||||
editor.delete();
|
|
||||||
|
|
||||||
let message = (self.on_change)(editor.contents());
|
|
||||||
messages.push(message);
|
|
||||||
}
|
|
||||||
keyboard::KeyCode::Left => {
|
|
||||||
if platform::is_jump_modifier_pressed(modifiers)
|
|
||||||
&& !self.is_secure
|
|
||||||
{
|
|
||||||
if modifiers.shift {
|
|
||||||
self.state.cursor.select_left_by_words(&self.value);
|
|
||||||
} else {
|
|
||||||
self.state.cursor.move_left_by_words(&self.value);
|
|
||||||
}
|
|
||||||
} else if modifiers.shift {
|
|
||||||
self.state.cursor.select_left(&self.value)
|
|
||||||
} else {
|
|
||||||
self.state.cursor.move_left(&self.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
keyboard::KeyCode::Right => {
|
|
||||||
if platform::is_jump_modifier_pressed(modifiers)
|
|
||||||
&& !self.is_secure
|
|
||||||
{
|
|
||||||
if modifiers.shift {
|
|
||||||
self.state
|
|
||||||
.cursor
|
|
||||||
.select_right_by_words(&self.value);
|
|
||||||
} else {
|
|
||||||
self.state.cursor.move_right_by_words(&self.value);
|
|
||||||
}
|
|
||||||
} else if modifiers.shift {
|
|
||||||
self.state.cursor.select_right(&self.value)
|
|
||||||
} else {
|
|
||||||
self.state.cursor.move_right(&self.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
keyboard::KeyCode::Home => {
|
|
||||||
if modifiers.shift {
|
|
||||||
self.state.cursor.select_range(
|
|
||||||
self.state.cursor.start(&self.value),
|
|
||||||
0,
|
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
self.state.cursor.move_to(0);
|
editor.backspace();
|
||||||
|
|
||||||
|
let message = (self.on_change)(editor.contents());
|
||||||
|
messages.push(message);
|
||||||
}
|
}
|
||||||
}
|
keyboard::KeyCode::Delete => {
|
||||||
keyboard::KeyCode::End => {
|
if platform::is_jump_modifier_pressed(modifiers)
|
||||||
if modifiers.shift {
|
&& self
|
||||||
self.state.cursor.select_range(
|
.state
|
||||||
self.state.cursor.start(&self.value),
|
.cursor
|
||||||
self.value.len(),
|
.selection(&self.value)
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
if self.is_secure {
|
||||||
|
let cursor_pos =
|
||||||
|
self.state.cursor.end(&self.value);
|
||||||
|
self.state
|
||||||
|
.cursor
|
||||||
|
.select_range(cursor_pos, self.value.len());
|
||||||
|
} else {
|
||||||
|
self.state
|
||||||
|
.cursor
|
||||||
|
.select_right_by_words(&self.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut editor = Editor::new(
|
||||||
|
&mut self.value,
|
||||||
|
&mut self.state.cursor,
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
self.state.cursor.move_to(self.value.len());
|
editor.delete();
|
||||||
|
|
||||||
|
let message = (self.on_change)(editor.contents());
|
||||||
|
messages.push(message);
|
||||||
}
|
}
|
||||||
}
|
keyboard::KeyCode::Left => {
|
||||||
keyboard::KeyCode::V => {
|
if platform::is_jump_modifier_pressed(modifiers)
|
||||||
if platform::is_copy_paste_modifier_pressed(modifiers) {
|
&& !self.is_secure
|
||||||
if let Some(clipboard) = clipboard {
|
{
|
||||||
let content = match self.state.is_pasting.take() {
|
if modifiers.shift {
|
||||||
Some(content) => content,
|
self.state
|
||||||
None => {
|
.cursor
|
||||||
let content: String = clipboard
|
.select_left_by_words(&self.value);
|
||||||
.content()
|
} else {
|
||||||
.unwrap_or(String::new())
|
self.state
|
||||||
.chars()
|
.cursor
|
||||||
.filter(|c| !c.is_control())
|
.move_left_by_words(&self.value);
|
||||||
.collect();
|
}
|
||||||
|
} else if modifiers.shift {
|
||||||
Value::new(&content)
|
self.state.cursor.select_left(&self.value)
|
||||||
}
|
} else {
|
||||||
};
|
self.state.cursor.move_left(&self.value);
|
||||||
|
}
|
||||||
let mut editor = Editor::new(
|
}
|
||||||
&mut self.value,
|
keyboard::KeyCode::Right => {
|
||||||
&mut self.state.cursor,
|
if platform::is_jump_modifier_pressed(modifiers)
|
||||||
|
&& !self.is_secure
|
||||||
|
{
|
||||||
|
if modifiers.shift {
|
||||||
|
self.state
|
||||||
|
.cursor
|
||||||
|
.select_right_by_words(&self.value);
|
||||||
|
} else {
|
||||||
|
self.state
|
||||||
|
.cursor
|
||||||
|
.move_right_by_words(&self.value);
|
||||||
|
}
|
||||||
|
} else if modifiers.shift {
|
||||||
|
self.state.cursor.select_right(&self.value)
|
||||||
|
} else {
|
||||||
|
self.state.cursor.move_right(&self.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyboard::KeyCode::Home => {
|
||||||
|
if modifiers.shift {
|
||||||
|
self.state.cursor.select_range(
|
||||||
|
self.state.cursor.start(&self.value),
|
||||||
|
0,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
editor.paste(content.clone());
|
self.state.cursor.move_to(0);
|
||||||
|
|
||||||
let message = (self.on_change)(editor.contents());
|
|
||||||
messages.push(message);
|
|
||||||
|
|
||||||
self.state.is_pasting = Some(content);
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
keyboard::KeyCode::End => {
|
||||||
|
if modifiers.shift {
|
||||||
|
self.state.cursor.select_range(
|
||||||
|
self.state.cursor.start(&self.value),
|
||||||
|
self.value.len(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.state.cursor.move_to(self.value.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyboard::KeyCode::V => {
|
||||||
|
if platform::is_copy_paste_modifier_pressed(modifiers) {
|
||||||
|
if let Some(clipboard) = clipboard {
|
||||||
|
let content = match self.state.is_pasting.take()
|
||||||
|
{
|
||||||
|
Some(content) => content,
|
||||||
|
None => {
|
||||||
|
let content: String = clipboard
|
||||||
|
.content()
|
||||||
|
.unwrap_or(String::new())
|
||||||
|
.chars()
|
||||||
|
.filter(|c| !c.is_control())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Value::new(&content)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut editor = Editor::new(
|
||||||
|
&mut self.value,
|
||||||
|
&mut self.state.cursor,
|
||||||
|
);
|
||||||
|
|
||||||
|
editor.paste(content.clone());
|
||||||
|
|
||||||
|
let message =
|
||||||
|
(self.on_change)(editor.contents());
|
||||||
|
messages.push(message);
|
||||||
|
|
||||||
|
self.state.is_pasting = Some(content);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.state.is_pasting = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyboard::KeyCode::A => {
|
||||||
|
if platform::is_copy_paste_modifier_pressed(modifiers) {
|
||||||
|
self.state.cursor.select_all(&self.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyboard::KeyCode::Escape => {
|
||||||
|
self.state.is_focused = false;
|
||||||
|
self.state.is_dragging = false;
|
||||||
self.state.is_pasting = None;
|
self.state.is_pasting = None;
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
keyboard::KeyCode::A => {
|
|
||||||
if platform::is_copy_paste_modifier_pressed(modifiers) {
|
return event::Status::Captured;
|
||||||
self.state.cursor.select_all(&self.value);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
keyboard::KeyCode::Escape => {
|
|
||||||
self.state.is_focused = false;
|
|
||||||
self.state.is_dragging = false;
|
|
||||||
self.state.is_pasting = None;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
Event::Keyboard(keyboard::Event::KeyReleased {
|
Event::Keyboard(keyboard::Event::KeyReleased {
|
||||||
key_code, ..
|
key_code, ..
|
||||||
}) => match key_code {
|
}) if self.state.is_focused => {
|
||||||
keyboard::KeyCode::V => {
|
match key_code {
|
||||||
self.state.is_pasting = None;
|
keyboard::KeyCode::V => {
|
||||||
|
self.state.is_pasting = None;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
},
|
return event::Status::Captured;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
|
@ -242,29 +242,33 @@ async fn run_instance<A, E, C>(
|
||||||
let mut mouse_interaction = mouse::Interaction::default();
|
let mut mouse_interaction = mouse::Interaction::default();
|
||||||
|
|
||||||
let mut events = Vec::new();
|
let mut events = Vec::new();
|
||||||
let mut external_messages = Vec::new();
|
let mut messages = Vec::new();
|
||||||
|
|
||||||
debug.startup_finished();
|
debug.startup_finished();
|
||||||
|
|
||||||
while let Some(event) = receiver.next().await {
|
while let Some(event) = receiver.next().await {
|
||||||
match event {
|
match event {
|
||||||
event::Event::MainEventsCleared => {
|
event::Event::MainEventsCleared => {
|
||||||
if events.is_empty() && external_messages.is_empty() {
|
if events.is_empty() && messages.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.event_processing_started();
|
debug.event_processing_started();
|
||||||
let mut messages = user_interface.update(
|
|
||||||
|
let statuses = user_interface.update(
|
||||||
&events,
|
&events,
|
||||||
state.cursor_position(),
|
state.cursor_position(),
|
||||||
clipboard.as_ref().map(|c| c as _),
|
clipboard.as_ref().map(|c| c as _),
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
|
&mut messages,
|
||||||
);
|
);
|
||||||
|
|
||||||
messages.extend(external_messages.drain(..));
|
|
||||||
events.clear();
|
|
||||||
debug.event_processing_finished();
|
debug.event_processing_finished();
|
||||||
|
|
||||||
|
for event in events.drain(..).zip(statuses.into_iter()) {
|
||||||
|
runtime.broadcast(event);
|
||||||
|
}
|
||||||
|
|
||||||
if !messages.is_empty() {
|
if !messages.is_empty() {
|
||||||
let cache =
|
let cache =
|
||||||
ManuallyDrop::into_inner(user_interface).into_cache();
|
ManuallyDrop::into_inner(user_interface).into_cache();
|
||||||
|
@ -274,7 +278,7 @@ async fn run_instance<A, E, C>(
|
||||||
&mut application,
|
&mut application,
|
||||||
&mut runtime,
|
&mut runtime,
|
||||||
&mut debug,
|
&mut debug,
|
||||||
messages,
|
&mut messages,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update window
|
// Update window
|
||||||
|
@ -297,7 +301,7 @@ async fn run_instance<A, E, C>(
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
}
|
}
|
||||||
event::Event::UserEvent(message) => {
|
event::Event::UserEvent(message) => {
|
||||||
external_messages.push(message);
|
messages.push(message);
|
||||||
}
|
}
|
||||||
event::Event::RedrawRequested(_) => {
|
event::Event::RedrawRequested(_) => {
|
||||||
debug.render_started();
|
debug.render_started();
|
||||||
|
@ -365,8 +369,7 @@ async fn run_instance<A, E, C>(
|
||||||
state.scale_factor(),
|
state.scale_factor(),
|
||||||
state.modifiers(),
|
state.modifiers(),
|
||||||
) {
|
) {
|
||||||
events.push(event.clone());
|
events.push(event);
|
||||||
runtime.broadcast(event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -437,9 +440,9 @@ pub fn update<A: Application, E: Executor>(
|
||||||
application: &mut A,
|
application: &mut A,
|
||||||
runtime: &mut Runtime<E, Proxy<A::Message>, A::Message>,
|
runtime: &mut Runtime<E, Proxy<A::Message>, A::Message>,
|
||||||
debug: &mut Debug,
|
debug: &mut Debug,
|
||||||
messages: Vec<A::Message>,
|
messages: &mut Vec<A::Message>,
|
||||||
) {
|
) {
|
||||||
for message in messages {
|
for message in messages.drain(..) {
|
||||||
debug.log_message(&message);
|
debug.log_message(&message);
|
||||||
|
|
||||||
debug.update_started();
|
debug.update_started();
|
||||||
|
|
Loading…
Reference in New Issue