Draft iced_test crate and test todos example
This commit is contained in:
parent
d6182299b9
commit
d09d5d45ae
18 changed files with 640 additions and 63 deletions
|
|
@ -72,6 +72,7 @@ unconditional-rendering = ["iced_winit/unconditional-rendering"]
|
||||||
iced_core.workspace = true
|
iced_core.workspace = true
|
||||||
iced_futures.workspace = true
|
iced_futures.workspace = true
|
||||||
iced_renderer.workspace = true
|
iced_renderer.workspace = true
|
||||||
|
iced_test.workspace = true
|
||||||
iced_widget.workspace = true
|
iced_widget.workspace = true
|
||||||
iced_winit.features = ["program"]
|
iced_winit.features = ["program"]
|
||||||
iced_winit.workspace = true
|
iced_winit.workspace = true
|
||||||
|
|
@ -111,6 +112,7 @@ members = [
|
||||||
"highlighter",
|
"highlighter",
|
||||||
"renderer",
|
"renderer",
|
||||||
"runtime",
|
"runtime",
|
||||||
|
"test",
|
||||||
"tiny_skia",
|
"tiny_skia",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"widget",
|
"widget",
|
||||||
|
|
@ -137,6 +139,7 @@ iced_graphics = { version = "0.14.0-dev", path = "graphics" }
|
||||||
iced_highlighter = { version = "0.14.0-dev", path = "highlighter" }
|
iced_highlighter = { version = "0.14.0-dev", path = "highlighter" }
|
||||||
iced_renderer = { version = "0.14.0-dev", path = "renderer" }
|
iced_renderer = { version = "0.14.0-dev", path = "renderer" }
|
||||||
iced_runtime = { version = "0.14.0-dev", path = "runtime" }
|
iced_runtime = { version = "0.14.0-dev", path = "runtime" }
|
||||||
|
iced_test = { version = "0.14.0-dev", path = "test" }
|
||||||
iced_tiny_skia = { version = "0.14.0-dev", path = "tiny_skia" }
|
iced_tiny_skia = { version = "0.14.0-dev", path = "tiny_skia" }
|
||||||
iced_wgpu = { version = "0.14.0-dev", path = "wgpu" }
|
iced_wgpu = { version = "0.14.0-dev", path = "wgpu" }
|
||||||
iced_widget = { version = "0.14.0-dev", path = "widget" }
|
iced_widget = { version = "0.14.0-dev", path = "widget" }
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,12 @@ impl Key {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Named> for Key {
|
||||||
|
fn from(named: Named) -> Self {
|
||||||
|
Self::Named(named)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A named key.
|
/// A named key.
|
||||||
///
|
///
|
||||||
/// This is mostly the `NamedKey` type found in [`winit`].
|
/// This is mostly the `NamedKey` type found in [`winit`].
|
||||||
|
|
|
||||||
|
|
@ -30,24 +30,45 @@ pub trait Operation<T = ()>: Send {
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Operates on a widget that can be focused.
|
/// Operates on a widget that can be focused.
|
||||||
fn focusable(&mut self, _state: &mut dyn Focusable, _id: Option<&Id>) {}
|
fn focusable(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
_state: &mut dyn Focusable,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/// Operates on a widget that can be scrolled.
|
/// Operates on a widget that can be scrolled.
|
||||||
fn scrollable(
|
fn scrollable(
|
||||||
&mut self,
|
&mut self,
|
||||||
_state: &mut dyn Scrollable,
|
|
||||||
_id: Option<&Id>,
|
_id: Option<&Id>,
|
||||||
_bounds: Rectangle,
|
_bounds: Rectangle,
|
||||||
_content_bounds: Rectangle,
|
_content_bounds: Rectangle,
|
||||||
_translation: Vector,
|
_translation: Vector,
|
||||||
|
_state: &mut dyn Scrollable,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Operates on a widget that has text input.
|
/// Operates on a widget that has text input.
|
||||||
fn text_input(&mut self, _state: &mut dyn TextInput, _id: Option<&Id>) {}
|
fn text_input(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
_state: &mut dyn TextInput,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Operates on a widget that contains some text.
|
||||||
|
fn text(&mut self, _id: Option<&Id>, _bounds: Rectangle, _text: &str) {}
|
||||||
|
|
||||||
/// Operates on a custom widget with some state.
|
/// Operates on a custom widget with some state.
|
||||||
fn custom(&mut self, _state: &mut dyn Any, _id: Option<&Id>) {}
|
fn custom(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
_state: &mut dyn Any,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/// Finishes the [`Operation`] and returns its [`Outcome`].
|
/// Finishes the [`Operation`] and returns its [`Outcome`].
|
||||||
fn finish(&self) -> Outcome<T> {
|
fn finish(&self) -> Outcome<T> {
|
||||||
|
|
@ -68,33 +89,52 @@ where
|
||||||
self.as_mut().container(id, bounds, operate_on_children);
|
self.as_mut().container(id, bounds, operate_on_children);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
|
fn focusable(
|
||||||
self.as_mut().focusable(state, id);
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn Focusable,
|
||||||
|
) {
|
||||||
|
self.as_mut().focusable(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scrollable(
|
fn scrollable(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut dyn Scrollable,
|
|
||||||
id: Option<&Id>,
|
id: Option<&Id>,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
content_bounds: Rectangle,
|
content_bounds: Rectangle,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
|
state: &mut dyn Scrollable,
|
||||||
) {
|
) {
|
||||||
self.as_mut().scrollable(
|
self.as_mut().scrollable(
|
||||||
state,
|
|
||||||
id,
|
id,
|
||||||
bounds,
|
bounds,
|
||||||
content_bounds,
|
content_bounds,
|
||||||
translation,
|
translation,
|
||||||
|
state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
|
fn text_input(
|
||||||
self.as_mut().text_input(state, id);
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn TextInput,
|
||||||
|
) {
|
||||||
|
self.as_mut().text_input(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
|
fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
|
||||||
self.as_mut().custom(state, id);
|
self.as_mut().text(id, bounds, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn Any,
|
||||||
|
) {
|
||||||
|
self.as_mut().custom(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&self) -> Outcome<O> {
|
fn finish(&self) -> Outcome<O> {
|
||||||
|
|
@ -150,33 +190,52 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
|
fn focusable(
|
||||||
self.operation.focusable(state, id);
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn Focusable,
|
||||||
|
) {
|
||||||
|
self.operation.focusable(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scrollable(
|
fn scrollable(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut dyn Scrollable,
|
|
||||||
id: Option<&Id>,
|
id: Option<&Id>,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
content_bounds: Rectangle,
|
content_bounds: Rectangle,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
|
state: &mut dyn Scrollable,
|
||||||
) {
|
) {
|
||||||
self.operation.scrollable(
|
self.operation.scrollable(
|
||||||
state,
|
|
||||||
id,
|
id,
|
||||||
bounds,
|
bounds,
|
||||||
content_bounds,
|
content_bounds,
|
||||||
translation,
|
translation,
|
||||||
|
state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
|
fn text_input(
|
||||||
self.operation.text_input(state, id);
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn TextInput,
|
||||||
|
) {
|
||||||
|
self.operation.text_input(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
|
fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
|
||||||
self.operation.custom(state, id);
|
self.operation.text(id, bounds, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn Any,
|
||||||
|
) {
|
||||||
|
self.operation.custom(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&self) -> Outcome<O> {
|
fn finish(&self) -> Outcome<O> {
|
||||||
|
|
@ -234,39 +293,55 @@ where
|
||||||
|
|
||||||
fn scrollable(
|
fn scrollable(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut dyn Scrollable,
|
|
||||||
id: Option<&Id>,
|
id: Option<&Id>,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
content_bounds: Rectangle,
|
content_bounds: Rectangle,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
|
state: &mut dyn Scrollable,
|
||||||
) {
|
) {
|
||||||
self.operation.scrollable(
|
self.operation.scrollable(
|
||||||
state,
|
|
||||||
id,
|
id,
|
||||||
bounds,
|
bounds,
|
||||||
content_bounds,
|
content_bounds,
|
||||||
translation,
|
translation,
|
||||||
|
state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focusable(
|
fn focusable(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut dyn Focusable,
|
|
||||||
id: Option<&Id>,
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn Focusable,
|
||||||
) {
|
) {
|
||||||
self.operation.focusable(state, id);
|
self.operation.focusable(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_input(
|
fn text_input(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut dyn TextInput,
|
|
||||||
id: Option<&Id>,
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn TextInput,
|
||||||
) {
|
) {
|
||||||
self.operation.text_input(state, id);
|
self.operation.text_input(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
|
fn text(
|
||||||
self.operation.custom(state, id);
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
text: &str,
|
||||||
|
) {
|
||||||
|
self.operation.text(id, bounds, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn Any,
|
||||||
|
) {
|
||||||
|
self.operation.custom(id, bounds, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,33 +350,52 @@ where
|
||||||
MapRef { operation }.container(id, bounds, operate_on_children);
|
MapRef { operation }.container(id, bounds, operate_on_children);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
|
fn focusable(
|
||||||
self.operation.focusable(state, id);
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn Focusable,
|
||||||
|
) {
|
||||||
|
self.operation.focusable(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scrollable(
|
fn scrollable(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut dyn Scrollable,
|
|
||||||
id: Option<&Id>,
|
id: Option<&Id>,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
content_bounds: Rectangle,
|
content_bounds: Rectangle,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
|
state: &mut dyn Scrollable,
|
||||||
) {
|
) {
|
||||||
self.operation.scrollable(
|
self.operation.scrollable(
|
||||||
state,
|
|
||||||
id,
|
id,
|
||||||
bounds,
|
bounds,
|
||||||
content_bounds,
|
content_bounds,
|
||||||
translation,
|
translation,
|
||||||
|
state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
|
fn text_input(
|
||||||
self.operation.text_input(state, id);
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn TextInput,
|
||||||
|
) {
|
||||||
|
self.operation.text_input(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
|
fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
|
||||||
self.operation.custom(state, id);
|
self.operation.text(id, bounds, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn Any,
|
||||||
|
) {
|
||||||
|
self.operation.custom(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&self) -> Outcome<B> {
|
fn finish(&self) -> Outcome<B> {
|
||||||
|
|
@ -361,33 +455,52 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
|
fn focusable(
|
||||||
self.operation.focusable(state, id);
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn Focusable,
|
||||||
|
) {
|
||||||
|
self.operation.focusable(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scrollable(
|
fn scrollable(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut dyn Scrollable,
|
|
||||||
id: Option<&Id>,
|
id: Option<&Id>,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
content_bounds: Rectangle,
|
content_bounds: Rectangle,
|
||||||
translation: crate::Vector,
|
translation: crate::Vector,
|
||||||
|
state: &mut dyn Scrollable,
|
||||||
) {
|
) {
|
||||||
self.operation.scrollable(
|
self.operation.scrollable(
|
||||||
state,
|
|
||||||
id,
|
id,
|
||||||
bounds,
|
bounds,
|
||||||
content_bounds,
|
content_bounds,
|
||||||
translation,
|
translation,
|
||||||
|
state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
|
fn text_input(
|
||||||
self.operation.text_input(state, id);
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn TextInput,
|
||||||
|
) {
|
||||||
|
self.operation.text_input(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn custom(&mut self, state: &mut dyn std::any::Any, id: Option<&Id>) {
|
fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
|
||||||
self.operation.custom(state, id);
|
self.operation.text(id, bounds, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
state: &mut dyn Any,
|
||||||
|
) {
|
||||||
|
self.operation.custom(id, bounds, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&self) -> Outcome<B> {
|
fn finish(&self) -> Outcome<B> {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,12 @@ pub fn focus<T>(target: Id) -> impl Operation<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Operation<T> for Focus {
|
impl<T> Operation<T> for Focus {
|
||||||
fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
|
fn focusable(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
state: &mut dyn Focusable,
|
||||||
|
) {
|
||||||
match id {
|
match id {
|
||||||
Some(id) if id == &self.target => {
|
Some(id) if id == &self.target => {
|
||||||
state.focus();
|
state.focus();
|
||||||
|
|
@ -64,7 +69,12 @@ pub fn count() -> impl Operation<Count> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operation<Count> for CountFocusable {
|
impl Operation<Count> for CountFocusable {
|
||||||
fn focusable(&mut self, state: &mut dyn Focusable, _id: Option<&Id>) {
|
fn focusable(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
state: &mut dyn Focusable,
|
||||||
|
) {
|
||||||
if state.is_focused() {
|
if state.is_focused() {
|
||||||
self.count.focused = Some(self.count.total);
|
self.count.focused = Some(self.count.total);
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +114,12 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Operation<T> for FocusPrevious {
|
impl<T> Operation<T> for FocusPrevious {
|
||||||
fn focusable(&mut self, state: &mut dyn Focusable, _id: Option<&Id>) {
|
fn focusable(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
state: &mut dyn Focusable,
|
||||||
|
) {
|
||||||
if self.count.total == 0 {
|
if self.count.total == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -147,7 +162,12 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Operation<T> for FocusNext {
|
impl<T> Operation<T> for FocusNext {
|
||||||
fn focusable(&mut self, state: &mut dyn Focusable, _id: Option<&Id>) {
|
fn focusable(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
state: &mut dyn Focusable,
|
||||||
|
) {
|
||||||
match self.count.focused {
|
match self.count.focused {
|
||||||
None if self.current == 0 => state.focus(),
|
None if self.current == 0 => state.focus(),
|
||||||
Some(focused) if focused == self.current => state.unfocus(),
|
Some(focused) if focused == self.current => state.unfocus(),
|
||||||
|
|
@ -179,7 +199,12 @@ pub fn find_focused() -> impl Operation<Id> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operation<Id> for FindFocused {
|
impl Operation<Id> for FindFocused {
|
||||||
fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
|
fn focusable(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
state: &mut dyn Focusable,
|
||||||
|
) {
|
||||||
if state.is_focused() && id.is_some() {
|
if state.is_focused() && id.is_some() {
|
||||||
self.focused = id.cloned();
|
self.focused = id.cloned();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,11 @@ pub fn snap_to<T>(target: Id, offset: RelativeOffset) -> impl Operation<T> {
|
||||||
|
|
||||||
fn scrollable(
|
fn scrollable(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut dyn Scrollable,
|
|
||||||
id: Option<&Id>,
|
id: Option<&Id>,
|
||||||
_bounds: Rectangle,
|
_bounds: Rectangle,
|
||||||
_content_bounds: Rectangle,
|
_content_bounds: Rectangle,
|
||||||
_translation: Vector,
|
_translation: Vector,
|
||||||
|
state: &mut dyn Scrollable,
|
||||||
) {
|
) {
|
||||||
if Some(&self.target) == id {
|
if Some(&self.target) == id {
|
||||||
state.snap_to(self.offset);
|
state.snap_to(self.offset);
|
||||||
|
|
@ -74,11 +74,11 @@ pub fn scroll_to<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
|
||||||
|
|
||||||
fn scrollable(
|
fn scrollable(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut dyn Scrollable,
|
|
||||||
id: Option<&Id>,
|
id: Option<&Id>,
|
||||||
_bounds: Rectangle,
|
_bounds: Rectangle,
|
||||||
_content_bounds: Rectangle,
|
_content_bounds: Rectangle,
|
||||||
_translation: Vector,
|
_translation: Vector,
|
||||||
|
state: &mut dyn Scrollable,
|
||||||
) {
|
) {
|
||||||
if Some(&self.target) == id {
|
if Some(&self.target) == id {
|
||||||
state.scroll_to(self.offset);
|
state.scroll_to(self.offset);
|
||||||
|
|
@ -109,11 +109,11 @@ pub fn scroll_by<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
|
||||||
|
|
||||||
fn scrollable(
|
fn scrollable(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut dyn Scrollable,
|
|
||||||
id: Option<&Id>,
|
id: Option<&Id>,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
content_bounds: Rectangle,
|
content_bounds: Rectangle,
|
||||||
_translation: Vector,
|
_translation: Vector,
|
||||||
|
state: &mut dyn Scrollable,
|
||||||
) {
|
) {
|
||||||
if Some(&self.target) == id {
|
if Some(&self.target) == id {
|
||||||
state.scroll_by(self.offset, bounds, content_bounds);
|
state.scroll_by(self.offset, bounds, content_bounds);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,12 @@ pub fn move_cursor_to_front<T>(target: Id) -> impl Operation<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Operation<T> for MoveCursor {
|
impl<T> Operation<T> for MoveCursor {
|
||||||
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
|
fn text_input(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
state: &mut dyn TextInput,
|
||||||
|
) {
|
||||||
match id {
|
match id {
|
||||||
Some(id) if id == &self.target => {
|
Some(id) if id == &self.target => {
|
||||||
state.move_cursor_to_front();
|
state.move_cursor_to_front();
|
||||||
|
|
@ -53,7 +58,12 @@ pub fn move_cursor_to_end<T>(target: Id) -> impl Operation<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Operation<T> for MoveCursor {
|
impl<T> Operation<T> for MoveCursor {
|
||||||
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
|
fn text_input(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
state: &mut dyn TextInput,
|
||||||
|
) {
|
||||||
match id {
|
match id {
|
||||||
Some(id) if id == &self.target => {
|
Some(id) if id == &self.target => {
|
||||||
state.move_cursor_to_end();
|
state.move_cursor_to_end();
|
||||||
|
|
@ -84,7 +94,12 @@ pub fn move_cursor_to<T>(target: Id, position: usize) -> impl Operation<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Operation<T> for MoveCursor {
|
impl<T> Operation<T> for MoveCursor {
|
||||||
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
|
fn text_input(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
state: &mut dyn TextInput,
|
||||||
|
) {
|
||||||
match id {
|
match id {
|
||||||
Some(id) if id == &self.target => {
|
Some(id) if id == &self.target => {
|
||||||
state.move_cursor_to(self.position);
|
state.move_cursor_to(self.position);
|
||||||
|
|
@ -113,7 +128,12 @@ pub fn select_all<T>(target: Id) -> impl Operation<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Operation<T> for MoveCursor {
|
impl<T> Operation<T> for MoveCursor {
|
||||||
fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
|
fn text_input(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
state: &mut dyn TextInput,
|
||||||
|
) {
|
||||||
match id {
|
match id {
|
||||||
Some(id) if id == &self.target => {
|
Some(id) if id == &self.target => {
|
||||||
state.select_all();
|
state.select_all();
|
||||||
|
|
|
||||||
|
|
@ -267,6 +267,18 @@ where
|
||||||
|
|
||||||
draw(renderer, defaults, layout, state.0.raw(), style, viewport);
|
draw(renderer, defaults, layout, state.0.raw(), style, viewport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn operate(
|
||||||
|
&self,
|
||||||
|
_state: &mut Tree,
|
||||||
|
layout: Layout<'_>,
|
||||||
|
_renderer: &Renderer,
|
||||||
|
operation: &mut dyn super::Operation,
|
||||||
|
) {
|
||||||
|
dbg!(&self.fragment);
|
||||||
|
|
||||||
|
operation.text(None, layout.bounds(), &self.fragment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Produces the [`layout::Node`] of a [`Text`] widget.
|
/// Produces the [`layout::Node`] of a [`Text`] widget.
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ uuid = { version = "1.0", features = ["js"] }
|
||||||
web-sys = { workspace = true, features = ["Window", "Storage"] }
|
web-sys = { workspace = true, features = ["Window", "Storage"] }
|
||||||
wasm-timer.workspace = true
|
wasm-timer.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
iced_test.workspace = true
|
||||||
|
|
||||||
[package.metadata.deb]
|
[package.metadata.deb]
|
||||||
assets = [
|
assets = [
|
||||||
["target/release-opt/todos", "usr/bin/iced-todos", "755"],
|
["target/release-opt/todos", "usr/bin/iced-todos", "755"],
|
||||||
|
|
|
||||||
|
|
@ -584,3 +584,36 @@ impl SavedState {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use iced::test;
|
||||||
|
use iced::test::selector;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_creates_a_new_task() {
|
||||||
|
let (mut todos, _command) = Todos::new();
|
||||||
|
let _command = todos.update(Message::Loaded(Err(LoadError::File)));
|
||||||
|
|
||||||
|
let mut interface = test::interface(todos.view());
|
||||||
|
|
||||||
|
let _input = interface
|
||||||
|
.click("new-task")
|
||||||
|
.expect("new-task input must be present");
|
||||||
|
|
||||||
|
interface.typewrite("Create the universe");
|
||||||
|
interface.press_key(keyboard::key::Named::Enter);
|
||||||
|
|
||||||
|
for message in interface.into_messages() {
|
||||||
|
let _command = todos.update(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut interface = test::interface(todos.view());
|
||||||
|
|
||||||
|
let _ = interface
|
||||||
|
.find(selector::text("Create the universe"))
|
||||||
|
.expect("New task must be present");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -479,6 +479,7 @@ use iced_winit::runtime;
|
||||||
|
|
||||||
pub use iced_futures::futures;
|
pub use iced_futures::futures;
|
||||||
pub use iced_futures::stream;
|
pub use iced_futures::stream;
|
||||||
|
pub use iced_test as test;
|
||||||
|
|
||||||
#[cfg(feature = "highlighter")]
|
#[cfg(feature = "highlighter")]
|
||||||
pub use iced_highlighter as highlighter;
|
pub use iced_highlighter as highlighter;
|
||||||
|
|
@ -624,6 +625,7 @@ pub use error::Error;
|
||||||
pub use event::Event;
|
pub use event::Event;
|
||||||
pub use executor::Executor;
|
pub use executor::Executor;
|
||||||
pub use font::Font;
|
pub use font::Font;
|
||||||
|
pub use program::Program;
|
||||||
pub use renderer::Renderer;
|
pub use renderer::Renderer;
|
||||||
pub use settings::Settings;
|
pub use settings::Settings;
|
||||||
pub use task::Task;
|
pub use task::Task;
|
||||||
|
|
|
||||||
21
test/Cargo.toml
Normal file
21
test/Cargo.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "iced_test"
|
||||||
|
version.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
categories.workspace = true
|
||||||
|
keywords.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
iced_runtime.workspace = true
|
||||||
|
iced_tiny_skia.workspace = true
|
||||||
|
|
||||||
|
iced_renderer.workspace = true
|
||||||
|
iced_renderer.features = ["tiny-skia"]
|
||||||
296
test/src/lib.rs
Normal file
296
test/src/lib.rs
Normal file
|
|
@ -0,0 +1,296 @@
|
||||||
|
//! Test your `iced` applications in headless mode.
|
||||||
|
#![allow(missing_docs, missing_debug_implementations)]
|
||||||
|
pub mod selector;
|
||||||
|
|
||||||
|
pub use selector::Selector;
|
||||||
|
|
||||||
|
use iced_renderer as renderer;
|
||||||
|
use iced_runtime as runtime;
|
||||||
|
use iced_runtime::core;
|
||||||
|
use iced_tiny_skia as tiny_skia;
|
||||||
|
|
||||||
|
use crate::core::clipboard;
|
||||||
|
use crate::core::keyboard;
|
||||||
|
use crate::core::mouse;
|
||||||
|
use crate::core::widget;
|
||||||
|
use crate::core::{Element, Event, Font, Pixels, Rectangle, Size, SmolStr};
|
||||||
|
use crate::renderer::Renderer;
|
||||||
|
use crate::runtime::user_interface;
|
||||||
|
use crate::runtime::UserInterface;
|
||||||
|
|
||||||
|
pub fn interface<'a, Message, Theme>(
|
||||||
|
element: impl Into<Element<'a, Message, Theme, Renderer>>,
|
||||||
|
) -> Interface<'a, Message, Theme, Renderer> {
|
||||||
|
let mut renderer = Renderer::Secondary(tiny_skia::Renderer::new(
|
||||||
|
Font::default(),
|
||||||
|
Pixels(16.0),
|
||||||
|
));
|
||||||
|
|
||||||
|
let raw = UserInterface::build(
|
||||||
|
element,
|
||||||
|
Size::new(1024.0, 1024.0),
|
||||||
|
user_interface::Cache::default(),
|
||||||
|
&mut renderer,
|
||||||
|
);
|
||||||
|
|
||||||
|
Interface {
|
||||||
|
raw,
|
||||||
|
renderer,
|
||||||
|
messages: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Interface<'a, Message, Theme, Renderer> {
|
||||||
|
raw: UserInterface<'a, Message, Theme, Renderer>,
|
||||||
|
renderer: Renderer,
|
||||||
|
messages: Vec<Message>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Target {
|
||||||
|
bounds: Rectangle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message, Theme, Renderer> Interface<'_, Message, Theme, Renderer>
|
||||||
|
where
|
||||||
|
Renderer: core::Renderer,
|
||||||
|
{
|
||||||
|
pub fn find(
|
||||||
|
&mut self,
|
||||||
|
selector: impl Into<Selector>,
|
||||||
|
) -> Result<Target, Error> {
|
||||||
|
let selector = selector.into();
|
||||||
|
|
||||||
|
match &selector {
|
||||||
|
Selector::Id(id) => {
|
||||||
|
struct FindById<'a> {
|
||||||
|
id: &'a widget::Id,
|
||||||
|
target: Option<Target>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl widget::Operation for FindById<'_> {
|
||||||
|
fn container(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&widget::Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
operate_on_children: &mut dyn FnMut(
|
||||||
|
&mut dyn widget::Operation<()>,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
if self.target.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Some(self.id) == id {
|
||||||
|
self.target = Some(Target { bounds });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
operate_on_children(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scrollable(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&widget::Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
_content_bounds: Rectangle,
|
||||||
|
_translation: core::Vector,
|
||||||
|
_state: &mut dyn widget::operation::Scrollable,
|
||||||
|
) {
|
||||||
|
if self.target.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Some(self.id) == id {
|
||||||
|
self.target = Some(Target { bounds });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_input(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&widget::Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
_state: &mut dyn widget::operation::TextInput,
|
||||||
|
) {
|
||||||
|
if self.target.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Some(self.id) == id {
|
||||||
|
self.target = Some(Target { bounds });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&widget::Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
_text: &str,
|
||||||
|
) {
|
||||||
|
if self.target.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Some(self.id) == id {
|
||||||
|
self.target = Some(Target { bounds });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&widget::Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
_state: &mut dyn std::any::Any,
|
||||||
|
) {
|
||||||
|
if self.target.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Some(self.id) == id {
|
||||||
|
self.target = Some(Target { bounds });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut find = FindById { id, target: None };
|
||||||
|
|
||||||
|
self.raw.operate(&self.renderer, &mut find);
|
||||||
|
|
||||||
|
find.target.ok_or(Error::NotFound(selector))
|
||||||
|
}
|
||||||
|
Selector::Text(text) => {
|
||||||
|
struct FindByText<'a> {
|
||||||
|
text: &'a str,
|
||||||
|
target: Option<Target>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl widget::Operation for FindByText<'_> {
|
||||||
|
fn container(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&widget::Id>,
|
||||||
|
_bounds: Rectangle,
|
||||||
|
operate_on_children: &mut dyn FnMut(
|
||||||
|
&mut dyn widget::Operation<()>,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
if self.target.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
operate_on_children(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&widget::Id>,
|
||||||
|
bounds: Rectangle,
|
||||||
|
text: &str,
|
||||||
|
) {
|
||||||
|
if self.target.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.text == text {
|
||||||
|
self.target = Some(Target { bounds });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut find = FindByText { text, target: None };
|
||||||
|
|
||||||
|
self.raw.operate(&self.renderer, &mut find);
|
||||||
|
|
||||||
|
find.target.ok_or(Error::NotFound(selector))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn click(
|
||||||
|
&mut self,
|
||||||
|
selector: impl Into<Selector>,
|
||||||
|
) -> Result<Target, Error> {
|
||||||
|
let target = self.find(selector)?;
|
||||||
|
|
||||||
|
let _ = self.raw.update(
|
||||||
|
&[
|
||||||
|
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)),
|
||||||
|
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)),
|
||||||
|
],
|
||||||
|
mouse::Cursor::Available(target.bounds.center()),
|
||||||
|
&mut self.renderer,
|
||||||
|
&mut clipboard::Null,
|
||||||
|
&mut self.messages,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn typewrite(&mut self, text: impl AsRef<str>) {
|
||||||
|
let events: Vec<_> = text
|
||||||
|
.as_ref()
|
||||||
|
.chars()
|
||||||
|
.map(|c| SmolStr::new_inline(&c.to_string()))
|
||||||
|
.flat_map(|c| {
|
||||||
|
key_press_and_release(
|
||||||
|
keyboard::Key::Character(c.clone()),
|
||||||
|
Some(c),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let _ = self.raw.update(
|
||||||
|
&events,
|
||||||
|
mouse::Cursor::Unavailable,
|
||||||
|
&mut self.renderer,
|
||||||
|
&mut clipboard::Null,
|
||||||
|
&mut self.messages,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn press_key(&mut self, key: impl Into<keyboard::Key>) {
|
||||||
|
let _ = self.raw.update(
|
||||||
|
&key_press_and_release(key, None),
|
||||||
|
mouse::Cursor::Unavailable,
|
||||||
|
&mut self.renderer,
|
||||||
|
&mut clipboard::Null,
|
||||||
|
&mut self.messages,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_messages(self) -> impl IntoIterator<Item = Message> {
|
||||||
|
self.messages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_press_and_release(
|
||||||
|
key: impl Into<keyboard::Key>,
|
||||||
|
text: Option<SmolStr>,
|
||||||
|
) -> [Event; 2] {
|
||||||
|
let key = key.into();
|
||||||
|
|
||||||
|
[
|
||||||
|
Event::Keyboard(keyboard::Event::KeyPressed {
|
||||||
|
key: key.clone(),
|
||||||
|
modified_key: key.clone(),
|
||||||
|
physical_key: keyboard::key::Physical::Unidentified(
|
||||||
|
keyboard::key::NativeCode::Unidentified,
|
||||||
|
),
|
||||||
|
location: keyboard::Location::Standard,
|
||||||
|
modifiers: keyboard::Modifiers::default(),
|
||||||
|
text,
|
||||||
|
}),
|
||||||
|
Event::Keyboard(keyboard::Event::KeyReleased {
|
||||||
|
key: key.clone(),
|
||||||
|
modified_key: key,
|
||||||
|
physical_key: keyboard::key::Physical::Unidentified(
|
||||||
|
keyboard::key::NativeCode::Unidentified,
|
||||||
|
),
|
||||||
|
location: keyboard::Location::Standard,
|
||||||
|
modifiers: keyboard::Modifiers::default(),
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Error {
|
||||||
|
NotFound(Selector),
|
||||||
|
}
|
||||||
24
test/src/selector.rs
Normal file
24
test/src/selector.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
use crate::core::text;
|
||||||
|
use crate::core::widget;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Selector {
|
||||||
|
Id(widget::Id),
|
||||||
|
Text(text::Fragment<'static>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<widget::Id> for Selector {
|
||||||
|
fn from(id: widget::Id) -> Self {
|
||||||
|
Self::Id(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&'static str> for Selector {
|
||||||
|
fn from(id: &'static str) -> Self {
|
||||||
|
Self::Id(widget::Id::new(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text(fragment: impl text::IntoFragment<'static>) -> Selector {
|
||||||
|
Selector::Text(fragment.into_fragment())
|
||||||
|
}
|
||||||
|
|
@ -445,6 +445,16 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn operate(
|
||||||
|
&self,
|
||||||
|
_state: &mut Tree,
|
||||||
|
layout: Layout<'_>,
|
||||||
|
_renderer: &Renderer,
|
||||||
|
operation: &mut dyn widget::Operation,
|
||||||
|
) {
|
||||||
|
operation.text(None, layout.bounds(), &self.label);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Theme, Renderer> From<Checkbox<'a, Message, Theme, Renderer>>
|
impl<'a, Message, Theme, Renderer> From<Checkbox<'a, Message, Theme, Renderer>>
|
||||||
|
|
|
||||||
|
|
@ -493,11 +493,11 @@ pub fn visible_bounds(id: Id) -> Task<Option<Rectangle>> {
|
||||||
impl Operation<Option<Rectangle>> for VisibleBounds {
|
impl Operation<Option<Rectangle>> for VisibleBounds {
|
||||||
fn scrollable(
|
fn scrollable(
|
||||||
&mut self,
|
&mut self,
|
||||||
_state: &mut dyn widget::operation::Scrollable,
|
|
||||||
_id: Option<&widget::Id>,
|
_id: Option<&widget::Id>,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
_content_bounds: Rectangle,
|
_content_bounds: Rectangle,
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
|
_state: &mut dyn widget::operation::Scrollable,
|
||||||
) {
|
) {
|
||||||
match self.scrollables.last() {
|
match self.scrollables.last() {
|
||||||
Some((last_translation, last_viewport, _depth)) => {
|
Some((last_translation, last_viewport, _depth)) => {
|
||||||
|
|
|
||||||
|
|
@ -487,11 +487,11 @@ where
|
||||||
state.translation(self.direction, bounds, content_bounds);
|
state.translation(self.direction, bounds, content_bounds);
|
||||||
|
|
||||||
operation.scrollable(
|
operation.scrollable(
|
||||||
state,
|
|
||||||
self.id.as_ref().map(|id| &id.0),
|
self.id.as_ref().map(|id| &id.0),
|
||||||
bounds,
|
bounds,
|
||||||
content_bounds,
|
content_bounds,
|
||||||
translation,
|
translation,
|
||||||
|
state,
|
||||||
);
|
);
|
||||||
|
|
||||||
operation.container(
|
operation.container(
|
||||||
|
|
|
||||||
|
|
@ -971,13 +971,13 @@ where
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&self,
|
||||||
tree: &mut widget::Tree,
|
tree: &mut widget::Tree,
|
||||||
_layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
operation: &mut dyn widget::Operation,
|
operation: &mut dyn widget::Operation,
|
||||||
) {
|
) {
|
||||||
let state = tree.state.downcast_mut::<State<Highlighter>>();
|
let state = tree.state.downcast_mut::<State<Highlighter>>();
|
||||||
|
|
||||||
operation.focusable(state, None);
|
operation.focusable(None, layout.bounds(), state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -617,14 +617,23 @@ where
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
_layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
operation: &mut dyn Operation,
|
operation: &mut dyn Operation,
|
||||||
) {
|
) {
|
||||||
let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>();
|
let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>();
|
||||||
|
|
||||||
operation.focusable(state, self.id.as_ref().map(|id| &id.0));
|
operation.focusable(
|
||||||
operation.text_input(state, self.id.as_ref().map(|id| &id.0));
|
self.id.as_ref().map(|id| &id.0),
|
||||||
|
layout.bounds(),
|
||||||
|
state,
|
||||||
|
);
|
||||||
|
|
||||||
|
operation.text_input(
|
||||||
|
self.id.as_ref().map(|id| &id.0),
|
||||||
|
layout.bounds(),
|
||||||
|
state,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(
|
fn update(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue