Skip to content

Commit 62295f5

Browse files
authored
Merge pull request #614 from hecrj/feature/event-capturing
Event capturing
2 parents 73811c3 + bf2d256 commit 62295f5

33 files changed

Lines changed: 711 additions & 425 deletions

File tree

examples/bezier_tool/src/main.rs

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ impl Sandbox for Example {
6969

7070
mod bezier {
7171
use iced::{
72-
canvas::{self, Canvas, Cursor, Event, Frame, Geometry, Path, Stroke},
72+
canvas::event::{self, Event},
73+
canvas::{self, Canvas, Cursor, Frame, Geometry, Path, Stroke},
7374
mouse, Element, Length, Point, Rectangle,
7475
};
7576

@@ -109,41 +110,51 @@ mod bezier {
109110
event: Event,
110111
bounds: Rectangle,
111112
cursor: Cursor,
112-
) -> Option<Curve> {
113-
let cursor_position = cursor.position_in(&bounds)?;
113+
) -> (event::Status, Option<Curve>) {
114+
let cursor_position =
115+
if let Some(position) = cursor.position_in(&bounds) {
116+
position
117+
} else {
118+
return (event::Status::Ignored, None);
119+
};
114120

115121
match event {
116-
Event::Mouse(mouse_event) => match mouse_event {
117-
mouse::Event::ButtonPressed(mouse::Button::Left) => {
118-
match self.state.pending {
119-
None => {
120-
self.state.pending = Some(Pending::One {
121-
from: cursor_position,
122-
});
123-
None
124-
}
125-
Some(Pending::One { from }) => {
126-
self.state.pending = Some(Pending::Two {
127-
from,
128-
to: cursor_position,
129-
});
130-
131-
None
132-
}
133-
Some(Pending::Two { from, to }) => {
134-
self.state.pending = None;
135-
136-
Some(Curve {
137-
from,
138-
to,
139-
control: cursor_position,
140-
})
122+
Event::Mouse(mouse_event) => {
123+
let message = match mouse_event {
124+
mouse::Event::ButtonPressed(mouse::Button::Left) => {
125+
match self.state.pending {
126+
None => {
127+
self.state.pending = Some(Pending::One {
128+
from: cursor_position,
129+
});
130+
131+
None
132+
}
133+
Some(Pending::One { from }) => {
134+
self.state.pending = Some(Pending::Two {
135+
from,
136+
to: cursor_position,
137+
});
138+
139+
None
140+
}
141+
Some(Pending::Two { from, to }) => {
142+
self.state.pending = None;
143+
144+
Some(Curve {
145+
from,
146+
to,
147+
control: cursor_position,
148+
})
149+
}
141150
}
142151
}
143-
}
144-
_ => None,
145-
},
146-
_ => None,
152+
_ => None,
153+
};
154+
155+
(event::Status::Captured, message)
156+
}
157+
_ => (event::Status::Ignored, None),
147158
}
148159
}
149160

examples/game_of_life/src/main.rs

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,8 @@ impl Application for GameOfLife {
153153
mod grid {
154154
use crate::Preset;
155155
use iced::{
156-
canvas::{
157-
self, Cache, Canvas, Cursor, Event, Frame, Geometry, Path, Text,
158-
},
156+
canvas::event::{self, Event},
157+
canvas::{self, Cache, Canvas, Cursor, Frame, Geometry, Path, Text},
159158
mouse, Color, Element, HorizontalAlignment, Length, Point, Rectangle,
160159
Size, Vector, VerticalAlignment,
161160
};
@@ -328,12 +327,18 @@ mod grid {
328327
event: Event,
329328
bounds: Rectangle,
330329
cursor: Cursor,
331-
) -> Option<Message> {
330+
) -> (event::Status, Option<Message>) {
332331
if let Event::Mouse(mouse::Event::ButtonReleased(_)) = event {
333332
self.interaction = Interaction::None;
334333
}
335334

336-
let cursor_position = cursor.position_in(&bounds)?;
335+
let cursor_position =
336+
if let Some(position) = cursor.position_in(&bounds) {
337+
position
338+
} else {
339+
return (event::Status::Ignored, None);
340+
};
341+
337342
let cell = Cell::at(self.project(cursor_position, bounds.size()));
338343
let is_populated = self.state.contains(&cell);
339344

@@ -345,28 +350,32 @@ mod grid {
345350

346351
match event {
347352
Event::Mouse(mouse_event) => match mouse_event {
348-
mouse::Event::ButtonPressed(button) => match button {
349-
mouse::Button::Left => {
350-
self.interaction = if is_populated {
351-
Interaction::Erasing
352-
} else {
353-
Interaction::Drawing
354-
};
355-
356-
populate.or(unpopulate)
357-
}
358-
mouse::Button::Right => {
359-
self.interaction = Interaction::Panning {
360-
translation: self.translation,
361-
start: cursor_position,
362-
};
353+
mouse::Event::ButtonPressed(button) => {
354+
let message = match button {
355+
mouse::Button::Left => {
356+
self.interaction = if is_populated {
357+
Interaction::Erasing
358+
} else {
359+
Interaction::Drawing
360+
};
361+
362+
populate.or(unpopulate)
363+
}
364+
mouse::Button::Right => {
365+
self.interaction = Interaction::Panning {
366+
translation: self.translation,
367+
start: cursor_position,
368+
};
363369

364-
None
365-
}
366-
_ => None,
367-
},
370+
None
371+
}
372+
_ => None,
373+
};
374+
375+
(event::Status::Captured, message)
376+
}
368377
mouse::Event::CursorMoved { .. } => {
369-
match self.interaction {
378+
let message = match self.interaction {
370379
Interaction::Drawing => populate,
371380
Interaction::Erasing => unpopulate,
372381
Interaction::Panning { translation, start } => {
@@ -380,7 +389,14 @@ mod grid {
380389
None
381390
}
382391
_ => None,
383-
}
392+
};
393+
394+
let event_status = match self.interaction {
395+
Interaction::None => event::Status::Ignored,
396+
_ => event::Status::Captured,
397+
};
398+
399+
(event_status, message)
384400
}
385401
mouse::Event::WheelScrolled { delta } => match delta {
386402
mouse::ScrollDelta::Lines { y, .. }
@@ -413,12 +429,12 @@ mod grid {
413429
self.grid_cache.clear();
414430
}
415431

416-
None
432+
(event::Status::Captured, None)
417433
}
418434
},
419-
_ => None,
435+
_ => (event::Status::Ignored, None),
420436
},
421-
_ => None,
437+
_ => (event::Status::Ignored, None),
422438
}
423439
}
424440

examples/pane_grid/src/main.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use iced::{
33
Button, Column, Command, Container, Element, HorizontalAlignment, Length,
44
PaneGrid, Scrollable, Settings, Subscription, Text,
55
};
6-
use iced_native::{subscription, Event};
6+
use iced_native::{event, subscription, Event};
77

88
pub fn main() -> iced::Result {
99
Example::run(Settings::default())
@@ -119,12 +119,18 @@ impl Application for Example {
119119
}
120120

121121
fn subscription(&self) -> Subscription<Message> {
122-
subscription::events_with(|event| match event {
123-
Event::Keyboard(keyboard::Event::KeyPressed {
124-
modifiers,
125-
key_code,
126-
}) if modifiers.is_command_pressed() => handle_hotkey(key_code),
127-
_ => None,
122+
subscription::events_with(|event, status| {
123+
if let event::Status::Captured = status {
124+
return None;
125+
}
126+
127+
match event {
128+
Event::Keyboard(keyboard::Event::KeyPressed {
129+
modifiers,
130+
key_code,
131+
}) if modifiers.is_command_pressed() => handle_hotkey(key_code),
132+
_ => None,
133+
}
128134
})
129135
}
130136

glutin/src/application.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -156,29 +156,33 @@ async fn run_instance<A, E, C>(
156156
let mut mouse_interaction = mouse::Interaction::default();
157157

158158
let mut events = Vec::new();
159-
let mut external_messages = Vec::new();
159+
let mut messages = Vec::new();
160160

161161
debug.startup_finished();
162162

163163
while let Some(event) = receiver.next().await {
164164
match event {
165165
event::Event::MainEventsCleared => {
166-
if events.is_empty() && external_messages.is_empty() {
166+
if events.is_empty() && messages.is_empty() {
167167
continue;
168168
}
169169

170170
debug.event_processing_started();
171-
let mut messages = user_interface.update(
171+
172+
let statuses = user_interface.update(
172173
&events,
173174
state.cursor_position(),
174175
clipboard.as_ref().map(|c| c as _),
175176
&mut renderer,
177+
&mut messages,
176178
);
177179

178-
messages.extend(external_messages.drain(..));
179-
events.clear();
180180
debug.event_processing_finished();
181181

182+
for event in events.drain(..).zip(statuses.into_iter()) {
183+
runtime.broadcast(event);
184+
}
185+
182186
if !messages.is_empty() {
183187
let cache =
184188
ManuallyDrop::into_inner(user_interface).into_cache();
@@ -188,7 +192,7 @@ async fn run_instance<A, E, C>(
188192
&mut application,
189193
&mut runtime,
190194
&mut debug,
191-
messages,
195+
&mut messages,
192196
);
193197

194198
// Update window
@@ -212,7 +216,7 @@ async fn run_instance<A, E, C>(
212216
context.window().request_redraw();
213217
}
214218
event::Event::UserEvent(message) => {
215-
external_messages.push(message);
219+
messages.push(message);
216220
}
217221
event::Event::RedrawRequested(_) => {
218222
debug.render_started();
@@ -283,8 +287,7 @@ async fn run_instance<A, E, C>(
283287
state.scale_factor(),
284288
state.modifiers(),
285289
) {
286-
events.push(event.clone());
287-
runtime.broadcast(event);
290+
events.push(event);
288291
}
289292
}
290293
_ => {}

graphics/src/widget/canvas.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@
77
//! [`Canvas`]: struct.Canvas.html
88
//! [`Frame`]: struct.Frame.html
99
use crate::{Backend, Defaults, Primitive, Renderer};
10+
use iced_native::layout;
11+
use iced_native::mouse;
1012
use iced_native::{
11-
layout, mouse, Clipboard, Element, Hasher, Layout, Length, Point,
12-
Rectangle, Size, Vector, Widget,
13+
Clipboard, Element, Hasher, Layout, Length, Point, Rectangle, Size, Vector,
14+
Widget,
1315
};
1416
use std::hash::Hash;
1517
use std::marker::PhantomData;
1618

19+
pub mod event;
1720
pub mod path;
1821

1922
mod cache;
2023
mod cursor;
21-
mod event;
2224
mod fill;
2325
mod frame;
2426
mod geometry;
@@ -166,7 +168,7 @@ where
166168
messages: &mut Vec<Message>,
167169
_renderer: &Renderer<B>,
168170
_clipboard: Option<&dyn Clipboard>,
169-
) {
171+
) -> event::Status {
170172
let bounds = layout.bounds();
171173

172174
let canvas_event = match event {
@@ -182,12 +184,17 @@ where
182184
let cursor = Cursor::from_window_position(cursor_position);
183185

184186
if let Some(canvas_event) = canvas_event {
185-
if let Some(message) =
186-
self.program.update(canvas_event, bounds, cursor)
187-
{
187+
let (event_status, message) =
188+
self.program.update(canvas_event, bounds, cursor);
189+
190+
if let Some(message) = message {
188191
messages.push(message);
189192
}
193+
194+
return event_status;
190195
}
196+
197+
event::Status::Ignored
191198
}
192199

193200
fn draw(

graphics/src/widget/canvas/event.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
//! Handle events of a canvas.
12
use iced_native::keyboard;
23
use iced_native::mouse;
34

5+
pub use iced_native::event::Status;
6+
47
/// A [`Canvas`] event.
58
///
69
/// [`Canvas`]: struct.Event.html

0 commit comments

Comments
 (0)