Merge branch 'master' into feature/test-recorder
This commit is contained in:
commit
98d8f466bb
98 changed files with 643 additions and 204 deletions
85
Cargo.lock
generated
85
Cargo.lock
generated
|
|
@ -538,6 +538,26 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
|
||||
dependencies = [
|
||||
"bincode_derive",
|
||||
"serde",
|
||||
"unty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
|
||||
dependencies = [
|
||||
"virtue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
|
|
@ -730,6 +750,17 @@ dependencies = [
|
|||
"wayland-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-hot-protocol"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/hecrj/cargo-hot.git?rev=b8dc518b8640928178a501257e353b73bc06cf47#b8dc518b8640928178a501257e353b73bc06cf47"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode 2.0.1",
|
||||
"log",
|
||||
"subsecond",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
|
|
@ -2464,7 +2495,7 @@ dependencies = [
|
|||
name = "iced_beacon"
|
||||
version = "0.14.0-dev"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bincode 1.3.3",
|
||||
"futures",
|
||||
"iced_core",
|
||||
"log",
|
||||
|
|
@ -2496,6 +2527,7 @@ dependencies = [
|
|||
name = "iced_debug"
|
||||
version = "0.14.0-dev"
|
||||
dependencies = [
|
||||
"cargo-hot-protocol",
|
||||
"iced_beacon",
|
||||
"iced_core",
|
||||
"iced_futures",
|
||||
|
|
@ -3293,6 +3325,15 @@ version = "2.7.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "memfd"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64"
|
||||
dependencies = [
|
||||
"rustix 0.38.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.5"
|
||||
|
|
@ -5518,6 +5559,34 @@ dependencies = [
|
|||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subsecond"
|
||||
version = "0.7.0-alpha.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43c5b40acd555d02d9a0b5bf4080dbf2cd085d5e2eb2ae7851cb14b9bf5af15c"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"libc",
|
||||
"libloading",
|
||||
"memfd",
|
||||
"memmap2",
|
||||
"serde",
|
||||
"subsecond-types",
|
||||
"thiserror 2.0.12",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subsecond-types"
|
||||
version = "0.7.0-alpha.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bedadae58a56e137ac970c38c44bff38cee24400fef64c37d5a188a065b1ec1f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
|
|
@ -5595,7 +5664,7 @@ version = "5.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bincode 1.3.3",
|
||||
"bitflags 1.3.2",
|
||||
"flate2",
|
||||
"fnv",
|
||||
|
|
@ -6281,6 +6350,12 @@ version = "0.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "unty"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
|
|
@ -6406,6 +6481,12 @@ version = "0.9.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "virtue"
|
||||
version = "0.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
|
||||
|
||||
[[package]]
|
||||
name = "visible_bounds"
|
||||
version = "0.1.0"
|
||||
|
|
|
|||
|
|
@ -41,10 +41,12 @@ qr_code = ["iced_widget/qr_code"]
|
|||
markdown = ["iced_widget/markdown"]
|
||||
# Enables lazy widgets
|
||||
lazy = ["iced_widget/lazy"]
|
||||
# Enables a debug view in native platforms (press F12)
|
||||
# Enables debug metrics in native platforms (press F12)
|
||||
debug = ["iced_winit/debug", "iced_devtools"]
|
||||
# Enables time-travel debugging (very experimental!)
|
||||
time-travel = ["debug", "iced_devtools/time-travel"]
|
||||
# Enables hot reloading (very experimental!)
|
||||
hot = ["debug", "iced_debug/hot"]
|
||||
# Enables the tester developer tool for recording and playing tests (press F12)
|
||||
tester = ["debug", "test", "iced_devtools/tester"]
|
||||
# Enables testing features (e.g. application presets)
|
||||
|
|
@ -171,6 +173,7 @@ bincode = "1.3"
|
|||
bitflags = "2.0"
|
||||
bytemuck = { version = "1.0", features = ["derive"] }
|
||||
bytes = "1.6"
|
||||
cargo-hot = { package = "cargo-hot-protocol", git = "https://github.com/hecrj/cargo-hot.git", rev = "b8dc518b8640928178a501257e353b73bc06cf47" }
|
||||
cosmic-text = "0.14"
|
||||
dark-light = "2.0"
|
||||
futures = { version = "0.3", default-features = false }
|
||||
|
|
|
|||
|
|
@ -137,16 +137,24 @@ where
|
|||
//
|
||||
// We use the maximum cross length obtained in the first pass as the maximum
|
||||
// cross limit.
|
||||
//
|
||||
// We can defer the layout of any elements that have a fixed size in the main axis,
|
||||
// allowing them to use the cross calculations of the next pass.
|
||||
if cross_compress && some_fill_cross {
|
||||
for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate()
|
||||
{
|
||||
let (fill_main_factor, fill_cross_factor) = {
|
||||
let (main_size, cross_size) = {
|
||||
let size = child.as_widget().size();
|
||||
|
||||
axis.pack(size.width.fill_factor(), size.height.fill_factor())
|
||||
axis.pack(size.width, size.height)
|
||||
};
|
||||
|
||||
if fill_main_factor == 0 && fill_cross_factor != 0 {
|
||||
if main_size.fill_factor() == 0 && cross_size.fill_factor() != 0 {
|
||||
if let Length::Fixed(main) = main_size {
|
||||
available -= main;
|
||||
continue;
|
||||
}
|
||||
|
||||
let (max_width, max_height) = axis.pack(available, cross);
|
||||
|
||||
let child_limits =
|
||||
|
|
@ -176,9 +184,9 @@ where
|
|||
};
|
||||
|
||||
// THIRD PASS
|
||||
// We only have the elements that are fluid in the main axis left.
|
||||
// We lay out the elements that are fluid in the main axis.
|
||||
// We use the remaining space to evenly allocate space based on fill factors.
|
||||
for (i, (child, tree)) in items.iter().zip(trees).enumerate() {
|
||||
for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() {
|
||||
let (fill_main_factor, fill_cross_factor) = {
|
||||
let size = child.as_widget().size();
|
||||
|
||||
|
|
@ -224,10 +232,43 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// FOURTH PASS (conditional)
|
||||
// We lay out any elements that were deferred in the second pass.
|
||||
// These are elements that must be compressed in their cross axis and have
|
||||
// a fixed length in the main axis.
|
||||
if cross_compress && some_fill_cross {
|
||||
for (i, (child, tree)) in items.iter().zip(trees).enumerate() {
|
||||
let (main_size, cross_size) = {
|
||||
let size = child.as_widget().size();
|
||||
|
||||
axis.pack(size.width, size.height)
|
||||
};
|
||||
|
||||
if cross_size.fill_factor() != 0 {
|
||||
let Length::Fixed(main) = main_size else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let (max_width, max_height) = axis.pack(main, cross);
|
||||
|
||||
let child_limits =
|
||||
Limits::new(Size::ZERO, Size::new(max_width, max_height));
|
||||
|
||||
let layout =
|
||||
child.as_widget().layout(tree, renderer, &child_limits);
|
||||
let size = layout.size();
|
||||
|
||||
cross = cross.max(axis.cross(size));
|
||||
|
||||
nodes[i] = layout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let pad = axis.pack(padding.left, padding.top);
|
||||
let mut main = pad.0;
|
||||
|
||||
// FOURTH PASS
|
||||
// FIFTH PASS
|
||||
// We align all the laid out nodes in the cross axis, if needed.
|
||||
for (i, node) in nodes.iter_mut().enumerate() {
|
||||
if i > 0 {
|
||||
|
|
|
|||
|
|
@ -107,3 +107,13 @@ where
|
|||
write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl Point<f32> {
|
||||
/// Snaps the [`Point`] to __unsigned__ integer coordinates.
|
||||
pub fn snap(self) -> Point<u32> {
|
||||
Point {
|
||||
x: self.x.round() as u32,
|
||||
y: self.y.round() as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,16 +244,19 @@ impl Rectangle<f32> {
|
|||
|
||||
/// Snaps the [`Rectangle`] to __unsigned__ integer coordinates.
|
||||
pub fn snap(self) -> Option<Rectangle<u32>> {
|
||||
let width = self.width as u32;
|
||||
let height = self.height as u32;
|
||||
let top_left = self.position().snap();
|
||||
let bottom_right = (self.position() + Vector::from(self.size())).snap();
|
||||
|
||||
let width = bottom_right.x.checked_sub(top_left.x)?;
|
||||
let height = bottom_right.y.checked_sub(top_left.y)?;
|
||||
|
||||
if width < 1 || height < 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Rectangle {
|
||||
x: self.x as u32,
|
||||
y: self.y as u32,
|
||||
x: top_left.x,
|
||||
y: top_left.y,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ impl<'a, Message> Shell<'a, Message> {
|
|||
}
|
||||
|
||||
/// Returns true if the [`Shell`] contains no published messages
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.messages.is_empty()
|
||||
}
|
||||
|
|
@ -50,11 +51,13 @@ impl<'a, Message> Shell<'a, Message> {
|
|||
}
|
||||
|
||||
/// Returns the current [`event::Status`] of the [`Shell`].
|
||||
#[must_use]
|
||||
pub fn event_status(&self) -> event::Status {
|
||||
self.event_status
|
||||
}
|
||||
|
||||
/// Returns whether the current event has been captured.
|
||||
#[must_use]
|
||||
pub fn is_event_captured(&self) -> bool {
|
||||
self.event_status == event::Status::Captured
|
||||
}
|
||||
|
|
@ -73,6 +76,7 @@ impl<'a, Message> Shell<'a, Message> {
|
|||
}
|
||||
|
||||
/// Returns the request a redraw should happen, if any.
|
||||
#[must_use]
|
||||
pub fn redraw_request(&self) -> window::RedrawRequest {
|
||||
self.redraw_request
|
||||
}
|
||||
|
|
@ -101,16 +105,19 @@ impl<'a, Message> Shell<'a, Message> {
|
|||
}
|
||||
|
||||
/// Returns the current [`InputMethod`] strategy.
|
||||
#[must_use]
|
||||
pub fn input_method(&self) -> &InputMethod {
|
||||
&self.input_method
|
||||
}
|
||||
|
||||
/// Returns the current [`InputMethod`] strategy.
|
||||
#[must_use]
|
||||
pub fn input_method_mut(&mut self) -> &mut InputMethod {
|
||||
&mut self.input_method
|
||||
}
|
||||
|
||||
/// Returns whether the current layout is invalid or not.
|
||||
#[must_use]
|
||||
pub fn is_layout_invalid(&self) -> bool {
|
||||
self.is_layout_invalid
|
||||
}
|
||||
|
|
@ -134,6 +141,7 @@ impl<'a, Message> Shell<'a, Message> {
|
|||
|
||||
/// Returns whether the widgets of the current application have been
|
||||
/// invalidated.
|
||||
#[must_use]
|
||||
pub fn are_widgets_invalid(&self) -> bool {
|
||||
self.are_widgets_invalid
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{Point, Size};
|
||||
|
||||
/// The position of a window in a given screen.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Position {
|
||||
/// The platform-specific default position for a new window.
|
||||
Default,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ keywords.workspace = true
|
|||
|
||||
[features]
|
||||
enable = ["dep:iced_beacon"]
|
||||
hot = ["enable", "dep:cargo-hot"]
|
||||
|
||||
[dependencies]
|
||||
iced_core.workspace = true
|
||||
|
|
@ -21,3 +22,6 @@ log.workspace = true
|
|||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
iced_beacon.workspace = true
|
||||
iced_beacon.optional = true
|
||||
|
||||
cargo-hot.workspace = true
|
||||
cargo-hot.optional = true
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ pub fn disable() {
|
|||
|
||||
pub fn init(metadata: Metadata) {
|
||||
internal::init(metadata);
|
||||
hot::init();
|
||||
}
|
||||
|
||||
pub fn quit() -> bool {
|
||||
|
|
@ -113,6 +114,18 @@ pub fn commands() -> Subscription<Command> {
|
|||
internal::commands()
|
||||
}
|
||||
|
||||
pub fn hot<O>(f: impl FnOnce() -> O) -> O {
|
||||
hot::call(f)
|
||||
}
|
||||
|
||||
pub fn on_hotpatch(f: impl Fn() + Send + Sync + 'static) {
|
||||
hot::on_hotpatch(f)
|
||||
}
|
||||
|
||||
pub fn is_stale() -> bool {
|
||||
hot::is_stale()
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enable", not(target_arch = "wasm32")))]
|
||||
mod internal {
|
||||
use crate::core::theme;
|
||||
|
|
@ -399,3 +412,83 @@ mod internal {
|
|||
pub fn finish(self) {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "hot")]
|
||||
mod hot {
|
||||
use std::collections::BTreeSet;
|
||||
use std::sync::atomic::{self, AtomicBool};
|
||||
use std::sync::{Arc, Mutex, OnceLock};
|
||||
|
||||
static IS_STALE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
static HOT_FUNCTIONS_PENDING: Mutex<BTreeSet<u64>> =
|
||||
Mutex::new(BTreeSet::new());
|
||||
|
||||
static HOT_FUNCTIONS: OnceLock<BTreeSet<u64>> = OnceLock::new();
|
||||
|
||||
pub fn init() {
|
||||
cargo_hot::connect();
|
||||
|
||||
cargo_hot::subsecond::register_handler(Arc::new(|| {
|
||||
if HOT_FUNCTIONS.get().is_none() {
|
||||
HOT_FUNCTIONS
|
||||
.set(std::mem::take(
|
||||
&mut HOT_FUNCTIONS_PENDING
|
||||
.lock()
|
||||
.expect("Lock hot functions"),
|
||||
))
|
||||
.expect("Set hot functions");
|
||||
}
|
||||
|
||||
IS_STALE.store(false, atomic::Ordering::Relaxed);
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn call<O>(f: impl FnOnce() -> O) -> O {
|
||||
let mut f = Some(f);
|
||||
|
||||
// The `move` here is important. Hotpatching will not work
|
||||
// otherwise.
|
||||
let mut f = cargo_hot::subsecond::HotFn::current(move || {
|
||||
f.take().expect("Hot function is stale")()
|
||||
});
|
||||
|
||||
let address = f.ptr_address().0;
|
||||
|
||||
if let Some(hot_functions) = HOT_FUNCTIONS.get() {
|
||||
if hot_functions.contains(&address) {
|
||||
IS_STALE.store(true, atomic::Ordering::Relaxed);
|
||||
}
|
||||
} else {
|
||||
let _ = HOT_FUNCTIONS_PENDING
|
||||
.lock()
|
||||
.expect("Lock hot functions")
|
||||
.insert(address);
|
||||
}
|
||||
|
||||
f.call(())
|
||||
}
|
||||
|
||||
pub fn on_hotpatch(f: impl Fn() + Send + Sync + 'static) {
|
||||
cargo_hot::subsecond::register_handler(Arc::new(f));
|
||||
}
|
||||
|
||||
pub fn is_stale() -> bool {
|
||||
IS_STALE.load(atomic::Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "hot"))]
|
||||
mod hot {
|
||||
pub fn init() {}
|
||||
|
||||
pub fn call<O>(f: impl FnOnce() -> O) -> O {
|
||||
f()
|
||||
}
|
||||
|
||||
pub fn on_hotpatch(_f: impl Fn() + Send + Sync + 'static) {}
|
||||
|
||||
pub fn is_stale() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -397,13 +397,16 @@ where
|
|||
}
|
||||
.map(|mode| Element::from(mode).map(Event::Message));
|
||||
|
||||
let notification = self.show_notification.then(|| {
|
||||
bottom_right(opaque(
|
||||
container(text("Press F12 to open developer tools"))
|
||||
.padding(10)
|
||||
.style(container::dark),
|
||||
))
|
||||
});
|
||||
let notification = self
|
||||
.show_notification
|
||||
.then(|| text("Press F12 to open debug metrics"))
|
||||
.or_else(|| {
|
||||
debug::is_stale().then(|| {
|
||||
text(
|
||||
"Types have changed. Restart to re-enable hotpatching.",
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
let sidebar = if let Mode::Open { tester } = &self.mode {
|
||||
let title = monospace("Developer Tools");
|
||||
|
|
@ -429,7 +432,13 @@ where
|
|||
stack![content]
|
||||
.height(Fill)
|
||||
.push_maybe(setup.map(opaque))
|
||||
.push_maybe(notification),
|
||||
.push_maybe(notification.map(|notification| {
|
||||
bottom_right(opaque(
|
||||
container(notification)
|
||||
.padding(10)
|
||||
.style(container::dark),
|
||||
))
|
||||
})),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ impl Arc {
|
|||
self.cache.clear();
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
Canvas::new(self).width(Fill).height(Fill).into()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
container(hover(
|
||||
self.bezier.view(&self.curves).map(Message::AddCurve),
|
||||
if self.curves.is_empty() {
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ impl Generator {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
match self {
|
||||
Self::Loading => center("Loading...").into(),
|
||||
Self::Done => center(
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let default_checkbox = checkbox("Default", self.default)
|
||||
.on_toggle(Message::DefaultToggled);
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ impl Clock {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let canvas = canvas(self as &Self).width(Fill).height(Fill);
|
||||
|
||||
container(canvas).padding(20).into()
|
||||
|
|
@ -166,7 +166,7 @@ impl<Message> canvas::Program<Message> for Clock {
|
|||
let y = radius * angle.0.sin();
|
||||
|
||||
frame.fill_text(canvas::Text {
|
||||
content: format!("{}", hour),
|
||||
content: format!("{hour}"),
|
||||
size: (radius / 5.0).into(),
|
||||
position: Point::new(x * 0.82, y * 0.82),
|
||||
color: palette.secondary.strong.text,
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ impl ColorPalette {
|
|||
self.theme = Theme::new(to_color(srgb));
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let base = self.theme.base;
|
||||
|
||||
let srgb = to_rgb(base);
|
||||
|
|
@ -149,7 +149,7 @@ impl Theme {
|
|||
.chain(self.higher.iter())
|
||||
}
|
||||
|
||||
pub fn view(&self) -> Element<Message> {
|
||||
pub fn view(&self) -> Element<'_, Message> {
|
||||
Canvas::new(self).width(Fill).height(Fill).into()
|
||||
}
|
||||
|
||||
|
|
@ -296,7 +296,7 @@ trait ColorSpace: Sized {
|
|||
}
|
||||
|
||||
impl<C: ColorSpace + Copy> ColorPicker<C> {
|
||||
fn view(&self, color: C) -> Element<C> {
|
||||
fn view(&self, color: C) -> Element<'_, C> {
|
||||
let [c1, c2, c3] = color.components();
|
||||
let [cr1, cr2, cr3] = C::COMPONENT_RANGES;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let combo_box = combo_box(
|
||||
&self.languages,
|
||||
"Type a language...",
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ impl Counter {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Column<Message> {
|
||||
fn view(&self) -> Column<'_, Message> {
|
||||
column![
|
||||
button("Increment").on_press(Message::Increment),
|
||||
text(self.value).size(50),
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let border::Radius {
|
||||
top_left,
|
||||
top_right,
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let content = column![
|
||||
circle(self.radius),
|
||||
text!("Radius: {:.2}", self.radius),
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let downloads =
|
||||
Column::with_children(self.downloads.iter().map(Download::view))
|
||||
.push(
|
||||
|
|
@ -152,7 +152,7 @@ impl Download {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn view(&self) -> Element<Message> {
|
||||
pub fn view(&self) -> Element<'_, Message> {
|
||||
let current_progress = match &self.state {
|
||||
State::Idle => 0.0,
|
||||
State::Downloading { progress, .. } => *progress,
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ impl Editor {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let controls = row![
|
||||
action(new_icon(), "New file", Some(Message::NewFile)),
|
||||
action(
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ impl Events {
|
|||
event::listen().map(Message::EventOccurred)
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let events = Column::with_children(
|
||||
self.last
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ impl Exit {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let content = if self.show_confirm {
|
||||
column![
|
||||
"Are you sure you want to exit?",
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ impl Image {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let i_am_ferris = column![
|
||||
"Hello!",
|
||||
Element::from(
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ impl GameOfLife {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let version = self.version;
|
||||
let selected_speed = self.next_speed.unwrap_or(self.speed);
|
||||
let controls = view_controls(
|
||||
|
|
@ -320,7 +320,7 @@ mod grid {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn view(&self) -> Element<Message> {
|
||||
pub fn view(&self) -> Element<'_, Message> {
|
||||
Canvas::new(self).width(Fill).height(Fill).into()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ impl Gradient {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let Self {
|
||||
start,
|
||||
end,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ impl Controls {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn view(&self) -> Element<Message, Theme, Renderer> {
|
||||
pub fn view(&self) -> Element<'_, Message, Theme, Renderer> {
|
||||
let background_color = self.background_color;
|
||||
|
||||
let sliders = row![
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ impl Layout {
|
|||
})
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let header = row![
|
||||
text(self.example.title).size(20).font(Font::MONOSPACE),
|
||||
horizontal_space(),
|
||||
|
|
@ -121,7 +121,7 @@ impl Layout {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, Eq)]
|
||||
struct Example {
|
||||
title: &'static str,
|
||||
view: fn() -> Element<'static, Message>,
|
||||
|
|
@ -190,7 +190,7 @@ impl Example {
|
|||
Self::LIST.get(index + 1).copied().unwrap_or(self)
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
(self.view)()
|
||||
}
|
||||
}
|
||||
|
|
@ -201,6 +201,12 @@ impl Default for Example {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Example {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.title == other.title
|
||||
}
|
||||
}
|
||||
|
||||
fn centered<'a>() -> Element<'a, Message> {
|
||||
center(text("I am centered!").size(50)).into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let options = lazy(self.version, |_| {
|
||||
let mut items: Vec<_> = self.items.iter().cloned().collect();
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ impl LoadingSpinners {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let column = [
|
||||
&easing::EMPHASIZED,
|
||||
&easing::EMPHASIZED_DECELERATE,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl Loupe {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
center(loupe(
|
||||
3.0,
|
||||
column![
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ Now, let's show the actual counter by putting it all together in our __view logi
|
|||
use iced::widget::{button, column, text, Column};
|
||||
|
||||
impl Counter {
|
||||
pub fn view(&self) -> Column<Message> {
|
||||
pub fn view(&self) -> Column<'_, Message> {
|
||||
// We use a column: a simple vertical layout
|
||||
column![
|
||||
// The increment button. We tell it to produce an
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ impl Markdown {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let editor = text_editor(&self.raw)
|
||||
.placeholder("Type your Markdown here...")
|
||||
.on_action(Message::Edit)
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let content = container(
|
||||
column![
|
||||
row![text("Top Left"), horizontal_space(), text("Top Right")]
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self, window_id: window::Id) -> Element<Message> {
|
||||
fn view(&self, window_id: window::Id) -> Element<'_, Message> {
|
||||
if let Some(window) = self.windows.get(&window_id) {
|
||||
center(window.view(window_id)).into()
|
||||
} else {
|
||||
|
|
@ -161,14 +161,14 @@ impl Example {
|
|||
impl Window {
|
||||
fn new(count: usize) -> Self {
|
||||
Self {
|
||||
title: format!("Window_{}", count),
|
||||
title: format!("Window_{count}"),
|
||||
scale_input: "1.0".to_string(),
|
||||
current_scale: 1.0,
|
||||
theme: Theme::ALL[count % Theme::ALL.len()].clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self, id: window::Id) -> Element<Message> {
|
||||
fn view(&self, id: window::Id) -> Element<'_, Message> {
|
||||
let scale_input = column![
|
||||
text("Window scale factor:"),
|
||||
text_input("Window Scale", &self.scale_input)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ impl Multitouch {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
Canvas::new(self).width(Fill).height(Fill).into()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ impl Example {
|
|||
})
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let focus = self.focus;
|
||||
let total_panes = self.panes.len();
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let pick_list = pick_list(
|
||||
&Language::ALL[..],
|
||||
self.selected_language,
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ impl Pokedex {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let content: Element<_> = match self {
|
||||
Pokedex::Loading => {
|
||||
text("Searching for Pokémon...").size(40).into()
|
||||
|
|
@ -100,7 +100,7 @@ struct Pokemon {
|
|||
impl Pokemon {
|
||||
const TOTAL: u16 = 807;
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
row![
|
||||
image::viewer(self.image.clone()),
|
||||
column![
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl Progress {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let bar = progress_bar(0.0..=100.0, self.value);
|
||||
|
||||
column![
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ impl QRGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let title = text("QR Code Generator").size(70);
|
||||
|
||||
let input =
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ impl Example {
|
|||
|png_result| match png_result {
|
||||
Ok(path) => format!("Png saved as: {path:?}!"),
|
||||
Err(PngError(error)) => {
|
||||
format!("Png could not be saved due to:\n{}", error)
|
||||
format!("Png could not be saved due to:\n{error}")
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ impl ScrollableDemo {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let scrollbar_width_slider = slider(
|
||||
0..=15,
|
||||
self.scrollbar_width,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use iced::mouse;
|
||||
use iced::widget::canvas::{self, Canvas, Event, Geometry};
|
||||
use iced::widget::{column, row, slider, text};
|
||||
use iced::{Center, Color, Fill, Point, Rectangle, Renderer, Size, Theme};
|
||||
use iced::{
|
||||
Center, Color, Element, Fill, Point, Rectangle, Renderer, Size, Theme,
|
||||
};
|
||||
|
||||
use rand::Rng;
|
||||
use std::fmt::Debug;
|
||||
|
|
@ -46,7 +48,7 @@ impl SierpinskiEmulator {
|
|||
self.graph.redraw();
|
||||
}
|
||||
|
||||
fn view(&self) -> iced::Element<'_, Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
column![
|
||||
Canvas::new(&self.graph).width(Fill).height(Fill),
|
||||
row![
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ impl Slider {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let h_slider = container(
|
||||
slider(1..=100, self.value, Message::SliderChanged)
|
||||
.default(50)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ impl SolarSystem {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
canvas(&self.state).width(Fill).height(Fill).into()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ impl Stopwatch {
|
|||
Subscription::batch(vec![tick, keyboard::on_key_press(handle_hotkey)])
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
const MINUTE: u64 = 60;
|
||||
const HOUR: u64 = 60 * MINUTE;
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
12ba47a34ed415825a23f8ef377a2d52950d2f8614a66bf46c0ec28d0cf15c85
|
||||
30570747bb062e9f7730cdd58be961c84bcf4711a6983185bff6d903e8d29e9c
|
||||
|
|
@ -1 +1 @@
|
|||
78d3afadbdca4a992c662541d602850e0dec0abafa585e2a3078daa1be5998b8
|
||||
d5a086a08544f98087189bd4ece8815e5290722a07cd580b933f1bf77a040c52
|
||||
|
|
@ -1 +1 @@
|
|||
4e594cfec775d51f7f836646c59bf4a2de07252721d66ddddea69c17e9112bae
|
||||
30e523961db89a3ee97ad1eac09e727ecb3dec485faa362534a9f5ad083b32dd
|
||||
|
|
@ -1 +1 @@
|
|||
2ab665b51387c61086ae0199c29e291105bfe4583bd4c4daa652e30917f10bd6
|
||||
bce5427d5105f68e1d7fa18a34fcc551cb78c2fefd9a583ba44686331133436d
|
||||
|
|
@ -1 +1 @@
|
|||
61c9ee377b33ffa800f512877e45ad5f41fbac36f5d3f06d1b62d6af6ee9d7b2
|
||||
c8a7edbd5a8bbf559134b84253e14e65340f4ffe3e22c272b21c8438e47ffaf7
|
||||
|
|
@ -1 +1 @@
|
|||
75f2fb12c9090a256708515de01a25e78905f71e134b7cda79f4fe44b2434052
|
||||
63d646b22d3dffbb56dac2e3f345090bd26625a388dd6cc142359f2a7ac9c8df
|
||||
|
|
@ -1 +1 @@
|
|||
b4a1b42d2e21b2a493605745e6beb8e1f28cbeb01b73336e1e8d9061249a8311
|
||||
d26f55674cbd96bc3b534ffdd098a13199718ef9c5ffe8ece0882ddab714b776
|
||||
|
|
@ -1 +1 @@
|
|||
eb52921b3ee23e1814268701c935d0dff387e7eb741c50443f75a7ab902b5e44
|
||||
482c44c13d4ff3de19e71f3dddf93bbee170e54e2d353e818811069de28e18ed
|
||||
|
|
@ -1 +1 @@
|
|||
bf6c4cbd6eeed0167d28509e37292f5ce26ed1d58bb156bedb861d0619a1945b
|
||||
6738cc4fc6eb8a5d406c613a4b0f08c0e8dcd2c1a5444445eebd3888f9303841
|
||||
|
|
@ -1 +1 @@
|
|||
83726a4175900a9ef159b80925f2fa985b4ea87bff78d8bb01918fb6c40d6175
|
||||
0a918c52538fc4848aa0c68d8f2d6f4c981ed68971dd9c725f0093a39ef7f353
|
||||
|
|
@ -1 +1 @@
|
|||
54c8d44afbdd644f324cf40e744b3d7871263e44de2d9a91f6c10470c38ac3c6
|
||||
de3e1a2c21e1a86d76ca99989c73e8a2596ef627bba95d246fab8f02d56bd0af
|
||||
|
|
@ -1 +1 @@
|
|||
5713843396e2efcfc7cc8abd00343d5d66ce8b8a195212a9b75dbfeec8edf7a7
|
||||
3418ea4eb0f7786607ef02e7db4bc97309530f2f7c08f8aea15c768a13a09ca4
|
||||
|
|
@ -1 +1 @@
|
|||
f1b20ab79f8242776d9eb1ad9cff7090435aa416811c48a7c22c69b09cd8e70f
|
||||
c8474e02a9df23f123816a489c1ea7ae6cb994a0eca429592dfe6d933de1beee
|
||||
|
|
@ -1 +1 @@
|
|||
2c4be9dc1340b65cad6d15d5318017412eba1247a016379b83db379dde0214af
|
||||
02095fd09c078be02dc41e29e55de25e8a79e6ad4293aa7e430257a9016dfb3d
|
||||
|
|
@ -1 +1 @@
|
|||
2d5d6b9613ccb6a2f23142baf704288037808e7a60ee05bdc73490d8c8780064
|
||||
d82588a2aba3e7211f25b85ebb812a42dfa59137dd4b59d26f5f60d5b28e537f
|
||||
|
|
@ -1 +1 @@
|
|||
512b8dfd4687a609d202436e75ecf1a5553acc2157000e77e31c1578941b033c
|
||||
d6b73545929cc7794c1a918f069b5326ef129bed8f9ad2cd001be7d078a2b6a0
|
||||
|
|
@ -1 +1 @@
|
|||
4b3b7a2dc65307a3551227f1c5d2bb49da15d29e320ccaa160e3d9fca44c1037
|
||||
0ec7251c69755becd678b7aec398a275edf31cc077960723cd6b9364e8678548
|
||||
|
|
@ -1 +1 @@
|
|||
be1f056f0decaee8c138cd038e3e34352f02448b77c1e251796a8f0be8086913
|
||||
4a15c475d45cf8eb0ccd6727cf6e493bd8c22454610b167a632a2328308faed1
|
||||
|
|
@ -1 +1 @@
|
|||
31a7a46ed7951d69e1a29ab595d241e689cacdf66cea53dda6609db4927070e5
|
||||
49a41af93e89aab0a4e352e9cedfba3c6e18caf4267955c9d362bad40264a165
|
||||
|
|
@ -1 +1 @@
|
|||
5eab001ed1aeeea3f24fe18e4aab9b8522cb35ac1328d7ca3532dbdfdf95780f
|
||||
8fcd80d4569dafdac4b4452b8ca8ab0cdceeb755f3c83d374ccd5ed4d0e8d43d
|
||||
|
|
@ -1 +1 @@
|
|||
2fed695daa4c3da56f744832a041060704310a97d65820c97d556d297dfb271a
|
||||
c37a32784c769c046f3aa881914b121af373b8c6e175ced89304d15b626a653a
|
||||
|
|
@ -1 +1 @@
|
|||
0ecd51994f6eb37f111dc1b21cad72bb705499eb83156e9dc3ae2221ec392a42
|
||||
533d25575e8bf1111036fb082b424d0d0e60947a7da8428ab8c71e0bda01469e
|
||||
|
|
@ -65,7 +65,7 @@ impl Styling {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let choose_theme = column![
|
||||
text("Theme:"),
|
||||
pick_list(Theme::ALL, Some(&self.theme), Message::ThemeChanged)
|
||||
|
|
@ -126,7 +126,7 @@ impl Styling {
|
|||
|
||||
let content = column![
|
||||
choose_theme,
|
||||
horizontal_rule(38),
|
||||
horizontal_rule(1),
|
||||
text_input,
|
||||
row![primary, success, warning, danger]
|
||||
.spacing(10)
|
||||
|
|
@ -135,8 +135,8 @@ impl Styling {
|
|||
progress_bar(),
|
||||
row![
|
||||
scrollable,
|
||||
vertical_rule(38),
|
||||
column![checkbox, toggler].spacing(20)
|
||||
row![vertical_rule(1), column![checkbox, toggler].spacing(20)]
|
||||
.spacing(20)
|
||||
]
|
||||
.spacing(10)
|
||||
.height(100)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ impl Tiger {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let handle = svg::Handle::from_path(format!(
|
||||
"{}/resources/tiger.svg",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
use bytesize::ByteSize;
|
||||
|
||||
let content: Element<_> = match self {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ impl TheMatrix {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
canvas(self).width(Fill).height(Fill).into()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -613,12 +613,11 @@ mod toast {
|
|||
&self.viewport,
|
||||
renderer,
|
||||
)
|
||||
.max(
|
||||
cursor
|
||||
.is_over(layout.bounds())
|
||||
.then_some(mouse::Interaction::Idle)
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.max(if cursor.is_over(layout.bounds()) {
|
||||
mouse::Interaction::Idle
|
||||
} else {
|
||||
Default::default()
|
||||
})
|
||||
})
|
||||
.max()
|
||||
.unwrap_or_default()
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ impl Todos {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
match self {
|
||||
Todos::Loading => loading_message(),
|
||||
Todos::Loaded(State {
|
||||
|
|
@ -338,7 +338,7 @@ impl Task {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self, i: usize) -> Element<TaskMessage> {
|
||||
fn view(&self, i: usize) -> Element<'_, TaskMessage> {
|
||||
match &self.state {
|
||||
TaskState::Idle => {
|
||||
let checkbox = checkbox(&self.description, self.completed)
|
||||
|
|
@ -385,7 +385,10 @@ impl Task {
|
|||
}
|
||||
}
|
||||
|
||||
fn view_controls(tasks: &[Task], current_filter: Filter) -> Element<Message> {
|
||||
fn view_controls(
|
||||
tasks: &[Task],
|
||||
current_filter: Filter,
|
||||
) -> Element<'_, Message> {
|
||||
let tasks_left = tasks.iter().filter(|task| !task.completed).count();
|
||||
|
||||
let filter_button = |label, filter, current_filter| {
|
||||
|
|
@ -617,7 +620,7 @@ mod tests {
|
|||
use iced_test::selector::id;
|
||||
use iced_test::{Error, Simulator};
|
||||
|
||||
fn simulator(todos: &Todos) -> Simulator<Message> {
|
||||
fn simulator(todos: &Todos) -> Simulator<'_, Message> {
|
||||
Simulator::with_settings(
|
||||
Settings {
|
||||
fonts: vec![Todos::ICON_FONT.into()],
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ impl Tooltip {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let tooltip = tooltip(
|
||||
button("Press to change position")
|
||||
.on_press(Message::ChangePosition),
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ impl Tour {
|
|||
Screen::End => "End",
|
||||
};
|
||||
|
||||
format!("{} - Iced", screen)
|
||||
format!("{screen} - Iced")
|
||||
}
|
||||
|
||||
fn update(&mut self, event: Message) {
|
||||
|
|
@ -141,7 +141,7 @@ impl Tour {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let controls =
|
||||
row![]
|
||||
.push_maybe(self.screen.previous().is_some().then(|| {
|
||||
|
|
@ -197,7 +197,7 @@ impl Tour {
|
|||
}
|
||||
}
|
||||
|
||||
fn welcome(&self) -> Column<Message> {
|
||||
fn welcome(&self) -> Column<'_, Message> {
|
||||
Self::container("Welcome!")
|
||||
.push(
|
||||
"This is a simple tour meant to showcase a bunch of \
|
||||
|
|
@ -244,7 +244,7 @@ impl Tour {
|
|||
)
|
||||
}
|
||||
|
||||
fn slider(&self) -> Column<Message> {
|
||||
fn slider(&self) -> Column<'_, Message> {
|
||||
Self::container("Slider")
|
||||
.push(
|
||||
"A slider allows you to smoothly select a value from a range \
|
||||
|
|
@ -258,7 +258,7 @@ impl Tour {
|
|||
.push(text(self.slider.to_string()).width(Fill).align_x(Center))
|
||||
}
|
||||
|
||||
fn rows_and_columns(&self) -> Column<Message> {
|
||||
fn rows_and_columns(&self) -> Column<'_, Message> {
|
||||
let row_radio = radio(
|
||||
"Row",
|
||||
Layout::Row,
|
||||
|
|
@ -303,7 +303,7 @@ impl Tour {
|
|||
.push(spacing_section)
|
||||
}
|
||||
|
||||
fn text(&self) -> Column<Message> {
|
||||
fn text(&self) -> Column<'_, Message> {
|
||||
let size = self.text_size;
|
||||
let color = self.text_color;
|
||||
|
||||
|
|
@ -339,7 +339,7 @@ impl Tour {
|
|||
.push(color_section)
|
||||
}
|
||||
|
||||
fn radio(&self) -> Column<Message> {
|
||||
fn radio(&self) -> Column<'_, Message> {
|
||||
let question = column![
|
||||
text("Iced is written in...").size(24),
|
||||
column(
|
||||
|
|
@ -374,7 +374,7 @@ impl Tour {
|
|||
)
|
||||
}
|
||||
|
||||
fn toggler(&self) -> Column<Message> {
|
||||
fn toggler(&self) -> Column<'_, Message> {
|
||||
Self::container("Toggler")
|
||||
.push("A toggler is mostly used to enable or disable something.")
|
||||
.push(
|
||||
|
|
@ -387,7 +387,7 @@ impl Tour {
|
|||
)
|
||||
}
|
||||
|
||||
fn image(&self) -> Column<Message> {
|
||||
fn image(&self) -> Column<'_, Message> {
|
||||
let width = self.image_width;
|
||||
let filter_method = self.image_filter_method;
|
||||
|
||||
|
|
@ -406,7 +406,7 @@ impl Tour {
|
|||
.align_x(Center)
|
||||
}
|
||||
|
||||
fn scrollable(&self) -> Column<Message> {
|
||||
fn scrollable(&self) -> Column<'_, Message> {
|
||||
Self::container("Scrollable")
|
||||
.push(
|
||||
"Iced supports scrollable content. Try it out! Find the \
|
||||
|
|
@ -428,7 +428,7 @@ impl Tour {
|
|||
.push(text("You made it!").width(Fill).size(50).align_x(Center))
|
||||
}
|
||||
|
||||
fn text_input(&self) -> Column<Message> {
|
||||
fn text_input(&self) -> Column<'_, Message> {
|
||||
let value = &self.input_value;
|
||||
let is_secure = self.input_is_secure;
|
||||
let is_showing_icon = self.input_is_showing_icon;
|
||||
|
|
@ -474,7 +474,7 @@ impl Tour {
|
|||
)
|
||||
}
|
||||
|
||||
fn debugger(&self) -> Column<Message> {
|
||||
fn debugger(&self) -> Column<'_, Message> {
|
||||
Self::container("Debugger")
|
||||
.push(
|
||||
"You can ask Iced to visually explain the layouting of the \
|
||||
|
|
@ -491,7 +491,7 @@ impl Tour {
|
|||
.push("Feel free to go back and take a look.")
|
||||
}
|
||||
|
||||
fn end(&self) -> Column<Message> {
|
||||
fn end(&self) -> Column<'_, Message> {
|
||||
Self::container("You reached the end!")
|
||||
.push("This tour will be updated as more features are added.")
|
||||
.push("Make sure to keep an eye on it!")
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ impl App {
|
|||
event::listen_url().map(Message::UrlReceived)
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let content = match &self.url {
|
||||
Some(url) => text(url),
|
||||
None => text("No URL received yet!"),
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ impl VectorialText {
|
|||
self.state.cache.clear();
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let slider_with_label = |label, range, value, message: fn(f32) -> _| {
|
||||
column![
|
||||
row![text(label), horizontal_space(), text!("{:.2}", value)],
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let data_row = |label, value, color| {
|
||||
row![
|
||||
text(label),
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ impl WebSocket {
|
|||
])
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let message_log: Element<_> = if self.messages.is_empty() {
|
||||
center(
|
||||
text("Your messages will appear here...")
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ pub enum Action<T> {
|
|||
/// Run a system action.
|
||||
System(system::Action),
|
||||
|
||||
/// Recreate all user interfaces and redraw all windows.
|
||||
Reload,
|
||||
|
||||
/// Exits the runtime.
|
||||
///
|
||||
/// This will normally close any application windows and
|
||||
|
|
@ -79,6 +82,7 @@ impl<T> Action<T> {
|
|||
Action::Clipboard(action) => Err(Action::Clipboard(action)),
|
||||
Action::Window(action) => Err(Action::Window(action)),
|
||||
Action::System(action) => Err(Action::System(action)),
|
||||
Action::Reload => Err(Action::Reload),
|
||||
Action::Exit => Err(Action::Exit),
|
||||
}
|
||||
}
|
||||
|
|
@ -102,6 +106,7 @@ where
|
|||
}
|
||||
Action::Window(_) => write!(f, "Action::Window"),
|
||||
Action::System(action) => write!(f, "Action::System({action:?})"),
|
||||
Action::Reload => write!(f, "Action::Reload"),
|
||||
Action::Exit => write!(f, "Action::Exit"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ pub use sipper::{Never, Sender, Sipper, Straw, sipper, stream};
|
|||
/// A set of concurrent actions to be performed by the iced runtime.
|
||||
///
|
||||
/// A [`Task`] _may_ produce a bunch of values of type `T`.
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[must_use = "`Task` must be returned to the runtime to take effect; normally in your `update` or `new` functions."]
|
||||
pub struct Task<T> {
|
||||
stream: Option<BoxStream<Action<T>>>,
|
||||
|
|
@ -278,6 +277,14 @@ impl<T> Task<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> std::fmt::Debug for Task<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct(&format!("Task<{}>", std::any::type_name::<T>()))
|
||||
.field("units", &self.units)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle to a [`Task`] that can be used for aborting it.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Handle {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ use crate::{
|
|||
Element, Executor, Font, Result, Settings, Size, Subscription, Task,
|
||||
};
|
||||
|
||||
use iced_debug as debug;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub mod timed;
|
||||
|
|
@ -128,7 +130,7 @@ where
|
|||
state: &mut Self::State,
|
||||
message: Self::Message,
|
||||
) -> Task<Self::Message> {
|
||||
self.update.update(state, message)
|
||||
debug::hot(|| self.update.update(state, message))
|
||||
}
|
||||
|
||||
fn view<'a>(
|
||||
|
|
@ -136,7 +138,7 @@ where
|
|||
state: &'a Self::State,
|
||||
_window: window::Id,
|
||||
) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
|
||||
self.view.view(state)
|
||||
debug::hot(|| self.view.view(state))
|
||||
}
|
||||
|
||||
fn settings(&self) -> Settings {
|
||||
|
|
@ -342,7 +344,7 @@ impl<P: Program> Application<P> {
|
|||
> {
|
||||
Application {
|
||||
raw: program::with_title(self.raw, move |state, _window| {
|
||||
title.title(state)
|
||||
debug::hot(|| title.title(state))
|
||||
}),
|
||||
settings: self.settings,
|
||||
window: self.window,
|
||||
|
|
@ -359,7 +361,9 @@ impl<P: Program> Application<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Application {
|
||||
raw: program::with_subscription(self.raw, f),
|
||||
raw: program::with_subscription(self.raw, move |state| {
|
||||
debug::hot(|| f(state))
|
||||
}),
|
||||
settings: self.settings,
|
||||
window: self.window,
|
||||
#[cfg(feature = "test")]
|
||||
|
|
@ -375,7 +379,9 @@ impl<P: Program> Application<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Application {
|
||||
raw: program::with_theme(self.raw, move |state, _window| f(state)),
|
||||
raw: program::with_theme(self.raw, move |state, _window| {
|
||||
debug::hot(|| f(state))
|
||||
}),
|
||||
settings: self.settings,
|
||||
window: self.window,
|
||||
#[cfg(feature = "test")]
|
||||
|
|
@ -391,7 +397,9 @@ impl<P: Program> Application<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Application {
|
||||
raw: program::with_style(self.raw, f),
|
||||
raw: program::with_style(self.raw, move |state, theme| {
|
||||
debug::hot(|| f(state, theme))
|
||||
}),
|
||||
settings: self.settings,
|
||||
window: self.window,
|
||||
#[cfg(feature = "test")]
|
||||
|
|
@ -408,7 +416,7 @@ impl<P: Program> Application<P> {
|
|||
> {
|
||||
Application {
|
||||
raw: program::with_scale_factor(self.raw, move |state, _window| {
|
||||
f(state)
|
||||
debug::hot(|| f(state))
|
||||
}),
|
||||
settings: self.settings,
|
||||
window: self.window,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use crate::time::Instant;
|
|||
use crate::window;
|
||||
use crate::{Element, Program, Settings, Subscription, Task};
|
||||
|
||||
use iced_debug as debug;
|
||||
|
||||
/// Creates an [`Application`] with an `update` function that also
|
||||
/// takes the [`Instant`] of each `Message`.
|
||||
///
|
||||
|
|
@ -101,10 +103,12 @@ where
|
|||
state: &mut Self::State,
|
||||
(message, now): Self::Message,
|
||||
) -> Task<Self::Message> {
|
||||
self.update
|
||||
.update(state, message, now)
|
||||
.into()
|
||||
.map(|message| (message, Instant::now()))
|
||||
debug::hot(move || {
|
||||
self.update
|
||||
.update(state, message, now)
|
||||
.into()
|
||||
.map(|message| (message, Instant::now()))
|
||||
})
|
||||
}
|
||||
|
||||
fn view<'a>(
|
||||
|
|
@ -112,16 +116,21 @@ where
|
|||
state: &'a Self::State,
|
||||
_window: window::Id,
|
||||
) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
|
||||
self.view
|
||||
.view(state)
|
||||
.map(|message| (message, Instant::now()))
|
||||
debug::hot(|| {
|
||||
self.view
|
||||
.view(state)
|
||||
.map(|message| (message, Instant::now()))
|
||||
})
|
||||
}
|
||||
|
||||
fn subscription(
|
||||
&self,
|
||||
state: &Self::State,
|
||||
) -> self::Subscription<Self::Message> {
|
||||
(self.subscription)(state).map(|message| (message, Instant::now()))
|
||||
debug::hot(|| {
|
||||
(self.subscription)(state)
|
||||
.map(|message| (message, Instant::now()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use crate::theme;
|
|||
use crate::window;
|
||||
use crate::{Element, Executor, Font, Result, Settings, Subscription, Task};
|
||||
|
||||
use iced_debug as debug;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// Creates an iced [`Daemon`] given its boot, update, and view logic.
|
||||
|
|
@ -76,7 +78,7 @@ where
|
|||
state: &mut Self::State,
|
||||
message: Self::Message,
|
||||
) -> Task<Self::Message> {
|
||||
self.update.update(state, message)
|
||||
debug::hot(|| self.update.update(state, message))
|
||||
}
|
||||
|
||||
fn view<'a>(
|
||||
|
|
@ -84,7 +86,7 @@ where
|
|||
state: &'a Self::State,
|
||||
window: window::Id,
|
||||
) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
|
||||
self.view.view(state, window)
|
||||
debug::hot(|| self.view.view(state, window))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -182,7 +184,7 @@ impl<P: Program> Daemon<P> {
|
|||
> {
|
||||
Daemon {
|
||||
raw: program::with_title(self.raw, move |state, window| {
|
||||
title.title(state, window)
|
||||
debug::hot(|| title.title(state, window))
|
||||
}),
|
||||
settings: self.settings,
|
||||
}
|
||||
|
|
@ -196,7 +198,9 @@ impl<P: Program> Daemon<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Daemon {
|
||||
raw: program::with_subscription(self.raw, f),
|
||||
raw: program::with_subscription(self.raw, move |state| {
|
||||
debug::hot(|| f(state))
|
||||
}),
|
||||
settings: self.settings,
|
||||
}
|
||||
}
|
||||
|
|
@ -209,7 +213,9 @@ impl<P: Program> Daemon<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Daemon {
|
||||
raw: program::with_theme(self.raw, f),
|
||||
raw: program::with_theme(self.raw, move |state, window| {
|
||||
debug::hot(|| f(state, window))
|
||||
}),
|
||||
settings: self.settings,
|
||||
}
|
||||
}
|
||||
|
|
@ -222,7 +228,9 @@ impl<P: Program> Daemon<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Daemon {
|
||||
raw: program::with_style(self.raw, f),
|
||||
raw: program::with_style(self.raw, move |state, theme| {
|
||||
debug::hot(|| f(state, theme))
|
||||
}),
|
||||
settings: self.settings,
|
||||
}
|
||||
}
|
||||
|
|
@ -235,7 +243,9 @@ impl<P: Program> Daemon<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Daemon {
|
||||
raw: program::with_scale_factor(self.raw, f),
|
||||
raw: program::with_scale_factor(self.raw, move |state, window| {
|
||||
debug::hot(|| f(state, window))
|
||||
}),
|
||||
settings: self.settings,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
26
src/lib.rs
26
src/lib.rs
|
|
@ -34,7 +34,7 @@
|
|||
//! iced::run(update, view)
|
||||
//! }
|
||||
//! # fn update(state: &mut (), message: ()) {}
|
||||
//! # fn view(state: &()) -> iced::Element<()> { iced::widget::text("").into() }
|
||||
//! # fn view(state: &()) -> iced::Element<'_, ()> { iced::widget::text("").into() }
|
||||
//! ```
|
||||
//!
|
||||
//! Define an `update` function to __change__ your state:
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
//! use iced::widget::{button, text};
|
||||
//! use iced::Element;
|
||||
//!
|
||||
//! fn view(counter: &u64) -> Element<Message> {
|
||||
//! fn view(counter: &u64) -> Element<'_, Message> {
|
||||
//! button(text(counter)).on_press(Message::Increment).into()
|
||||
//! }
|
||||
//! # #[derive(Clone)]
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn view(counter: &Counter) -> Element<Message> {
|
||||
//! fn view(counter: &Counter) -> Element<'_, Message> {
|
||||
//! button(text(counter.value)).on_press(Message::Increment).into()
|
||||
//! }
|
||||
//! ```
|
||||
|
|
@ -115,7 +115,7 @@
|
|||
//! use iced::widget::{button, column, text};
|
||||
//! use iced::Element;
|
||||
//!
|
||||
//! fn view(counter: &Counter) -> Element<Message> {
|
||||
//! fn view(counter: &Counter) -> Element<'_, Message> {
|
||||
//! column![
|
||||
//! text(counter.value).size(20),
|
||||
//! button("Increment").on_press(Message::Increment),
|
||||
|
|
@ -144,7 +144,7 @@
|
|||
//! use iced::widget::{column, container, row};
|
||||
//! use iced::{Fill, Element};
|
||||
//!
|
||||
//! fn view(state: &State) -> Element<Message> {
|
||||
//! fn view(state: &State) -> Element<'_, Message> {
|
||||
//! container(
|
||||
//! column![
|
||||
//! "Top",
|
||||
|
|
@ -187,7 +187,7 @@
|
|||
//! use iced::widget::container;
|
||||
//! use iced::Element;
|
||||
//!
|
||||
//! fn view(state: &State) -> Element<Message> {
|
||||
//! fn view(state: &State) -> Element<'_, Message> {
|
||||
//! container("I am 300px tall!").height(300).into()
|
||||
//! }
|
||||
//! ```
|
||||
|
|
@ -216,7 +216,7 @@
|
|||
//! Theme::TokyoNight
|
||||
//! }
|
||||
//! # fn update(state: &mut State, message: ()) {}
|
||||
//! # fn view(state: &State) -> iced::Element<()> { iced::widget::text("").into() }
|
||||
//! # fn view(state: &State) -> iced::Element<'_, ()> { iced::widget::text("").into() }
|
||||
//! ```
|
||||
//!
|
||||
//! The `theme` function takes the current state of the application, allowing the
|
||||
|
|
@ -237,7 +237,7 @@
|
|||
//! use iced::widget::container;
|
||||
//! use iced::Element;
|
||||
//!
|
||||
//! fn view(state: &State) -> Element<Message> {
|
||||
//! fn view(state: &State) -> Element<'_, Message> {
|
||||
//! container("I am a rounded box!").style(container::rounded_box).into()
|
||||
//! }
|
||||
//! ```
|
||||
|
|
@ -252,7 +252,7 @@
|
|||
//! use iced::widget::button;
|
||||
//! use iced::{Element, Theme};
|
||||
//!
|
||||
//! fn view(state: &State) -> Element<Message> {
|
||||
//! fn view(state: &State) -> Element<'_, Message> {
|
||||
//! button("I am a styled button!").style(|theme: &Theme, status| {
|
||||
//! let palette = theme.extended_palette();
|
||||
//!
|
||||
|
|
@ -359,7 +359,7 @@
|
|||
//! }
|
||||
//! # fn new() -> State { State }
|
||||
//! # fn update(state: &mut State, message: Message) {}
|
||||
//! # fn view(state: &State) -> iced::Element<Message> { iced::widget::text("").into() }
|
||||
//! # fn view(state: &State) -> iced::Element<'_, Message> { iced::widget::text("").into() }
|
||||
//! ```
|
||||
//!
|
||||
//! A [`Subscription`] is [a _declarative_ builder of streams](Subscription#the-lifetime-of-a-subscription)
|
||||
|
|
@ -452,7 +452,7 @@
|
|||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn view(state: &State) -> Element<Message> {
|
||||
//! fn view(state: &State) -> Element<'_, Message> {
|
||||
//! match &state.screen {
|
||||
//! Screen::Contacts(contacts) => contacts.view().map(Message::Contacts),
|
||||
//! Screen::Conversation(conversation) => conversation.view().map(Message::Conversation),
|
||||
|
|
@ -659,8 +659,8 @@ pub type Element<
|
|||
/// The result of running an iced program.
|
||||
pub type Result = std::result::Result<(), Error>;
|
||||
|
||||
/// Runs a basic iced application with default [`Settings`] given its title,
|
||||
/// update, and view logic.
|
||||
/// Runs a basic iced application with default [`Settings`] given its update
|
||||
/// and view logic.
|
||||
///
|
||||
/// This is equivalent to chaining [`application()`] with [`Application::run`].
|
||||
///
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@ impl<P: Program + 'static> Emulator<P> {
|
|||
Action::Exit => {
|
||||
// TODO
|
||||
}
|
||||
Action::Reload => {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -626,10 +626,10 @@ fn prepare(
|
|||
scale: transformation.scale_factor()
|
||||
* layer_transformation.scale_factor(),
|
||||
bounds: cryoglyph::TextBounds {
|
||||
left: clip_bounds.x as i32,
|
||||
top: clip_bounds.y as i32,
|
||||
right: (clip_bounds.x + clip_bounds.width) as i32,
|
||||
bottom: (clip_bounds.y + clip_bounds.height) as i32,
|
||||
left: clip_bounds.x.round() as i32,
|
||||
top: clip_bounds.y.round() as i32,
|
||||
right: (clip_bounds.x + clip_bounds.width).round() as i32,
|
||||
bottom: (clip_bounds.y + clip_bounds.height).round() as i32,
|
||||
},
|
||||
default_color: to_color(color),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ impl Compositor {
|
|||
let adapter = instance
|
||||
.request_adapter(&adapter_options)
|
||||
.await
|
||||
.ok_or(Error::NoAdapterFound(format!("{:?}", adapter_options)))?;
|
||||
.ok_or(Error::NoAdapterFound(format!("{adapter_options:?}")))?;
|
||||
|
||||
log::info!("Selected: {:#?}", adapter.get_info());
|
||||
|
||||
|
|
|
|||
|
|
@ -400,9 +400,9 @@ where
|
|||
Renderer: core::Renderer + 'a,
|
||||
{
|
||||
fn from(
|
||||
column: Container<'a, Message, Theme, Renderer>,
|
||||
container: Container<'a, Message, Theme, Renderer>,
|
||||
) -> Element<'a, Message, Theme, Renderer> {
|
||||
Element::new(column)
|
||||
Element::new(container)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,10 @@ use crate::core::theme;
|
|||
use crate::core::{
|
||||
self, Color, Element, Length, Padding, Pixels, Theme, color,
|
||||
};
|
||||
use crate::{column, container, rich_text, row, scrollable, span, text};
|
||||
use crate::{
|
||||
column, container, horizontal_rule, rich_text, row, rule, scrollable, span,
|
||||
text, vertical_rule,
|
||||
};
|
||||
|
||||
use std::borrow::BorrowMut;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
|
@ -208,6 +211,10 @@ pub enum Item {
|
|||
/// The alternative text of the image.
|
||||
alt: Text,
|
||||
},
|
||||
/// A quote.
|
||||
Quote(Vec<Item>),
|
||||
/// A horizontal separator.
|
||||
Rule,
|
||||
}
|
||||
|
||||
/// A bunch of parsed Markdown text.
|
||||
|
|
@ -339,8 +346,8 @@ impl Span {
|
|||
///
|
||||
/// fn view(&self) -> Element<'_, Message> {
|
||||
/// markdown::view(&self.markdown, Theme::TokyoNight)
|
||||
/// .map(Message::LinkClicked)
|
||||
/// .into()
|
||||
/// .map(Message::LinkClicked)
|
||||
/// .into()
|
||||
/// }
|
||||
///
|
||||
/// fn update(state: &mut State, message: Message) {
|
||||
|
|
@ -454,6 +461,7 @@ fn parse_with<'a>(
|
|||
) -> impl Iterator<Item = (Item, &'a str, HashSet<String>)> + 'a {
|
||||
enum Scope {
|
||||
List(List),
|
||||
Quote(Vec<Item>),
|
||||
}
|
||||
|
||||
struct List {
|
||||
|
|
@ -524,6 +532,9 @@ fn parse_with<'a>(
|
|||
Scope::List(list) => {
|
||||
list.items.last_mut().expect("item context").push(item);
|
||||
}
|
||||
Scope::Quote(items) => {
|
||||
items.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
|
|
@ -605,6 +616,22 @@ fn parse_with<'a>(
|
|||
|
||||
None
|
||||
}
|
||||
pulldown_cmark::Tag::BlockQuote(_kind) if !metadata && !table => {
|
||||
let prev = if spans.is_empty() {
|
||||
None
|
||||
} else {
|
||||
produce(
|
||||
state.borrow_mut(),
|
||||
&mut stack,
|
||||
Item::Paragraph(Text::new(spans.drain(..).collect())),
|
||||
source,
|
||||
)
|
||||
};
|
||||
|
||||
stack.push(Scope::Quote(Vec::new()));
|
||||
|
||||
prev
|
||||
}
|
||||
pulldown_cmark::Tag::CodeBlock(
|
||||
pulldown_cmark::CodeBlockKind::Fenced(language),
|
||||
) if !metadata && !table => {
|
||||
|
|
@ -703,7 +730,9 @@ fn parse_with<'a>(
|
|||
pulldown_cmark::TagEnd::List(_) if !metadata && !table => {
|
||||
let scope = stack.pop()?;
|
||||
|
||||
let Scope::List(list) = scope;
|
||||
let Scope::List(list) = scope else {
|
||||
return None;
|
||||
};
|
||||
|
||||
produce(
|
||||
state.borrow_mut(),
|
||||
|
|
@ -715,6 +744,22 @@ fn parse_with<'a>(
|
|||
source,
|
||||
)
|
||||
}
|
||||
pulldown_cmark::TagEnd::BlockQuote(_kind)
|
||||
if !metadata && !table =>
|
||||
{
|
||||
let scope = stack.pop()?;
|
||||
|
||||
let Scope::Quote(quote) = scope else {
|
||||
return None;
|
||||
};
|
||||
|
||||
produce(
|
||||
state.borrow_mut(),
|
||||
&mut stack,
|
||||
Item::Quote(quote),
|
||||
source,
|
||||
)
|
||||
}
|
||||
pulldown_cmark::TagEnd::Image if !metadata && !table => {
|
||||
let (url, title) = image.take()?;
|
||||
let alt = Text::new(spans.drain(..).collect());
|
||||
|
|
@ -834,6 +879,9 @@ fn parse_with<'a>(
|
|||
});
|
||||
None
|
||||
}
|
||||
pulldown_cmark::Event::Rule => {
|
||||
produce(state.borrow_mut(), &mut stack, Item::Rule, source)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
|
@ -1063,6 +1111,8 @@ where
|
|||
start: Some(start),
|
||||
items,
|
||||
} => viewer.ordered_list(settings, *start, items),
|
||||
Item::Quote(quote) => viewer.quote(settings, quote),
|
||||
Item::Rule => viewer.rule(settings),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1226,7 +1276,44 @@ where
|
|||
.into()
|
||||
}
|
||||
|
||||
/// A view strategy to display a Markdown [`Item`].j
|
||||
/// Displays a quote using the default look.
|
||||
pub fn quote<'a, Message, Theme, Renderer>(
|
||||
viewer: &impl Viewer<'a, Message, Theme, Renderer>,
|
||||
settings: Settings,
|
||||
contents: &'a [Item],
|
||||
) -> Element<'a, Message, Theme, Renderer>
|
||||
where
|
||||
Message: 'a,
|
||||
Theme: Catalog + 'a,
|
||||
Renderer: core::text::Renderer<Font = Font> + 'a,
|
||||
{
|
||||
row![
|
||||
vertical_rule(4),
|
||||
column(
|
||||
contents
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, content)| item(viewer, settings, content, i)),
|
||||
)
|
||||
.spacing(settings.spacing.0),
|
||||
]
|
||||
.height(Length::Shrink)
|
||||
.spacing(settings.spacing.0)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Displays a rule using the default look.
|
||||
pub fn rule<'a, Message, Theme, Renderer>()
|
||||
-> Element<'a, Message, Theme, Renderer>
|
||||
where
|
||||
Message: 'a,
|
||||
Theme: Catalog + 'a,
|
||||
Renderer: core::text::Renderer<Font = Font> + 'a,
|
||||
{
|
||||
horizontal_rule(2).into()
|
||||
}
|
||||
|
||||
/// A view strategy to display a Markdown [`Item`].
|
||||
pub trait Viewer<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>
|
||||
where
|
||||
Self: Sized + 'a,
|
||||
|
|
@ -1321,6 +1408,27 @@ where
|
|||
) -> Element<'a, Message, Theme, Renderer> {
|
||||
ordered_list(self, settings, start, items)
|
||||
}
|
||||
|
||||
/// Displays a quote.
|
||||
///
|
||||
/// By default, it calls [`quote`].
|
||||
fn quote(
|
||||
&self,
|
||||
settings: Settings,
|
||||
contents: &'a [Item],
|
||||
) -> Element<'a, Message, Theme, Renderer> {
|
||||
quote(self, settings, contents)
|
||||
}
|
||||
|
||||
/// Displays a rule.
|
||||
///
|
||||
/// By default, it calls [`rule`](self::rule()).
|
||||
fn rule(
|
||||
&self,
|
||||
_settings: Settings,
|
||||
) -> Element<'a, Message, Theme, Renderer> {
|
||||
rule()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
@ -1338,7 +1446,7 @@ where
|
|||
|
||||
/// The theme catalog of Markdown items.
|
||||
pub trait Catalog:
|
||||
container::Catalog + scrollable::Catalog + text::Catalog
|
||||
container::Catalog + scrollable::Catalog + rule::Catalog + text::Catalog
|
||||
{
|
||||
/// The styling class of a Markdown code block.
|
||||
fn code_block<'a>() -> <Self as container::Catalog>::Class<'a>;
|
||||
|
|
|
|||
|
|
@ -297,11 +297,11 @@ where
|
|||
}
|
||||
|
||||
fn drag_enabled(&self) -> bool {
|
||||
self.internal
|
||||
.maximized()
|
||||
.is_none()
|
||||
.then(|| self.on_drag.is_some())
|
||||
.unwrap_or_default()
|
||||
if self.internal.maximized().is_none() {
|
||||
self.on_drag.is_some()
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn grid_interaction(
|
||||
|
|
|
|||
|
|
@ -134,9 +134,7 @@ where
|
|||
let style = theme.style(&self.class);
|
||||
|
||||
let bounds = if self.is_horizontal {
|
||||
let line_y = (bounds.y + (bounds.height / 2.0)
|
||||
- (style.width as f32 / 2.0))
|
||||
.round();
|
||||
let line_y = (bounds.y + (bounds.height / 2.0)).round();
|
||||
|
||||
let (offset, line_width) = style.fill_mode.fill(bounds.width);
|
||||
let line_x = bounds.x + offset;
|
||||
|
|
@ -145,12 +143,10 @@ where
|
|||
x: line_x,
|
||||
y: line_y,
|
||||
width: line_width,
|
||||
height: style.width as f32,
|
||||
height: bounds.height,
|
||||
}
|
||||
} else {
|
||||
let line_x = (bounds.x + (bounds.width / 2.0)
|
||||
- (style.width as f32 / 2.0))
|
||||
.round();
|
||||
let line_x = (bounds.x + (bounds.width / 2.0)).round();
|
||||
|
||||
let (offset, line_height) = style.fill_mode.fill(bounds.height);
|
||||
let line_y = bounds.y + offset;
|
||||
|
|
@ -158,7 +154,7 @@ where
|
|||
Rectangle {
|
||||
x: line_x,
|
||||
y: line_y,
|
||||
width: style.width as f32,
|
||||
width: bounds.width,
|
||||
height: line_height,
|
||||
}
|
||||
};
|
||||
|
|
@ -167,6 +163,7 @@ where
|
|||
renderer::Quad {
|
||||
bounds,
|
||||
border: border::rounded(style.radius),
|
||||
snap: style.snap,
|
||||
..renderer::Quad::default()
|
||||
},
|
||||
style.color,
|
||||
|
|
@ -191,12 +188,12 @@ where
|
|||
pub struct Style {
|
||||
/// The color of the rule.
|
||||
pub color: Color,
|
||||
/// The width (thickness) of the rule line.
|
||||
pub width: u16,
|
||||
/// The radius of the line corners.
|
||||
pub radius: border::Radius,
|
||||
/// The [`FillMode`] of the rule.
|
||||
pub fill_mode: FillMode,
|
||||
/// Whether the rule should be snapped to the pixel grid.
|
||||
pub snap: bool,
|
||||
}
|
||||
|
||||
/// The fill mode of a rule.
|
||||
|
|
@ -298,8 +295,8 @@ pub fn default(theme: &Theme) -> Style {
|
|||
|
||||
Style {
|
||||
color: palette.background.strong.color,
|
||||
width: 1,
|
||||
radius: 0.0.into(),
|
||||
fill_mode: FillMode::Full,
|
||||
snap: true,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ where
|
|||
},
|
||||
|limits| {
|
||||
let child_limits = layout::Limits::new(
|
||||
Size::new(limits.min().width, limits.min().height),
|
||||
limits.min(),
|
||||
Size::new(
|
||||
if self.direction.horizontal().is_some() {
|
||||
f32::INFINITY
|
||||
|
|
|
|||
|
|
@ -85,6 +85,15 @@ where
|
|||
|
||||
let (proxy, worker) = Proxy::new(event_loop.create_proxy());
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
{
|
||||
let proxy = proxy.clone();
|
||||
|
||||
debug::on_hotpatch(move || {
|
||||
proxy.send_action(Action::Reload);
|
||||
});
|
||||
}
|
||||
|
||||
let mut runtime = {
|
||||
let executor =
|
||||
P::Executor::new().map_err(Error::ExecutorCreationFailed)?;
|
||||
|
|
@ -527,7 +536,7 @@ async fn run_instance<P>(
|
|||
|
||||
let create_compositor = {
|
||||
let window = window.clone();
|
||||
let mut proxy = proxy.clone();
|
||||
let proxy = proxy.clone();
|
||||
let default_fonts = default_fonts.clone();
|
||||
|
||||
async move {
|
||||
|
|
@ -801,7 +810,7 @@ async fn run_instance<P>(
|
|||
Err(error) => match error {
|
||||
// This is an unrecoverable error.
|
||||
compositor::SurfaceError::OutOfMemory => {
|
||||
panic!("{:?}", error);
|
||||
panic!("{error:?}");
|
||||
}
|
||||
_ => {
|
||||
present_span.finish();
|
||||
|
|
@ -1075,9 +1084,9 @@ fn update<P: Program, E: Executor>(
|
|||
runtime.track(recipes);
|
||||
}
|
||||
|
||||
fn run_action<P, C>(
|
||||
fn run_action<'a, P, C>(
|
||||
action: Action<P::Message>,
|
||||
program: &program::Instance<P>,
|
||||
program: &'a program::Instance<P>,
|
||||
compositor: &mut Option<C>,
|
||||
events: &mut Vec<(window::Id, core::Event)>,
|
||||
messages: &mut Vec<P::Message>,
|
||||
|
|
@ -1085,7 +1094,7 @@ fn run_action<P, C>(
|
|||
control_sender: &mut mpsc::UnboundedSender<Control>,
|
||||
interfaces: &mut FxHashMap<
|
||||
window::Id,
|
||||
UserInterface<'_, P::Message, P::Theme, P::Renderer>,
|
||||
UserInterface<'a, P::Message, P::Theme, P::Renderer>,
|
||||
>,
|
||||
window_manager: &mut WindowManager<P, C>,
|
||||
ui_caches: &mut FxHashMap<window::Id, user_interface::Cache>,
|
||||
|
|
@ -1437,6 +1446,29 @@ fn run_action<P, C>(
|
|||
let _ = channel.send(Ok(()));
|
||||
}
|
||||
}
|
||||
Action::Reload => {
|
||||
for (id, window) in window_manager.iter_mut() {
|
||||
let Some(ui) = interfaces.remove(&id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let cache = ui.into_cache();
|
||||
let size = window.size();
|
||||
|
||||
let _ = interfaces.insert(
|
||||
id,
|
||||
build_user_interface(
|
||||
program,
|
||||
cache,
|
||||
&mut window.renderer,
|
||||
size,
|
||||
id,
|
||||
),
|
||||
);
|
||||
|
||||
window.raw.request_redraw();
|
||||
}
|
||||
}
|
||||
Action::Exit => {
|
||||
control_sender
|
||||
.start_send(Control::Exit)
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ impl<T: 'static> Proxy<T> {
|
|||
///
|
||||
/// Note: This skips the backpressure mechanism with an unbounded
|
||||
/// channel. Use sparingly!
|
||||
pub fn send(&mut self, value: T)
|
||||
pub fn send(&self, value: T)
|
||||
where
|
||||
T: std::fmt::Debug,
|
||||
{
|
||||
|
|
@ -88,13 +88,11 @@ impl<T: 'static> Proxy<T> {
|
|||
///
|
||||
/// Note: This skips the backpressure mechanism with an unbounded
|
||||
/// channel. Use sparingly!
|
||||
pub fn send_action(&mut self, action: Action<T>)
|
||||
pub fn send_action(&self, action: Action<T>)
|
||||
where
|
||||
T: std::fmt::Debug,
|
||||
{
|
||||
self.raw
|
||||
.send_event(action)
|
||||
.expect("Send message to event loop");
|
||||
let _ = self.raw.send_event(action);
|
||||
}
|
||||
|
||||
/// Frees an amount of slots for additional messages to be queued in
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue