Introduce selector flag and decouple iced_widget from iced_runtime
This commit is contained in:
parent
34a42b5ad4
commit
81d1eda7fe
22 changed files with 118 additions and 67 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -2622,6 +2622,7 @@ dependencies = [
|
|||
"iced_core",
|
||||
"iced_debug",
|
||||
"iced_futures",
|
||||
"iced_selector",
|
||||
"raw-window-handle 0.6.2",
|
||||
"sipper",
|
||||
"thiserror 2.0.14",
|
||||
|
|
@ -2690,7 +2691,6 @@ version = "0.14.0-dev"
|
|||
dependencies = [
|
||||
"iced_highlighter",
|
||||
"iced_renderer",
|
||||
"iced_runtime",
|
||||
"log",
|
||||
"num-traits",
|
||||
"ouroboros",
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ crisp = ["iced_core/crisp", "iced_widget/crisp"]
|
|||
webgl = ["iced_renderer/webgl"]
|
||||
# Enables syntax highligthing
|
||||
highlighter = ["iced_highlighter", "iced_widget/highlighter"]
|
||||
# Enables the `widget::selector` module
|
||||
selector = ["iced_runtime/selector"]
|
||||
# Enables the advanced module
|
||||
advanced = ["iced_core/advanced", "iced_widget/advanced"]
|
||||
# Embeds Fira Sans into the final application; useful for testing and Wasm builds
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
//! Display interactive elements on top of other widgets.
|
||||
mod element;
|
||||
mod group;
|
||||
mod nested;
|
||||
|
||||
pub use element::Element;
|
||||
pub use group::Group;
|
||||
pub use nested::Nested;
|
||||
|
||||
use crate::layout;
|
||||
use crate::mouse;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use crate::core::event;
|
||||
use crate::core::layout;
|
||||
use crate::core::mouse;
|
||||
use crate::core::overlay;
|
||||
use crate::core::renderer;
|
||||
use crate::core::widget;
|
||||
use crate::core::{Clipboard, Event, Layout, Shell, Size};
|
||||
use crate::event;
|
||||
use crate::layout;
|
||||
use crate::mouse;
|
||||
use crate::overlay;
|
||||
use crate::renderer;
|
||||
use crate::widget;
|
||||
use crate::{Clipboard, Event, Layout, Shell, Size};
|
||||
|
||||
/// An overlay container that displays nested overlays
|
||||
#[allow(missing_debug_implementations)]
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
#![allow(missing_docs)]
|
||||
use iced_debug as debug;
|
||||
use iced_program as program;
|
||||
use iced_program::runtime;
|
||||
use iced_program::runtime::futures;
|
||||
#[cfg(feature = "tester")]
|
||||
use iced_test as test;
|
||||
use iced_widget::core;
|
||||
use iced_widget::runtime;
|
||||
use iced_widget::runtime::futures;
|
||||
|
||||
mod comet;
|
||||
mod executor;
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ publish = false
|
|||
|
||||
[dependencies]
|
||||
iced.workspace = true
|
||||
iced.features = ["debug"]
|
||||
iced.features = ["debug", "selector"]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use iced::event::{self, Event};
|
||||
use iced::mouse;
|
||||
use iced::widget::{
|
||||
column, container, horizontal_space, row, scrollable, text, vertical_space,
|
||||
column, container, horizontal_space, row, scrollable, selector, text,
|
||||
vertical_space,
|
||||
};
|
||||
use iced::window;
|
||||
use iced::{
|
||||
|
|
@ -23,13 +24,13 @@ struct Example {
|
|||
inner_bounds: Option<Rectangle>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone)]
|
||||
enum Message {
|
||||
MouseMoved(Point),
|
||||
WindowResized,
|
||||
Scrolled,
|
||||
OuterBoundsFetched(Option<Rectangle>),
|
||||
InnerBoundsFetched(Option<Rectangle>),
|
||||
OuterFound(Option<selector::Match>),
|
||||
InnerFound(Option<selector::Match>),
|
||||
}
|
||||
|
||||
impl Example {
|
||||
|
|
@ -41,18 +42,18 @@ impl Example {
|
|||
Task::none()
|
||||
}
|
||||
Message::Scrolled | Message::WindowResized => Task::batch(vec![
|
||||
container::visible_bounds(OUTER_CONTAINER)
|
||||
.map(Message::OuterBoundsFetched),
|
||||
container::visible_bounds(INNER_CONTAINER)
|
||||
.map(Message::InnerBoundsFetched),
|
||||
selector::find_by_id(OUTER_CONTAINER).map(Message::OuterFound),
|
||||
selector::find_by_id(INNER_CONTAINER).map(Message::InnerFound),
|
||||
]),
|
||||
Message::OuterBoundsFetched(outer_bounds) => {
|
||||
self.outer_bounds = outer_bounds;
|
||||
Message::OuterFound(outer) => {
|
||||
self.outer_bounds =
|
||||
outer.as_ref().and_then(selector::Bounded::visible_bounds);
|
||||
|
||||
Task::none()
|
||||
}
|
||||
Message::InnerBoundsFetched(inner_bounds) => {
|
||||
self.inner_bounds = inner_bounds;
|
||||
Message::InnerFound(inner) => {
|
||||
self.inner_bounds =
|
||||
inner.as_ref().and_then(selector::Bounded::visible_bounds);
|
||||
|
||||
Task::none()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ homepage.workspace = true
|
|||
categories.workspace = true
|
||||
keywords.workspace = true
|
||||
|
||||
[features]
|
||||
selector = ["dep:iced_selector"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
|
@ -17,7 +20,6 @@ workspace = true
|
|||
bytes.workspace = true
|
||||
iced_core.workspace = true
|
||||
iced_debug.workspace = true
|
||||
|
||||
iced_futures.workspace = true
|
||||
|
||||
raw-window-handle.workspace = true
|
||||
|
|
@ -25,3 +27,6 @@ thiserror.workspace = true
|
|||
|
||||
sipper.workspace = true
|
||||
sipper.optional = true
|
||||
|
||||
iced_selector.workspace = true
|
||||
iced_selector.optional = true
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@
|
|||
pub mod clipboard;
|
||||
pub mod font;
|
||||
pub mod keyboard;
|
||||
pub mod overlay;
|
||||
pub mod system;
|
||||
pub mod task;
|
||||
pub mod user_interface;
|
||||
pub mod widget;
|
||||
pub mod window;
|
||||
|
||||
pub use iced_core as core;
|
||||
|
|
@ -25,7 +25,6 @@ pub use iced_futures as futures;
|
|||
pub use task::Task;
|
||||
pub use user_interface::UserInterface;
|
||||
|
||||
use crate::core::widget;
|
||||
use crate::futures::futures::channel::oneshot;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
|
@ -45,7 +44,7 @@ pub enum Action<T> {
|
|||
},
|
||||
|
||||
/// Run a widget operation.
|
||||
Widget(Box<dyn widget::Operation>),
|
||||
Widget(Box<dyn core::widget::Operation>),
|
||||
|
||||
/// Run a clipboard action.
|
||||
Clipboard(clipboard::Action),
|
||||
|
|
@ -67,8 +66,8 @@ pub enum Action<T> {
|
|||
}
|
||||
|
||||
impl<T> Action<T> {
|
||||
/// Creates a new [`Action::Widget`] with the given [`widget::Operation`].
|
||||
pub fn widget(operation: impl widget::Operation + 'static) -> Self {
|
||||
/// Creates a new [`Action::Widget`] with the given [`widget::Operation`](core::widget::Operation).
|
||||
pub fn widget(operation: impl core::widget::Operation + 'static) -> Self {
|
||||
Self::Widget(Box::new(operation))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
//! Overlays for user interfaces.
|
||||
mod nested;
|
||||
|
||||
pub use nested::Nested;
|
||||
|
|
@ -2,13 +2,13 @@
|
|||
use crate::core::event::{self, Event};
|
||||
use crate::core::layout;
|
||||
use crate::core::mouse;
|
||||
use crate::core::overlay;
|
||||
use crate::core::renderer;
|
||||
use crate::core::widget;
|
||||
use crate::core::window;
|
||||
use crate::core::{
|
||||
Clipboard, Element, InputMethod, Layout, Rectangle, Shell, Size, Vector,
|
||||
};
|
||||
use crate::overlay;
|
||||
|
||||
/// A set of interactive graphical elements with a specific [`Layout`].
|
||||
///
|
||||
|
|
|
|||
5
runtime/src/widget.rs
Normal file
5
runtime/src/widget.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
//! Operate on widgets and query them at runtime.
|
||||
pub mod operation;
|
||||
|
||||
#[cfg(feature = "selector")]
|
||||
pub mod selector;
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
//! Change internal widget state.
|
||||
use crate::Id;
|
||||
use crate::core::widget::Id;
|
||||
use crate::core::widget::operation;
|
||||
use crate::runtime::task;
|
||||
use crate::runtime::{Action, Task};
|
||||
use crate::task;
|
||||
use crate::{Action, Task};
|
||||
|
||||
pub use crate::core::widget::operation::scrollable::{
|
||||
AbsoluteOffset, RelativeOffset,
|
||||
18
runtime/src/widget/selector.rs
Normal file
18
runtime/src/widget/selector.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//! Find and query widgets in your applications.
|
||||
pub use iced_selector::Selector;
|
||||
|
||||
pub use iced_selector::target::{Bounded, Match, Target, Text};
|
||||
|
||||
use crate::Task;
|
||||
use crate::core::widget;
|
||||
use crate::task;
|
||||
|
||||
/// Finds a widget by the given [`widget::Id`].
|
||||
pub fn find_by_id(id: impl Into<widget::Id>) -> Task<Option<Match>> {
|
||||
task::widget(id.into().find())
|
||||
}
|
||||
|
||||
/// Finds a widget that contains the given text.
|
||||
pub fn find_by_text(text: impl Into<String>) -> Task<Option<Text>> {
|
||||
task::widget(Selector::find(text.into()))
|
||||
}
|
||||
|
|
@ -66,6 +66,40 @@ impl Selector for &str {
|
|||
}
|
||||
}
|
||||
|
||||
impl Selector for String {
|
||||
type Output = target::Text;
|
||||
|
||||
fn select(&mut self, target: Target<'_>) -> Option<Self::Output> {
|
||||
match target {
|
||||
Target::TextInput {
|
||||
id,
|
||||
bounds,
|
||||
visible_bounds,
|
||||
state,
|
||||
} if state.text() == *self => Some(target::Text::Input {
|
||||
id: id.cloned(),
|
||||
bounds,
|
||||
visible_bounds,
|
||||
}),
|
||||
Target::Text {
|
||||
id,
|
||||
bounds,
|
||||
visible_bounds,
|
||||
content,
|
||||
} if content == *self => Some(target::Text::Raw {
|
||||
id: id.cloned(),
|
||||
bounds,
|
||||
visible_bounds,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn description(&self) -> String {
|
||||
format!("text == \"{}\"", self.escape_default())
|
||||
}
|
||||
}
|
||||
|
||||
impl Selector for Id {
|
||||
type Output = target::Match;
|
||||
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@
|
|||
//! Tasks can also be used to interact with the iced runtime. Some modules
|
||||
//! expose functions that create tasks for different purposes—like [changing
|
||||
//! window settings](window#functions), [focusing a widget](widget::operation::focus_next), or
|
||||
//! [querying its visible bounds](widget::container::visible_bounds).
|
||||
//! [querying its visible bounds](widget::selector::find_by_id).
|
||||
//!
|
||||
//! Like futures and streams, tasks expose [a monadic interface](Task::then)—but they can also be
|
||||
//! [mapped](Task::map), [chained](Task::chain), [batched](Task::batch), [canceled](Task::abortable),
|
||||
|
|
@ -620,15 +620,13 @@ pub mod touch {
|
|||
#[allow(hidden_glob_reexports)]
|
||||
pub mod widget {
|
||||
//! Use the built-in widgets or create your own.
|
||||
pub use iced_runtime::widget::*;
|
||||
pub use iced_widget::*;
|
||||
|
||||
// We hide the re-exported modules by `iced_widget`
|
||||
mod core {}
|
||||
mod graphics {}
|
||||
mod native {}
|
||||
mod renderer {}
|
||||
mod style {}
|
||||
mod runtime {}
|
||||
}
|
||||
|
||||
pub use application::Application;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ crisp = []
|
|||
|
||||
[dependencies]
|
||||
iced_renderer.workspace = true
|
||||
iced_runtime.workspace = true
|
||||
|
||||
num-traits.workspace = true
|
||||
log.workspace = true
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ use crate::core::{
|
|||
Padding, Pixels, Rectangle, Shadow, Shell, Size, Theme, Vector, Widget,
|
||||
color,
|
||||
};
|
||||
use crate::runtime::Task;
|
||||
|
||||
/// A widget that aligns its contents inside of its boundaries.
|
||||
///
|
||||
|
|
@ -457,12 +456,6 @@ pub fn draw_background<Renderer>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Produces a [`Task`] that queries the visible screen bounds of the
|
||||
/// [`Container`] with the given [`widget::Id`].
|
||||
pub fn visible_bounds(_id: impl Into<widget::Id>) -> Task<Option<Rectangle>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// The appearance of a container.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||
pub struct Style {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ use crate::core::widget::{self, Widget};
|
|||
use crate::core::{
|
||||
self, Clipboard, Event, Length, Rectangle, Shell, Size, Vector,
|
||||
};
|
||||
use crate::runtime::overlay::Nested;
|
||||
|
||||
use ouroboros::self_referencing;
|
||||
use rustc_hash::FxHasher;
|
||||
|
|
@ -286,7 +285,7 @@ where
|
|||
element
|
||||
.as_widget_mut()
|
||||
.overlay(tree, *layout, renderer, viewport, translation)
|
||||
.map(|overlay| RefCell::new(Nested::new(overlay)))
|
||||
.map(|overlay| RefCell::new(overlay::Nested::new(overlay)))
|
||||
},
|
||||
}
|
||||
.build();
|
||||
|
|
@ -317,7 +316,7 @@ struct Inner<'a, Message: 'a, Theme: 'a, Renderer: 'a> {
|
|||
|
||||
#[borrows(mut element, mut tree, layout)]
|
||||
#[not_covariant]
|
||||
overlay: Option<RefCell<Nested<'this, Message, Theme, Renderer>>>,
|
||||
overlay: Option<RefCell<overlay::Nested<'this, Message, Theme, Renderer>>>,
|
||||
}
|
||||
|
||||
struct Overlay<'a, Message, Theme, Renderer>(
|
||||
|
|
@ -334,7 +333,7 @@ impl<Message, Theme, Renderer> Drop for Overlay<'_, Message, Theme, Renderer> {
|
|||
impl<Message, Theme, Renderer> Overlay<'_, Message, Theme, Renderer> {
|
||||
fn with_overlay_maybe<T>(
|
||||
&self,
|
||||
f: impl FnOnce(&mut Nested<'_, Message, Theme, Renderer>) -> T,
|
||||
f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,
|
||||
) -> Option<T> {
|
||||
self.0.as_ref().unwrap().with_overlay(|overlay| {
|
||||
overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut()))
|
||||
|
|
@ -343,7 +342,7 @@ impl<Message, Theme, Renderer> Overlay<'_, Message, Theme, Renderer> {
|
|||
|
||||
fn with_overlay_mut_maybe<T>(
|
||||
&mut self,
|
||||
f: impl FnOnce(&mut Nested<'_, Message, Theme, Renderer>) -> T,
|
||||
f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,
|
||||
) -> Option<T> {
|
||||
self.0.as_mut().unwrap().with_overlay_mut(|overlay| {
|
||||
overlay.as_mut().map(|nested| (f)(nested.get_mut()))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use crate::core::widget::tree::{self, Tree};
|
|||
use crate::core::{
|
||||
self, Clipboard, Element, Length, Rectangle, Shell, Size, Vector, Widget,
|
||||
};
|
||||
use crate::runtime::overlay::Nested;
|
||||
|
||||
use ouroboros::self_referencing;
|
||||
use std::cell::RefCell;
|
||||
|
|
@ -472,7 +471,9 @@ where
|
|||
viewport,
|
||||
translation,
|
||||
)
|
||||
.map(|overlay| RefCell::new(Nested::new(overlay)))
|
||||
.map(|overlay| {
|
||||
RefCell::new(overlay::Nested::new(overlay))
|
||||
})
|
||||
},
|
||||
)
|
||||
},
|
||||
|
|
@ -519,7 +520,7 @@ struct Inner<'a, 'b, Message, Theme, Renderer, Event, S> {
|
|||
|
||||
#[borrows(mut instance, mut tree)]
|
||||
#[not_covariant]
|
||||
overlay: Option<RefCell<Nested<'this, Event, Theme, Renderer>>>,
|
||||
overlay: Option<RefCell<overlay::Nested<'this, Event, Theme, Renderer>>>,
|
||||
}
|
||||
|
||||
struct OverlayInstance<'a, 'b, Message, Theme, Renderer, Event, S> {
|
||||
|
|
@ -531,7 +532,7 @@ impl<Message, Theme, Renderer, Event, S>
|
|||
{
|
||||
fn with_overlay_maybe<T>(
|
||||
&self,
|
||||
f: impl FnOnce(&mut Nested<'_, Event, Theme, Renderer>) -> T,
|
||||
f: impl FnOnce(&mut overlay::Nested<'_, Event, Theme, Renderer>) -> T,
|
||||
) -> Option<T> {
|
||||
self.overlay
|
||||
.as_ref()
|
||||
|
|
@ -546,7 +547,7 @@ impl<Message, Theme, Renderer, Event, S>
|
|||
|
||||
fn with_overlay_mut_maybe<T>(
|
||||
&mut self,
|
||||
f: impl FnOnce(&mut Nested<'_, Event, Theme, Renderer>) -> T,
|
||||
f: impl FnOnce(&mut overlay::Nested<'_, Event, Theme, Renderer>) -> T,
|
||||
) -> Option<T> {
|
||||
self.overlay
|
||||
.as_mut()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use crate::core::{
|
|||
Vector, Widget,
|
||||
};
|
||||
use crate::horizontal_space;
|
||||
use crate::runtime::overlay::Nested;
|
||||
|
||||
use ouroboros::self_referencing;
|
||||
use std::cell::{RefCell, RefMut};
|
||||
|
|
@ -327,7 +326,9 @@ where
|
|||
viewport,
|
||||
translation,
|
||||
)
|
||||
.map(|overlay| RefCell::new(Nested::new(overlay))),
|
||||
.map(|overlay| {
|
||||
RefCell::new(overlay::Nested::new(overlay))
|
||||
}),
|
||||
is_layout_invalid,
|
||||
)
|
||||
},
|
||||
|
|
@ -364,7 +365,7 @@ struct Overlay<'a, 'b, Message, Theme, Renderer> {
|
|||
#[borrows(mut content, mut tree)]
|
||||
#[not_covariant]
|
||||
overlay: (
|
||||
Option<RefCell<Nested<'this, Message, Theme, Renderer>>>,
|
||||
Option<RefCell<overlay::Nested<'this, Message, Theme, Renderer>>>,
|
||||
&'this mut bool,
|
||||
),
|
||||
}
|
||||
|
|
@ -372,7 +373,7 @@ struct Overlay<'a, 'b, Message, Theme, Renderer> {
|
|||
impl<Message, Theme, Renderer> Overlay<'_, '_, Message, Theme, Renderer> {
|
||||
fn with_overlay_maybe<T>(
|
||||
&self,
|
||||
f: impl FnOnce(&mut Nested<'_, Message, Theme, Renderer>) -> T,
|
||||
f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,
|
||||
) -> Option<T> {
|
||||
self.with_overlay(|(overlay, _layout)| {
|
||||
overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut()))
|
||||
|
|
@ -381,7 +382,7 @@ impl<Message, Theme, Renderer> Overlay<'_, '_, Message, Theme, Renderer> {
|
|||
|
||||
fn with_overlay_mut_maybe<T>(
|
||||
&mut self,
|
||||
f: impl FnOnce(&mut Nested<'_, Message, Theme, Renderer>) -> T,
|
||||
f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,
|
||||
) -> Option<T> {
|
||||
self.with_overlay_mut(|(overlay, _layout)| {
|
||||
overlay.as_mut().map(|nested| (f)(nested.get_mut()))
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@
|
|||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
pub use iced_renderer as renderer;
|
||||
pub use iced_renderer::core;
|
||||
pub use iced_renderer::graphics;
|
||||
pub use iced_runtime as runtime;
|
||||
pub use iced_runtime::core;
|
||||
|
||||
pub use core::widget::Id;
|
||||
|
||||
|
|
@ -25,7 +24,6 @@ pub mod container;
|
|||
pub mod float;
|
||||
pub mod grid;
|
||||
pub mod keyed;
|
||||
pub mod operation;
|
||||
pub mod overlay;
|
||||
pub mod pane_grid;
|
||||
pub mod pick_list;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue