Merge remote-tracking branch 'origin/master' into feat/multi-window-support
# Conflicts: # examples/events/src/main.rs # glutin/src/application.rs # native/src/window.rs # winit/src/window.rs
This commit is contained in:
commit
70d487ba20
57 changed files with 815 additions and 446 deletions
2
.github/ISSUE_TEMPLATE/BUG-REPORT.yml
vendored
2
.github/ISSUE_TEMPLATE/BUG-REPORT.yml
vendored
|
|
@ -63,7 +63,7 @@ body:
|
||||||
If you are using an older release, please upgrade to the latest one before filing an issue.
|
If you are using an older release, please upgrade to the latest one before filing an issue.
|
||||||
options:
|
options:
|
||||||
- master
|
- master
|
||||||
- 0.6
|
- 0.7
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
|
|
||||||
46
CHANGELOG.md
46
CHANGELOG.md
|
|
@ -6,6 +6,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.7.0] - 2023-01-14
|
||||||
|
### Added
|
||||||
|
- Widget-driven animations. [#1647](https://github.com/iced-rs/iced/pull/1647)
|
||||||
|
- Multidirectional scrolling support for `Scrollable`. [#1550](https://github.com/iced-rs/iced/pull/1550)
|
||||||
|
- `VerticalSlider` widget. [#1596](https://github.com/iced-rs/iced/pull/1596)
|
||||||
|
- `Shift+Click` text selection support in `TextInput`. [#1622](https://github.com/iced-rs/iced/pull/1622)
|
||||||
|
- Profiling support with the `chrome-trace` feature. [#1565](https://github.com/iced-rs/iced/pull/1565)
|
||||||
|
- Customization of the handle of a `PickList`. [#1562](https://github.com/iced-rs/iced/pull/1562)
|
||||||
|
- `window` action to request user attention. [#1584](https://github.com/iced-rs/iced/pull/1584)
|
||||||
|
- `window` action to gain focus. [#1585](https://github.com/iced-rs/iced/pull/1585)
|
||||||
|
- `window` action to toggle decorations. [#1588](https://github.com/iced-rs/iced/pull/1588)
|
||||||
|
- `Copy` implementation for `gradient::Location`. [#1636](https://github.com/iced-rs/iced/pull/1636)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Replaced `Application::should_exit` with a `window::close` action. [#1606](https://github.com/iced-rs/iced/pull/1606)
|
||||||
|
- Made `focusable::Count` fields public. [#1635](https://github.com/iced-rs/iced/pull/1635)
|
||||||
|
- Added `Dependency` argument to the closure of `Lazy`. [#1646](https://github.com/iced-rs/iced/pull/1646)
|
||||||
|
- Switched arguments order of `Toggler::new` for consistency. [#1616](https://github.com/iced-rs/iced/pull/1616)
|
||||||
|
- Switched arguments order of `Checkbox::new` for consistency. [#1633](https://github.com/iced-rs/iced/pull/1633)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Compilation error in `iced_glow` when the `image` feature is enabled but `svg` isn't. [#1593](https://github.com/iced-rs/iced/pull/1593)
|
||||||
|
- Widget operations for `Responsive` widget. [#1615](https://github.com/iced-rs/iced/pull/1615)
|
||||||
|
- Overlay placement for `Responsive`. [#1638](https://github.com/iced-rs/iced/pull/1638)
|
||||||
|
- `overlay` implementation for `Lazy`. [#1644](https://github.com/iced-rs/iced/pull/1644)
|
||||||
|
- Minor typo in documentation. [#1624](https://github.com/iced-rs/iced/pull/1624)
|
||||||
|
- Links in documentation. [#1634](https://github.com/iced-rs/iced/pull/1634)
|
||||||
|
- Missing comment in documentation. [#1648](https://github.com/iced-rs/iced/pull/1648)
|
||||||
|
|
||||||
|
Many thanks to...
|
||||||
|
|
||||||
|
- @13r0ck
|
||||||
|
- @Araxeus
|
||||||
|
- @ben-wallis
|
||||||
|
- @bungoboingo
|
||||||
|
- @casperstorm
|
||||||
|
- @nicksenger
|
||||||
|
- @Night-Hunter-NF
|
||||||
|
- @rpitasky
|
||||||
|
- @rs017991
|
||||||
|
- @tarkah
|
||||||
|
- @wiktor-k
|
||||||
|
|
||||||
## [0.6.0] - 2022-12-07
|
## [0.6.0] - 2022-12-07
|
||||||
### Added
|
### Added
|
||||||
- Support for non-uniform border radius for `Primitive::Quad`. [#1506](https://github.com/iced-rs/iced/pull/1506)
|
- Support for non-uniform border radius for `Primitive::Quad`. [#1506](https://github.com/iced-rs/iced/pull/1506)
|
||||||
|
|
@ -321,7 +364,8 @@ Many thanks to...
|
||||||
### Added
|
### Added
|
||||||
- First release! :tada:
|
- First release! :tada:
|
||||||
|
|
||||||
[Unreleased]: https://github.com/iced-rs/iced/compare/0.6.0...HEAD
|
[Unreleased]: https://github.com/iced-rs/iced/compare/0.7.0...HEAD
|
||||||
|
[0.7.0]: https://github.com/iced-rs/iced/compare/0.6.0...0.7.0
|
||||||
[0.6.0]: https://github.com/iced-rs/iced/compare/0.5.0...0.6.0
|
[0.6.0]: https://github.com/iced-rs/iced/compare/0.5.0...0.6.0
|
||||||
[0.5.0]: https://github.com/iced-rs/iced/compare/0.4.2...0.5.0
|
[0.5.0]: https://github.com/iced-rs/iced/compare/0.4.2...0.5.0
|
||||||
[0.4.2]: https://github.com/iced-rs/iced/compare/0.4.1...0.4.2
|
[0.4.2]: https://github.com/iced-rs/iced/compare/0.4.1...0.4.2
|
||||||
|
|
|
||||||
18
Cargo.toml
18
Cargo.toml
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "iced"
|
name = "iced"
|
||||||
version = "0.6.0"
|
version = "0.7.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A cross-platform GUI library inspired by Elm"
|
description = "A cross-platform GUI library inspired by Elm"
|
||||||
|
|
@ -68,13 +68,13 @@ members = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced_core = { version = "0.6", path = "core" }
|
iced_core = { version = "0.7", path = "core" }
|
||||||
iced_futures = { version = "0.5", path = "futures" }
|
iced_futures = { version = "0.5", path = "futures" }
|
||||||
iced_native = { version = "0.7", path = "native" }
|
iced_native = { version = "0.8", path = "native" }
|
||||||
iced_graphics = { version = "0.5", path = "graphics" }
|
iced_graphics = { version = "0.6", path = "graphics" }
|
||||||
iced_winit = { version = "0.6", path = "winit", features = ["application"] }
|
iced_winit = { version = "0.7", path = "winit", features = ["application"] }
|
||||||
iced_glutin = { version = "0.5", path = "glutin", optional = true }
|
iced_glutin = { version = "0.6", path = "glutin", optional = true }
|
||||||
iced_glow = { version = "0.5", path = "glow", optional = true }
|
iced_glow = { version = "0.6", path = "glow", optional = true }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
||||||
[dependencies.image_rs]
|
[dependencies.image_rs]
|
||||||
|
|
@ -83,10 +83,10 @@ package = "image"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
iced_wgpu = { version = "0.7", path = "wgpu", optional = true }
|
iced_wgpu = { version = "0.8", path = "wgpu", optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
iced_wgpu = { version = "0.7", path = "wgpu", features = ["webgl"], optional = true }
|
iced_wgpu = { version = "0.8", path = "wgpu", features = ["webgl"], optional = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ __Iced is currently experimental software.__ [Take a look at the roadmap],
|
||||||
Add `iced` as a dependency in your `Cargo.toml`:
|
Add `iced` as a dependency in your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
iced = "0.6"
|
iced = "0.7"
|
||||||
```
|
```
|
||||||
|
|
||||||
If your project is using a Rust edition older than 2021, then you will need to
|
If your project is using a Rust edition older than 2021, then you will need to
|
||||||
|
|
@ -215,7 +215,7 @@ cargo run --features iced/glow --package game_of_life
|
||||||
and then use it in your project with
|
and then use it in your project with
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
iced = { version = "0.6", default-features = false, features = ["glow"] }
|
iced = { version = "0.7", default-features = false, features = ["glow"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
__NOTE:__ Chances are you have hardware that supports at least OpenGL 2.1 or OpenGL ES 2.0,
|
__NOTE:__ Chances are you have hardware that supports at least OpenGL 2.1 or OpenGL ES 2.0,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "iced_core"
|
name = "iced_core"
|
||||||
version = "0.6.2"
|
version = "0.7.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "The essential concepts of Iced"
|
description = "The essential concepts of Iced"
|
||||||
|
|
@ -15,4 +15,4 @@ version = "0.6"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
wasm-timer = { version = "0.2" }
|
instant = "0.1"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ This crate is meant to be a starting point for an Iced runtime.
|
||||||
Add `iced_core` as a dependency in your `Cargo.toml`:
|
Add `iced_core` as a dependency in your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
iced_core = "0.4"
|
iced_core = "0.7"
|
||||||
```
|
```
|
||||||
|
|
||||||
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
//! 
|
//! 
|
||||||
//!
|
//!
|
||||||
//! [Iced]: https://github.com/iced-rs/iced
|
//! [Iced]: https://github.com/iced-rs/iced
|
||||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.6/native
|
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
//! [`iced_web`]: https://github.com/iced-rs/iced_web
|
//! [`iced_web`]: https://github.com/iced-rs/iced_web
|
||||||
#![doc(
|
#![doc(
|
||||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
//! Keep track of time, both in native and web platforms!
|
//! Keep track of time, both in native and web platforms!
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub use wasm_timer::Instant;
|
pub use instant::Instant;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
pub use instant::Duration;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub use std::time::Instant;
|
pub use std::time::Instant;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub use std::time::Duration;
|
pub use std::time::Duration;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "cached"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Nick Senger <dev@nsenger.com>"]
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
iced = { path = "../..", features = ["debug"] }
|
|
||||||
iced_lazy = { path = "../../lazy" }
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
use iced::theme;
|
|
||||||
use iced::widget::{
|
|
||||||
button, column, horizontal_space, row, scrollable, text, text_input,
|
|
||||||
};
|
|
||||||
use iced::{Element, Length, Sandbox, Settings};
|
|
||||||
use iced_lazy::lazy;
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
pub fn main() -> iced::Result {
|
|
||||||
App::run(Settings::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
struct App {
|
|
||||||
options: HashSet<String>,
|
|
||||||
input: String,
|
|
||||||
order: Order,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for App {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
options: ["Foo", "Bar", "Baz", "Qux", "Corge", "Waldo", "Fred"]
|
|
||||||
.into_iter()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.collect(),
|
|
||||||
input: Default::default(),
|
|
||||||
order: Order::Ascending,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
enum Message {
|
|
||||||
InputChanged(String),
|
|
||||||
ToggleOrder,
|
|
||||||
DeleteOption(String),
|
|
||||||
AddOption(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sandbox for App {
|
|
||||||
type Message = Message;
|
|
||||||
|
|
||||||
fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn title(&self) -> String {
|
|
||||||
String::from("Cached - Iced")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, message: Message) {
|
|
||||||
match message {
|
|
||||||
Message::InputChanged(input) => {
|
|
||||||
self.input = input;
|
|
||||||
}
|
|
||||||
Message::ToggleOrder => {
|
|
||||||
self.order = match self.order {
|
|
||||||
Order::Ascending => Order::Descending,
|
|
||||||
Order::Descending => Order::Ascending,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Message::AddOption(option) => {
|
|
||||||
self.options.insert(option);
|
|
||||||
self.input.clear();
|
|
||||||
}
|
|
||||||
Message::DeleteOption(option) => {
|
|
||||||
self.options.remove(&option);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
|
||||||
let options = lazy((&self.order, self.options.len()), || {
|
|
||||||
let mut options: Vec<_> = self.options.iter().collect();
|
|
||||||
|
|
||||||
options.sort_by(|a, b| match self.order {
|
|
||||||
Order::Ascending => a.to_lowercase().cmp(&b.to_lowercase()),
|
|
||||||
Order::Descending => b.to_lowercase().cmp(&a.to_lowercase()),
|
|
||||||
});
|
|
||||||
|
|
||||||
column(
|
|
||||||
options
|
|
||||||
.into_iter()
|
|
||||||
.map(|option| {
|
|
||||||
row![
|
|
||||||
text(option),
|
|
||||||
horizontal_space(Length::Fill),
|
|
||||||
button("Delete")
|
|
||||||
.on_press(Message::DeleteOption(
|
|
||||||
option.to_string(),
|
|
||||||
),)
|
|
||||||
.style(theme::Button::Destructive)
|
|
||||||
]
|
|
||||||
.into()
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
.spacing(10)
|
|
||||||
});
|
|
||||||
|
|
||||||
column![
|
|
||||||
scrollable(options).height(Length::Fill),
|
|
||||||
row![
|
|
||||||
text_input(
|
|
||||||
"Add a new option",
|
|
||||||
&self.input,
|
|
||||||
Message::InputChanged,
|
|
||||||
)
|
|
||||||
.on_submit(Message::AddOption(self.input.clone())),
|
|
||||||
button(text(format!("Toggle Order ({})", self.order)))
|
|
||||||
.on_press(Message::ToggleOrder)
|
|
||||||
]
|
|
||||||
.spacing(10)
|
|
||||||
]
|
|
||||||
.spacing(20)
|
|
||||||
.padding(20)
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Hash)]
|
|
||||||
enum Order {
|
|
||||||
Ascending,
|
|
||||||
Descending,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Order {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}",
|
|
||||||
match self {
|
|
||||||
Self::Ascending => "Ascending",
|
|
||||||
Self::Descending => "Descending",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,5 +6,5 @@ edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced = { path = "../.." }
|
iced = { path = "../..", features = ["debug"] }
|
||||||
iced_native = { path = "../../native" }
|
iced_native = { path = "../../native" }
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use iced::alignment;
|
use iced::alignment;
|
||||||
use iced::executor;
|
use iced::executor;
|
||||||
use iced::widget::{button, checkbox, container, text, Column};
|
use iced::widget::{button, checkbox, container, text, Column};
|
||||||
|
use iced::window;
|
||||||
use iced::{
|
use iced::{
|
||||||
Alignment, Application, Command, Element, Length, Settings, Subscription,
|
Alignment, Application, Command, Element, Length, Settings, Subscription,
|
||||||
Theme,
|
Theme,
|
||||||
};
|
};
|
||||||
use iced_native::{window, Event};
|
use iced_native::Event;
|
||||||
|
|
||||||
pub fn main() -> iced::Result {
|
pub fn main() -> iced::Result {
|
||||||
Events::run(Settings {
|
Events::run(Settings {
|
||||||
|
|
@ -18,14 +19,13 @@ pub fn main() -> iced::Result {
|
||||||
struct Events {
|
struct Events {
|
||||||
last: Vec<iced_native::Event>,
|
last: Vec<iced_native::Event>,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
should_exit: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
EventOccurred(iced_native::Event),
|
EventOccurred(iced_native::Event),
|
||||||
Toggled(bool),
|
Toggled(bool),
|
||||||
Exit,
|
Exit(window::Id),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application for Events {
|
impl Application for Events {
|
||||||
|
|
@ -50,31 +50,29 @@ impl Application for Events {
|
||||||
if self.last.len() > 5 {
|
if self.last.len() > 5 {
|
||||||
let _ = self.last.remove(0);
|
let _ = self.last.remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Command::none()
|
||||||
}
|
}
|
||||||
Message::EventOccurred(event) => {
|
Message::EventOccurred(event) => {
|
||||||
if let Event::Window(_, window::Event::CloseRequested) = event {
|
if let Event::Window(id, window::Event::CloseRequested) = event {
|
||||||
self.should_exit = true;
|
window::close(id)
|
||||||
|
} else {
|
||||||
|
Command::none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Toggled(enabled) => {
|
Message::Toggled(enabled) => {
|
||||||
self.enabled = enabled;
|
self.enabled = enabled;
|
||||||
}
|
|
||||||
Message::Exit => {
|
|
||||||
self.should_exit = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Command::none()
|
Command::none()
|
||||||
|
}
|
||||||
|
Message::Exit(id) => window::close(id),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
iced_native::subscription::events().map(Message::EventOccurred)
|
iced_native::subscription::events().map(Message::EventOccurred)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_exit(&self) -> bool {
|
|
||||||
self.should_exit
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Message> {
|
||||||
let events = Column::with_children(
|
let events = Column::with_children(
|
||||||
self.last
|
self.last
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
use iced::executor;
|
||||||
use iced::widget::{button, column, container};
|
use iced::widget::{button, column, container};
|
||||||
use iced::{Alignment, Element, Length, Sandbox, Settings};
|
use iced::window;
|
||||||
|
use iced::{Alignment, Application, Command, Element, Length, Settings, Theme};
|
||||||
|
|
||||||
pub fn main() -> iced::Result {
|
pub fn main() -> iced::Result {
|
||||||
Exit::run(Settings::default())
|
Exit::run(Settings::default())
|
||||||
|
|
@ -8,7 +10,6 @@ pub fn main() -> iced::Result {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Exit {
|
struct Exit {
|
||||||
show_confirm: bool,
|
show_confirm: bool,
|
||||||
exit: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
@ -17,28 +18,27 @@ enum Message {
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sandbox for Exit {
|
impl Application for Exit {
|
||||||
|
type Executor = executor::Default;
|
||||||
type Message = Message;
|
type Message = Message;
|
||||||
|
type Theme = Theme;
|
||||||
|
type Flags = ();
|
||||||
|
|
||||||
fn new() -> Self {
|
fn new(_flags: ()) -> (Self, Command<Message>) {
|
||||||
Self::default()
|
(Self::default(), Command::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn title(&self) -> String {
|
fn title(&self) -> String {
|
||||||
String::from("Exit - Iced")
|
String::from("Exit - Iced")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_exit(&self) -> bool {
|
fn update(&mut self, message: Message) -> Command<Message> {
|
||||||
self.exit
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, message: Message) {
|
|
||||||
match message {
|
match message {
|
||||||
Message::Confirm => {
|
Message::Confirm => window::close(),
|
||||||
self.exit = true;
|
|
||||||
}
|
|
||||||
Message::Exit => {
|
Message::Exit => {
|
||||||
self.show_confirm = true;
|
self.show_confirm = true;
|
||||||
|
|
||||||
|
Command::none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,21 @@
|
||||||
use iced::theme;
|
use iced::theme;
|
||||||
use iced::widget::{
|
use iced::widget::{
|
||||||
button, column, horizontal_space, row, scrollable, text, text_input,
|
button, column, horizontal_space, pick_list, row, scrollable, text,
|
||||||
|
text_input,
|
||||||
};
|
};
|
||||||
use iced::{Element, Length, Sandbox, Settings};
|
use iced::{Element, Length, Sandbox, Settings};
|
||||||
use iced_lazy::lazy;
|
use iced_lazy::lazy;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
pub fn main() -> iced::Result {
|
pub fn main() -> iced::Result {
|
||||||
App::run(Settings::default())
|
App::run(Settings::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct App {
|
struct App {
|
||||||
options: HashSet<String>,
|
version: u8,
|
||||||
|
items: HashSet<Item>,
|
||||||
input: String,
|
input: String,
|
||||||
order: Order,
|
order: Order,
|
||||||
}
|
}
|
||||||
|
|
@ -20,9 +23,10 @@ struct App {
|
||||||
impl Default for App {
|
impl Default for App {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
options: ["Foo", "Bar", "Baz", "Qux", "Corge", "Waldo", "Fred"]
|
version: 0,
|
||||||
|
items: ["Foo", "Bar", "Baz", "Qux", "Corge", "Waldo", "Fred"]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(ToString::to_string)
|
.map(From::from)
|
||||||
.collect(),
|
.collect(),
|
||||||
input: Default::default(),
|
input: Default::default(),
|
||||||
order: Order::Ascending,
|
order: Order::Ascending,
|
||||||
|
|
@ -30,12 +34,92 @@ impl Default for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||||
|
enum Color {
|
||||||
|
#[default]
|
||||||
|
Black,
|
||||||
|
Red,
|
||||||
|
Orange,
|
||||||
|
Yellow,
|
||||||
|
Green,
|
||||||
|
Blue,
|
||||||
|
Purple,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
const ALL: &[Color] = &[
|
||||||
|
Color::Black,
|
||||||
|
Color::Red,
|
||||||
|
Color::Orange,
|
||||||
|
Color::Yellow,
|
||||||
|
Color::Green,
|
||||||
|
Color::Blue,
|
||||||
|
Color::Purple,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Color {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
Self::Black => "Black",
|
||||||
|
Self::Red => "Red",
|
||||||
|
Self::Orange => "Orange",
|
||||||
|
Self::Yellow => "Yellow",
|
||||||
|
Self::Green => "Green",
|
||||||
|
Self::Blue => "Blue",
|
||||||
|
Self::Purple => "Purple",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Color> for iced::Color {
|
||||||
|
fn from(value: Color) -> Self {
|
||||||
|
match value {
|
||||||
|
Color::Black => iced::Color::from_rgb8(0, 0, 0),
|
||||||
|
Color::Red => iced::Color::from_rgb8(220, 50, 47),
|
||||||
|
Color::Orange => iced::Color::from_rgb8(203, 75, 22),
|
||||||
|
Color::Yellow => iced::Color::from_rgb8(181, 137, 0),
|
||||||
|
Color::Green => iced::Color::from_rgb8(133, 153, 0),
|
||||||
|
Color::Blue => iced::Color::from_rgb8(38, 139, 210),
|
||||||
|
Color::Purple => iced::Color::from_rgb8(108, 113, 196),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq)]
|
||||||
|
struct Item {
|
||||||
|
name: String,
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for Item {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.name.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Item {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.name.eq(&other.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Item {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: s.to_owned(),
|
||||||
|
color: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
InputChanged(String),
|
InputChanged(String),
|
||||||
ToggleOrder,
|
ToggleOrder,
|
||||||
DeleteOption(String),
|
DeleteItem(Item),
|
||||||
AddOption(String),
|
AddItem(String),
|
||||||
|
ItemColorChanged(Item, Color),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sandbox for App {
|
impl Sandbox for App {
|
||||||
|
|
@ -46,7 +130,7 @@ impl Sandbox for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn title(&self) -> String {
|
fn title(&self) -> String {
|
||||||
String::from("Cached - Iced")
|
String::from("Lazy - Iced")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, message: Message) {
|
fn update(&mut self, message: Message) {
|
||||||
|
|
@ -55,43 +139,71 @@ impl Sandbox for App {
|
||||||
self.input = input;
|
self.input = input;
|
||||||
}
|
}
|
||||||
Message::ToggleOrder => {
|
Message::ToggleOrder => {
|
||||||
|
self.version = self.version.wrapping_add(1);
|
||||||
self.order = match self.order {
|
self.order = match self.order {
|
||||||
Order::Ascending => Order::Descending,
|
Order::Ascending => Order::Descending,
|
||||||
Order::Descending => Order::Ascending,
|
Order::Descending => Order::Ascending,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::AddOption(option) => {
|
Message::AddItem(name) => {
|
||||||
self.options.insert(option);
|
self.version = self.version.wrapping_add(1);
|
||||||
|
self.items.insert(name.as_str().into());
|
||||||
self.input.clear();
|
self.input.clear();
|
||||||
}
|
}
|
||||||
Message::DeleteOption(option) => {
|
Message::DeleteItem(item) => {
|
||||||
self.options.remove(&option);
|
self.version = self.version.wrapping_add(1);
|
||||||
|
self.items.remove(&item);
|
||||||
|
}
|
||||||
|
Message::ItemColorChanged(item, color) => {
|
||||||
|
self.version = self.version.wrapping_add(1);
|
||||||
|
if self.items.remove(&item) {
|
||||||
|
self.items.insert(Item {
|
||||||
|
name: item.name,
|
||||||
|
color,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Message> {
|
||||||
let options = lazy((&self.order, self.options.len()), || {
|
let options = lazy(self.version, |_| {
|
||||||
let mut options: Vec<_> = self.options.iter().collect();
|
let mut items: Vec<_> = self.items.iter().cloned().collect();
|
||||||
|
|
||||||
options.sort_by(|a, b| match self.order {
|
items.sort_by(|a, b| match self.order {
|
||||||
Order::Ascending => a.to_lowercase().cmp(&b.to_lowercase()),
|
Order::Ascending => {
|
||||||
Order::Descending => b.to_lowercase().cmp(&a.to_lowercase()),
|
a.name.to_lowercase().cmp(&b.name.to_lowercase())
|
||||||
|
}
|
||||||
|
Order::Descending => {
|
||||||
|
b.name.to_lowercase().cmp(&a.name.to_lowercase())
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
column(
|
column(
|
||||||
options
|
items
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|option| {
|
.map(|item| {
|
||||||
|
let button = button("Delete")
|
||||||
|
.on_press(Message::DeleteItem(item.clone()))
|
||||||
|
.style(theme::Button::Destructive);
|
||||||
|
|
||||||
row![
|
row![
|
||||||
text(option),
|
text(&item.name)
|
||||||
|
.style(theme::Text::Color(item.color.into())),
|
||||||
horizontal_space(Length::Fill),
|
horizontal_space(Length::Fill),
|
||||||
button("Delete")
|
pick_list(
|
||||||
.on_press(Message::DeleteOption(
|
Color::ALL,
|
||||||
option.to_string(),
|
Some(item.color),
|
||||||
),)
|
move |color| {
|
||||||
.style(theme::Button::Destructive)
|
Message::ItemColorChanged(
|
||||||
|
item.clone(),
|
||||||
|
color,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
button
|
||||||
]
|
]
|
||||||
|
.spacing(20)
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
@ -107,7 +219,7 @@ impl Sandbox for App {
|
||||||
&self.input,
|
&self.input,
|
||||||
Message::InputChanged,
|
Message::InputChanged,
|
||||||
)
|
)
|
||||||
.on_submit(Message::AddOption(self.input.clone())),
|
.on_submit(Message::AddItem(self.input.clone())),
|
||||||
button(text(format!("Toggle Order ({})", self.order)))
|
button(text(format!("Toggle Order ({})", self.order)))
|
||||||
.on_press(Message::ToggleOrder)
|
.on_press(Message::ToggleOrder)
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
use iced::application;
|
use iced::application;
|
||||||
use iced::executor;
|
use iced::executor;
|
||||||
use iced::theme::{self, Theme};
|
use iced::theme::{self, Theme};
|
||||||
use iced::time;
|
|
||||||
use iced::widget::canvas;
|
use iced::widget::canvas;
|
||||||
use iced::widget::canvas::gradient::{self, Gradient};
|
use iced::widget::canvas::gradient::{self, Gradient};
|
||||||
use iced::widget::canvas::stroke::{self, Stroke};
|
use iced::widget::canvas::stroke::{self, Stroke};
|
||||||
|
|
@ -90,7 +89,7 @@ impl Application for SolarSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
time::every(time::Duration::from_millis(10)).map(Message::Tick)
|
window::frames().map(Message::Tick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,9 +125,9 @@ impl<I, O, H> std::fmt::Debug for Subscription<I, O, H> {
|
||||||
/// - [`stopwatch`], a watch with start/stop and reset buttons showcasing how
|
/// - [`stopwatch`], a watch with start/stop and reset buttons showcasing how
|
||||||
/// to listen to time.
|
/// to listen to time.
|
||||||
///
|
///
|
||||||
/// [examples]: https://github.com/iced-rs/iced/tree/0.6/examples
|
/// [examples]: https://github.com/iced-rs/iced/tree/0.7/examples
|
||||||
/// [`download_progress`]: https://github.com/iced-rs/iced/tree/0.6/examples/download_progress
|
/// [`download_progress`]: https://github.com/iced-rs/iced/tree/0.7/examples/download_progress
|
||||||
/// [`stopwatch`]: https://github.com/iced-rs/iced/tree/0.6/examples/stopwatch
|
/// [`stopwatch`]: https://github.com/iced-rs/iced/tree/0.7/examples/stopwatch
|
||||||
pub trait Recipe<Hasher: std::hash::Hasher, Event> {
|
pub trait Recipe<Hasher: std::hash::Hasher, Event> {
|
||||||
/// The events that will be produced by a [`Subscription`] with this
|
/// The events that will be produced by a [`Subscription`] with this
|
||||||
/// [`Recipe`].
|
/// [`Recipe`].
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "iced_glow"
|
name = "iced_glow"
|
||||||
version = "0.5.1"
|
version = "0.6.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A glow renderer for iced"
|
description = "A glow renderer for iced"
|
||||||
|
|
@ -34,11 +34,11 @@ bytemuck = "1.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
[dependencies.iced_native]
|
[dependencies.iced_native]
|
||||||
version = "0.7"
|
version = "0.8"
|
||||||
path = "../native"
|
path = "../native"
|
||||||
|
|
||||||
[dependencies.iced_graphics]
|
[dependencies.iced_graphics]
|
||||||
version = "0.5"
|
version = "0.6"
|
||||||
path = "../graphics"
|
path = "../graphics"
|
||||||
features = ["font-fallback", "font-icons", "opengl"]
|
features = ["font-fallback", "font-icons", "opengl"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ Currently, `iced_glow` supports the following primitives:
|
||||||
Add `iced_glow` as a dependency in your `Cargo.toml`:
|
Add `iced_glow` as a dependency in your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
iced_glow = "0.2"
|
iced_glow = "0.6"
|
||||||
```
|
```
|
||||||
|
|
||||||
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
//! 
|
//! 
|
||||||
//!
|
//!
|
||||||
//! [`glow`]: https://github.com/grovesNL/glow
|
//! [`glow`]: https://github.com/grovesNL/glow
|
||||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.6/native
|
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
#![doc(
|
#![doc(
|
||||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
||||||
)]
|
)]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "iced_glutin"
|
name = "iced_glutin"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A glutin runtime for Iced"
|
description = "A glutin runtime for Iced"
|
||||||
|
|
@ -19,26 +19,26 @@ multi_window = ["iced_winit/multi_window"]
|
||||||
[dependencies.raw-window-handle]
|
[dependencies.raw-window-handle]
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
|
||||||
[dependencies.log]
|
[dependencies]
|
||||||
version = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
[dependencies.glutin]
|
[dependencies.glutin]
|
||||||
version = "0.30"
|
version = "0.30"
|
||||||
|
|
||||||
[dependencies.iced_native]
|
[dependencies.iced_native]
|
||||||
version = "0.7"
|
version = "0.8"
|
||||||
path = "../native"
|
path = "../native"
|
||||||
|
|
||||||
[dependencies.iced_winit]
|
[dependencies.iced_winit]
|
||||||
version = "0.6"
|
version = "0.7"
|
||||||
path = "../winit"
|
path = "../winit"
|
||||||
features = ["application"]
|
features = ["application"]
|
||||||
|
|
||||||
[dependencies.iced_graphics]
|
[dependencies.iced_graphics]
|
||||||
version = "0.5"
|
version = "0.6"
|
||||||
path = "../graphics"
|
path = "../graphics"
|
||||||
features = ["opengl"]
|
features = ["opengl"]
|
||||||
|
|
||||||
[dependencies.tracing]
|
[dependencies.tracing]
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ It exposes a renderer-agnostic `Application` trait that can be implemented and t
|
||||||
Add `iced_glutin` as a dependency in your `Cargo.toml`:
|
Add `iced_glutin` as a dependency in your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
iced_glutin = "0.2"
|
iced_glutin = "0.6"
|
||||||
```
|
```
|
||||||
|
|
||||||
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ use iced_winit::conversion;
|
||||||
use iced_winit::futures;
|
use iced_winit::futures;
|
||||||
use iced_winit::futures::channel::mpsc;
|
use iced_winit::futures::channel::mpsc;
|
||||||
use iced_winit::renderer;
|
use iced_winit::renderer;
|
||||||
|
use iced_winit::time::Instant;
|
||||||
use iced_winit::user_interface;
|
use iced_winit::user_interface;
|
||||||
use iced_winit::winit;
|
use iced_winit::winit;
|
||||||
use iced_winit::{Clipboard, Command, Debug, Proxy, Settings};
|
use iced_winit::{Clipboard, Command, Debug, Event, Proxy, Settings};
|
||||||
|
|
||||||
use glutin::config::{
|
use glutin::config::{
|
||||||
Config, ConfigSurfaceTypes, ConfigTemplateBuilder, GlConfig,
|
Config, ConfigSurfaceTypes, ConfigTemplateBuilder, GlConfig,
|
||||||
|
|
@ -280,7 +281,8 @@ where
|
||||||
|
|
||||||
let context = { context.make_not_current().expect("make context current") };
|
let context = { context.make_not_current().expect("make context current") };
|
||||||
|
|
||||||
let (mut sender, receiver) = mpsc::unbounded();
|
let (mut event_sender, event_receiver) = mpsc::unbounded();
|
||||||
|
let (control_sender, mut control_receiver) = mpsc::unbounded();
|
||||||
|
|
||||||
let mut instance = Box::pin({
|
let mut instance = Box::pin({
|
||||||
let run_instance = run_instance::<A, E, C>(
|
let run_instance = run_instance::<A, E, C>(
|
||||||
|
|
@ -290,7 +292,8 @@ where
|
||||||
runtime,
|
runtime,
|
||||||
proxy,
|
proxy,
|
||||||
debug,
|
debug,
|
||||||
receiver,
|
event_receiver,
|
||||||
|
control_sender,
|
||||||
window,
|
window,
|
||||||
surface,
|
surface,
|
||||||
context,
|
context,
|
||||||
|
|
@ -330,14 +333,20 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(event) = event {
|
if let Some(event) = event {
|
||||||
sender.start_send(event).expect("Send event");
|
event_sender.start_send(event).expect("Send event");
|
||||||
|
|
||||||
let poll = instance.as_mut().poll(&mut context);
|
let poll = instance.as_mut().poll(&mut context);
|
||||||
|
|
||||||
*control_flow = match poll {
|
match poll {
|
||||||
task::Poll::Pending => ControlFlow::Wait,
|
task::Poll::Pending => {
|
||||||
task::Poll::Ready(_) => ControlFlow::Exit,
|
if let Ok(Some(flow)) = control_receiver.try_next() {
|
||||||
};
|
*control_flow = flow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task::Poll::Ready(_) => {
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -351,7 +360,8 @@ async fn run_instance<A, E, C>(
|
||||||
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
|
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
|
||||||
mut proxy: winit::event_loop::EventLoopProxy<A::Message>,
|
mut proxy: winit::event_loop::EventLoopProxy<A::Message>,
|
||||||
mut debug: Debug,
|
mut debug: Debug,
|
||||||
mut receiver: mpsc::UnboundedReceiver<winit::event::Event<'_, A::Message>>,
|
mut event_receiver: mpsc::UnboundedReceiver<winit::event::Event<'_, A::Message>, >,
|
||||||
|
mut control_sender: mpsc::UnboundedSender<winit::event_loop::ControlFlow>,
|
||||||
window: winit::window::Window,
|
window: winit::window::Window,
|
||||||
surface: Surface<WindowSurface>,
|
surface: Surface<WindowSurface>,
|
||||||
context: NotCurrentContext,
|
context: NotCurrentContext,
|
||||||
|
|
@ -364,6 +374,7 @@ async fn run_instance<A, E, C>(
|
||||||
<A::Renderer as iced_native::Renderer>::Theme: StyleSheet,
|
<A::Renderer as iced_native::Renderer>::Theme: StyleSheet,
|
||||||
{
|
{
|
||||||
use iced_winit::futures::stream::StreamExt;
|
use iced_winit::futures::stream::StreamExt;
|
||||||
|
use winit::event_loop::ControlFlow;
|
||||||
use winit::event;
|
use winit::event;
|
||||||
|
|
||||||
let context = {
|
let context = {
|
||||||
|
|
@ -406,13 +417,22 @@ async fn run_instance<A, E, C>(
|
||||||
let mut mouse_interaction = mouse::Interaction::default();
|
let mut mouse_interaction = mouse::Interaction::default();
|
||||||
let mut events = Vec::new();
|
let mut events = Vec::new();
|
||||||
let mut messages = Vec::new();
|
let mut messages = Vec::new();
|
||||||
|
let mut redraw_pending = false;
|
||||||
|
|
||||||
debug.startup_finished();
|
debug.startup_finished();
|
||||||
|
|
||||||
while let Some(event) = receiver.next().await {
|
while let Some(event) = event_receiver.next().await {
|
||||||
match event {
|
match event {
|
||||||
|
event::Event::NewEvents(start_cause) => {
|
||||||
|
redraw_pending = matches!(
|
||||||
|
start_cause,
|
||||||
|
event::StartCause::Init
|
||||||
|
| event::StartCause::Poll
|
||||||
|
| event::StartCause::ResumeTimeReached { .. }
|
||||||
|
);
|
||||||
|
}
|
||||||
event::Event::MainEventsCleared => {
|
event::Event::MainEventsCleared => {
|
||||||
if events.is_empty() && messages.is_empty() {
|
if !redraw_pending && events.is_empty() && messages.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,6 +494,24 @@ async fn run_instance<A, E, C>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Avoid redrawing all the time by forcing widgets to
|
||||||
|
// request redraws on state changes
|
||||||
|
//
|
||||||
|
// Then, we can use the `interface_state` here to decide if a redraw
|
||||||
|
// is needed right away, or simply wait until a specific time.
|
||||||
|
let redraw_event = Event::Window(
|
||||||
|
crate::window::Id::MAIN,
|
||||||
|
crate::window::Event::RedrawRequested(Instant::now()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (interface_state, _) = user_interface.update(
|
||||||
|
&[redraw_event.clone()],
|
||||||
|
state.cursor_position(),
|
||||||
|
&mut renderer,
|
||||||
|
&mut clipboard,
|
||||||
|
&mut messages,
|
||||||
|
);
|
||||||
|
|
||||||
debug.draw_started();
|
debug.draw_started();
|
||||||
let new_mouse_interaction = user_interface.draw(
|
let new_mouse_interaction = user_interface.draw(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
|
|
@ -494,6 +532,23 @@ async fn run_instance<A, E, C>(
|
||||||
}
|
}
|
||||||
|
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
|
runtime.broadcast((redraw_event, crate::event::Status::Ignored));
|
||||||
|
|
||||||
|
let _ = control_sender.start_send(match interface_state {
|
||||||
|
user_interface::State::Updated {
|
||||||
|
redraw_request: Some(redraw_request),
|
||||||
|
} => match redraw_request {
|
||||||
|
crate::window::RedrawRequest::NextFrame => {
|
||||||
|
ControlFlow::Poll
|
||||||
|
}
|
||||||
|
crate::window::RedrawRequest::At(at) => {
|
||||||
|
ControlFlow::WaitUntil(at)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => ControlFlow::Wait,
|
||||||
|
});
|
||||||
|
|
||||||
|
redraw_pending = false;
|
||||||
}
|
}
|
||||||
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
|
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
|
||||||
event::MacOS::ReceivedUrl(url),
|
event::MacOS::ReceivedUrl(url),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "iced_graphics"
|
name = "iced_graphics"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A bunch of backend-agnostic types that can be leveraged to build a renderer for Iced"
|
description = "A bunch of backend-agnostic types that can be leveraged to build a renderer for Iced"
|
||||||
|
|
@ -44,11 +44,11 @@ version = "1.4"
|
||||||
features = ["derive"]
|
features = ["derive"]
|
||||||
|
|
||||||
[dependencies.iced_native]
|
[dependencies.iced_native]
|
||||||
version = "0.7"
|
version = "0.8"
|
||||||
path = "../native"
|
path = "../native"
|
||||||
|
|
||||||
[dependencies.iced_style]
|
[dependencies.iced_style]
|
||||||
version = "0.5"
|
version = "0.6"
|
||||||
path = "../style"
|
path = "../style"
|
||||||
|
|
||||||
[dependencies.lyon]
|
[dependencies.lyon]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "iced_lazy"
|
name = "iced_lazy"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Lazy widgets for Iced"
|
description = "Lazy widgets for Iced"
|
||||||
|
|
@ -14,5 +14,5 @@ categories = ["gui"]
|
||||||
ouroboros = "0.13"
|
ouroboros = "0.13"
|
||||||
|
|
||||||
[dependencies.iced_native]
|
[dependencies.iced_native]
|
||||||
version = "0.7"
|
version = "0.8"
|
||||||
path = "../native"
|
path = "../native"
|
||||||
|
|
|
||||||
128
lazy/src/lazy.rs
128
lazy/src/lazy.rs
|
|
@ -9,16 +9,17 @@ use iced_native::Element;
|
||||||
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell, Size};
|
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell, Size};
|
||||||
|
|
||||||
use ouroboros::self_referencing;
|
use ouroboros::self_referencing;
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::RefCell;
|
||||||
use std::hash::{Hash, Hasher as H};
|
use std::hash::{Hash, Hasher as H};
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Lazy<'a, Message, Renderer, Dependency, View> {
|
pub struct Lazy<'a, Message, Renderer, Dependency, View> {
|
||||||
dependency: Dependency,
|
dependency: Dependency,
|
||||||
view: Box<dyn Fn() -> View + 'a>,
|
view: Box<dyn Fn(&Dependency) -> View + 'a>,
|
||||||
element: RefCell<Option<Rc<RefCell<Element<'static, Message, Renderer>>>>>,
|
element: RefCell<
|
||||||
|
Option<Rc<RefCell<Option<Element<'static, Message, Renderer>>>>>,
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Renderer, Dependency, View>
|
impl<'a, Message, Renderer, Dependency, View>
|
||||||
|
|
@ -27,7 +28,10 @@ where
|
||||||
Dependency: Hash + 'a,
|
Dependency: Hash + 'a,
|
||||||
View: Into<Element<'static, Message, Renderer>>,
|
View: Into<Element<'static, Message, Renderer>>,
|
||||||
{
|
{
|
||||||
pub fn new(dependency: Dependency, view: impl Fn() -> View + 'a) -> Self {
|
pub fn new(
|
||||||
|
dependency: Dependency,
|
||||||
|
view: impl Fn(&Dependency) -> View + 'a,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
dependency,
|
dependency,
|
||||||
view: Box::new(view),
|
view: Box::new(view),
|
||||||
|
|
@ -37,21 +41,35 @@ where
|
||||||
|
|
||||||
fn with_element<T>(
|
fn with_element<T>(
|
||||||
&self,
|
&self,
|
||||||
f: impl FnOnce(Ref<Element<Message, Renderer>>) -> T,
|
f: impl FnOnce(&Element<Message, Renderer>) -> T,
|
||||||
) -> T {
|
) -> T {
|
||||||
f(self.element.borrow().as_ref().unwrap().borrow())
|
f(self
|
||||||
|
.element
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_element_mut<T>(
|
fn with_element_mut<T>(
|
||||||
&self,
|
&self,
|
||||||
f: impl FnOnce(RefMut<Element<Message, Renderer>>) -> T,
|
f: impl FnOnce(&mut Element<Message, Renderer>) -> T,
|
||||||
) -> T {
|
) -> T {
|
||||||
f(self.element.borrow().as_ref().unwrap().borrow_mut())
|
f(self
|
||||||
|
.element
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.borrow_mut()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Internal<Message, Renderer> {
|
struct Internal<Message, Renderer> {
|
||||||
element: Rc<RefCell<Element<'static, Message, Renderer>>>,
|
element: Rc<RefCell<Option<Element<'static, Message, Renderer>>>>,
|
||||||
hash: u64,
|
hash: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,7 +91,8 @@ where
|
||||||
self.dependency.hash(&mut hasher);
|
self.dependency.hash(&mut hasher);
|
||||||
let hash = hasher.finish();
|
let hash = hasher.finish();
|
||||||
|
|
||||||
let element = Rc::new(RefCell::new((self.view)().into()));
|
let element =
|
||||||
|
Rc::new(RefCell::new(Some((self.view)(&self.dependency).into())));
|
||||||
|
|
||||||
(*self.element.borrow_mut()) = Some(element.clone());
|
(*self.element.borrow_mut()) = Some(element.clone());
|
||||||
|
|
||||||
|
|
@ -81,9 +100,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children(&self) -> Vec<Tree> {
|
fn children(&self) -> Vec<Tree> {
|
||||||
vec![Tree::new(
|
self.with_element(|element| vec![Tree::new(element.as_widget())])
|
||||||
self.element.borrow().as_ref().unwrap().borrow().as_widget(),
|
|
||||||
)]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff(&self, tree: &mut Tree) {
|
fn diff(&self, tree: &mut Tree) {
|
||||||
|
|
@ -96,13 +113,13 @@ where
|
||||||
if current.hash != new_hash {
|
if current.hash != new_hash {
|
||||||
current.hash = new_hash;
|
current.hash = new_hash;
|
||||||
|
|
||||||
let element = (self.view)().into();
|
let element = (self.view)(&self.dependency).into();
|
||||||
current.element = Rc::new(RefCell::new(element));
|
current.element = Rc::new(RefCell::new(Some(element)));
|
||||||
|
|
||||||
(*self.element.borrow_mut()) = Some(current.element.clone());
|
(*self.element.borrow_mut()) = Some(current.element.clone());
|
||||||
tree.diff_children(std::slice::from_ref(
|
self.with_element(|element| {
|
||||||
&self.element.borrow().as_ref().unwrap().borrow().as_widget(),
|
tree.diff_children(std::slice::from_ref(&element.as_widget()))
|
||||||
));
|
});
|
||||||
} else {
|
} else {
|
||||||
(*self.element.borrow_mut()) = Some(current.element.clone());
|
(*self.element.borrow_mut()) = Some(current.element.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -153,7 +170,7 @@ where
|
||||||
clipboard: &mut dyn Clipboard,
|
clipboard: &mut dyn Clipboard,
|
||||||
shell: &mut Shell<'_, Message>,
|
shell: &mut Shell<'_, Message>,
|
||||||
) -> event::Status {
|
) -> event::Status {
|
||||||
self.with_element_mut(|mut element| {
|
self.with_element_mut(|element| {
|
||||||
element.as_widget_mut().on_event(
|
element.as_widget_mut().on_event(
|
||||||
&mut tree.children[0],
|
&mut tree.children[0],
|
||||||
event,
|
event,
|
||||||
|
|
@ -214,23 +231,27 @@ where
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
) -> Option<overlay::Element<'_, Message, Renderer>> {
|
) -> Option<overlay::Element<'_, Message, Renderer>> {
|
||||||
let overlay = OverlayBuilder {
|
let overlay = Overlay(Some(
|
||||||
cached: self,
|
InnerBuilder {
|
||||||
tree: &mut tree.children[0],
|
cell: self.element.borrow().as_ref().unwrap().clone(),
|
||||||
types: PhantomData,
|
element: self
|
||||||
overlay_builder: |cached, tree| {
|
.element
|
||||||
Rc::get_mut(cached.element.get_mut().as_mut().unwrap())
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_mut()
|
.borrow_mut()
|
||||||
.as_widget_mut()
|
.take()
|
||||||
.overlay(tree, layout, renderer)
|
.unwrap(),
|
||||||
},
|
tree: &mut tree.children[0],
|
||||||
}
|
overlay_builder: |element, tree| {
|
||||||
.build();
|
element.as_widget_mut().overlay(tree, layout, renderer)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
.build(),
|
||||||
|
));
|
||||||
|
|
||||||
let has_overlay = overlay.with_overlay(|overlay| {
|
let has_overlay = overlay
|
||||||
overlay.as_ref().map(overlay::Element::position)
|
.with_overlay_maybe(|overlay| overlay::Element::position(overlay));
|
||||||
});
|
|
||||||
|
|
||||||
has_overlay
|
has_overlay
|
||||||
.map(|position| overlay::Element::new(position, Box::new(overlay)))
|
.map(|position| overlay::Element::new(position, Box::new(overlay)))
|
||||||
|
|
@ -238,37 +259,50 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[self_referencing]
|
#[self_referencing]
|
||||||
struct Overlay<'a, 'b, Message, Renderer, Dependency, View> {
|
struct Inner<'a, Message, Renderer>
|
||||||
cached: &'a mut Lazy<'b, Message, Renderer, Dependency, View>,
|
where
|
||||||
|
Message: 'a,
|
||||||
|
Renderer: 'a,
|
||||||
|
{
|
||||||
|
cell: Rc<RefCell<Option<Element<'static, Message, Renderer>>>>,
|
||||||
|
element: Element<'static, Message, Renderer>,
|
||||||
tree: &'a mut Tree,
|
tree: &'a mut Tree,
|
||||||
types: PhantomData<(Message, Dependency, View)>,
|
|
||||||
|
|
||||||
#[borrows(mut cached, mut tree)]
|
#[borrows(mut element, mut tree)]
|
||||||
#[covariant]
|
#[covariant]
|
||||||
overlay: Option<overlay::Element<'this, Message, Renderer>>,
|
overlay: Option<overlay::Element<'this, Message, Renderer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, Message, Renderer, Dependency, View>
|
struct Overlay<'a, Message, Renderer>(Option<Inner<'a, Message, Renderer>>);
|
||||||
Overlay<'a, 'b, Message, Renderer, Dependency, View>
|
|
||||||
{
|
impl<'a, Message, Renderer> Drop for Overlay<'a, Message, Renderer> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let heads = self.0.take().unwrap().into_heads();
|
||||||
|
(*heads.cell.borrow_mut()) = Some(heads.element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message, Renderer> Overlay<'a, Message, Renderer> {
|
||||||
fn with_overlay_maybe<T>(
|
fn with_overlay_maybe<T>(
|
||||||
&self,
|
&self,
|
||||||
f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T,
|
f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T,
|
||||||
) -> Option<T> {
|
) -> Option<T> {
|
||||||
self.borrow_overlay().as_ref().map(f)
|
self.0.as_ref().unwrap().borrow_overlay().as_ref().map(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_overlay_mut_maybe<T>(
|
fn with_overlay_mut_maybe<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T,
|
f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T,
|
||||||
) -> Option<T> {
|
) -> Option<T> {
|
||||||
self.with_overlay_mut(|overlay| overlay.as_mut().map(f))
|
self.0
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.with_overlay_mut(|overlay| overlay.as_mut().map(f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, Message, Renderer, Dependency, View>
|
impl<'a, Message, Renderer> overlay::Overlay<Message, Renderer>
|
||||||
overlay::Overlay<Message, Renderer>
|
for Overlay<'a, Message, Renderer>
|
||||||
for Overlay<'a, 'b, Message, Renderer, Dependency, View>
|
|
||||||
where
|
where
|
||||||
Renderer: iced_native::Renderer,
|
Renderer: iced_native::Renderer,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ use std::hash::Hash;
|
||||||
|
|
||||||
pub fn lazy<'a, Message, Renderer, Dependency, View>(
|
pub fn lazy<'a, Message, Renderer, Dependency, View>(
|
||||||
dependency: Dependency,
|
dependency: Dependency,
|
||||||
view: impl Fn() -> View + 'a,
|
view: impl Fn(&Dependency) -> View + 'a,
|
||||||
) -> Lazy<'a, Message, Renderer, Dependency, View>
|
) -> Lazy<'a, Message, Renderer, Dependency, View>
|
||||||
where
|
where
|
||||||
Dependency: Hash + 'a,
|
Dependency: Hash + 'a,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "iced_native"
|
name = "iced_native"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A renderer-agnostic library for native GUIs"
|
description = "A renderer-agnostic library for native GUIs"
|
||||||
|
|
@ -16,7 +16,7 @@ unicode-segmentation = "1.6"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
|
|
||||||
[dependencies.iced_core]
|
[dependencies.iced_core]
|
||||||
version = "0.6"
|
version = "0.7"
|
||||||
path = "../core"
|
path = "../core"
|
||||||
|
|
||||||
[dependencies.iced_futures]
|
[dependencies.iced_futures]
|
||||||
|
|
@ -25,5 +25,5 @@ path = "../futures"
|
||||||
features = ["thread-pool"]
|
features = ["thread-pool"]
|
||||||
|
|
||||||
[dependencies.iced_style]
|
[dependencies.iced_style]
|
||||||
version = "0.5.1"
|
version = "0.6.0"
|
||||||
path = "../style"
|
path = "../style"
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ To achieve this, it introduces a bunch of reusable interfaces:
|
||||||
Add `iced_native` as a dependency in your `Cargo.toml`:
|
Add `iced_native` as a dependency in your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
iced_native = "0.4"
|
iced_native = "0.8"
|
||||||
```
|
```
|
||||||
|
|
||||||
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use crate::{
|
||||||
Clipboard, Color, Layout, Length, Point, Rectangle, Shell, Widget,
|
Clipboard, Color, Layout, Length, Point, Rectangle, Shell, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
/// A generic [`Widget`].
|
/// A generic [`Widget`].
|
||||||
|
|
@ -333,6 +334,10 @@ where
|
||||||
) {
|
) {
|
||||||
self.operation.text_input(state, id);
|
self.operation.text_input(state, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn custom(&mut self, state: &mut dyn Any, id: Option<&widget::Id>) {
|
||||||
|
self.operation.custom(state, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.widget.operate(
|
self.widget.operate(
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@
|
||||||
//! - Build a new renderer, see the [renderer] module.
|
//! - Build a new renderer, see the [renderer] module.
|
||||||
//! - Build a custom widget, start at the [`Widget`] trait.
|
//! - Build a custom widget, start at the [`Widget`] trait.
|
||||||
//!
|
//!
|
||||||
//! [`iced_core`]: https://github.com/iced-rs/iced/tree/0.6/core
|
//! [`iced_core`]: https://github.com/iced-rs/iced/tree/0.7/core
|
||||||
//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/0.6/winit
|
//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/0.7/winit
|
||||||
//! [`druid`]: https://github.com/xi-editor/druid
|
//! [`druid`]: https://github.com/xi-editor/druid
|
||||||
//! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle
|
//! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle
|
||||||
//! [renderer]: crate::renderer
|
//! [renderer]: crate::renderer
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ use crate::renderer;
|
||||||
use crate::widget;
|
use crate::widget;
|
||||||
use crate::{Clipboard, Layout, Point, Rectangle, Shell, Size, Vector};
|
use crate::{Clipboard, Layout, Point, Rectangle, Shell, Size, Vector};
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
/// A generic [`Overlay`].
|
/// A generic [`Overlay`].
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Element<'a, Message, Renderer> {
|
pub struct Element<'a, Message, Renderer> {
|
||||||
|
|
@ -188,6 +190,10 @@ where
|
||||||
) {
|
) {
|
||||||
self.operation.text_input(state, id)
|
self.operation.text_input(state, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn custom(&mut self, state: &mut dyn Any, id: Option<&widget::Id>) {
|
||||||
|
self.operation.custom(state, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.content
|
self.content
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,11 @@ pub trait Renderer: Sized {
|
||||||
f: impl FnOnce(&mut Self),
|
f: impl FnOnce(&mut Self),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Clears all of the recorded primitives in the [`Renderer`].
|
|
||||||
fn clear(&mut self);
|
|
||||||
|
|
||||||
/// Fills a [`Quad`] with the provided [`Background`].
|
/// Fills a [`Quad`] with the provided [`Background`].
|
||||||
fn fill_quad(&mut self, quad: Quad, background: impl Into<Background>);
|
fn fill_quad(&mut self, quad: Quad, background: impl Into<Background>);
|
||||||
|
|
||||||
|
/// Clears all of the recorded primitives in the [`Renderer`].
|
||||||
|
fn clear(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A polygon with four sides.
|
/// A polygon with four sides.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::window;
|
||||||
|
|
||||||
/// A connection to the state of a shell.
|
/// A connection to the state of a shell.
|
||||||
///
|
///
|
||||||
/// A [`Widget`] can leverage a [`Shell`] to trigger changes in an application,
|
/// A [`Widget`] can leverage a [`Shell`] to trigger changes in an application,
|
||||||
|
|
@ -7,6 +9,7 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Shell<'a, Message> {
|
pub struct Shell<'a, Message> {
|
||||||
messages: &'a mut Vec<Message>,
|
messages: &'a mut Vec<Message>,
|
||||||
|
redraw_request: Option<window::RedrawRequest>,
|
||||||
is_layout_invalid: bool,
|
is_layout_invalid: bool,
|
||||||
are_widgets_invalid: bool,
|
are_widgets_invalid: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -16,11 +19,47 @@ impl<'a, Message> Shell<'a, Message> {
|
||||||
pub fn new(messages: &'a mut Vec<Message>) -> Self {
|
pub fn new(messages: &'a mut Vec<Message>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
messages,
|
messages,
|
||||||
|
redraw_request: None,
|
||||||
is_layout_invalid: false,
|
is_layout_invalid: false,
|
||||||
are_widgets_invalid: false,
|
are_widgets_invalid: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Publish the given `Message` for an application to process it.
|
||||||
|
pub fn publish(&mut self, message: Message) {
|
||||||
|
self.messages.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Requests a new frame to be drawn at the given [`Instant`].
|
||||||
|
pub fn request_redraw(&mut self, request: window::RedrawRequest) {
|
||||||
|
match self.redraw_request {
|
||||||
|
None => {
|
||||||
|
self.redraw_request = Some(request);
|
||||||
|
}
|
||||||
|
Some(current) if request < current => {
|
||||||
|
self.redraw_request = Some(request);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the requested [`Instant`] a redraw should happen, if any.
|
||||||
|
pub fn redraw_request(&self) -> Option<window::RedrawRequest> {
|
||||||
|
self.redraw_request
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the current layout is invalid or not.
|
||||||
|
pub fn is_layout_invalid(&self) -> bool {
|
||||||
|
self.is_layout_invalid
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidates the current application layout.
|
||||||
|
///
|
||||||
|
/// The shell will relayout the application widgets.
|
||||||
|
pub fn invalidate_layout(&mut self) {
|
||||||
|
self.is_layout_invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Triggers the given function if the layout is invalid, cleaning it in the
|
/// Triggers the given function if the layout is invalid, cleaning it in the
|
||||||
/// process.
|
/// process.
|
||||||
pub fn revalidate_layout(&mut self, f: impl FnOnce()) {
|
pub fn revalidate_layout(&mut self, f: impl FnOnce()) {
|
||||||
|
|
@ -31,21 +70,10 @@ impl<'a, Message> Shell<'a, Message> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the current layout is invalid or not.
|
/// Returns whether the widgets of the current application have been
|
||||||
pub fn is_layout_invalid(&self) -> bool {
|
/// invalidated.
|
||||||
self.is_layout_invalid
|
pub fn are_widgets_invalid(&self) -> bool {
|
||||||
}
|
self.are_widgets_invalid
|
||||||
|
|
||||||
/// Publish the given `Message` for an application to process it.
|
|
||||||
pub fn publish(&mut self, message: Message) {
|
|
||||||
self.messages.push(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invalidates the current application layout.
|
|
||||||
///
|
|
||||||
/// The shell will relayout the application widgets.
|
|
||||||
pub fn invalidate_layout(&mut self) {
|
|
||||||
self.is_layout_invalid = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invalidates the current application widgets.
|
/// Invalidates the current application widgets.
|
||||||
|
|
@ -62,16 +90,14 @@ impl<'a, Message> Shell<'a, Message> {
|
||||||
pub fn merge<B>(&mut self, other: Shell<'_, B>, f: impl Fn(B) -> Message) {
|
pub fn merge<B>(&mut self, other: Shell<'_, B>, f: impl Fn(B) -> Message) {
|
||||||
self.messages.extend(other.messages.drain(..).map(f));
|
self.messages.extend(other.messages.drain(..).map(f));
|
||||||
|
|
||||||
|
if let Some(at) = other.redraw_request {
|
||||||
|
self.request_redraw(at);
|
||||||
|
}
|
||||||
|
|
||||||
self.is_layout_invalid =
|
self.is_layout_invalid =
|
||||||
self.is_layout_invalid || other.is_layout_invalid;
|
self.is_layout_invalid || other.is_layout_invalid;
|
||||||
|
|
||||||
self.are_widgets_invalid =
|
self.are_widgets_invalid =
|
||||||
self.are_widgets_invalid || other.are_widgets_invalid;
|
self.are_widgets_invalid || other.are_widgets_invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the widgets of the current application have been
|
|
||||||
/// invalidated.
|
|
||||||
pub fn are_widgets_invalid(&self) -> bool {
|
|
||||||
self.are_widgets_invalid
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
//! Listen to external events in your application.
|
//! Listen to external events in your application.
|
||||||
use crate::event::{self, Event};
|
use crate::event::{self, Event};
|
||||||
|
use crate::window;
|
||||||
use crate::Hasher;
|
use crate::Hasher;
|
||||||
|
|
||||||
use iced_futures::futures::{self, Future, Stream};
|
use iced_futures::futures::{self, Future, Stream};
|
||||||
|
|
@ -33,7 +34,7 @@ pub type Tracker =
|
||||||
|
|
||||||
pub use iced_futures::subscription::Recipe;
|
pub use iced_futures::subscription::Recipe;
|
||||||
|
|
||||||
/// Returns a [`Subscription`] to all the runtime events.
|
/// Returns a [`Subscription`] to all the ignored runtime events.
|
||||||
///
|
///
|
||||||
/// This subscription will notify your application of any [`Event`] that was
|
/// This subscription will notify your application of any [`Event`] that was
|
||||||
/// not captured by any widget.
|
/// not captured by any widget.
|
||||||
|
|
@ -58,8 +59,36 @@ pub fn events_with<Message>(
|
||||||
where
|
where
|
||||||
Message: 'static + MaybeSend,
|
Message: 'static + MaybeSend,
|
||||||
{
|
{
|
||||||
|
#[derive(Hash)]
|
||||||
|
struct EventsWith;
|
||||||
|
|
||||||
Subscription::from_recipe(Runner {
|
Subscription::from_recipe(Runner {
|
||||||
id: f,
|
id: (EventsWith, f),
|
||||||
|
spawn: move |events| {
|
||||||
|
use futures::future;
|
||||||
|
use futures::stream::StreamExt;
|
||||||
|
|
||||||
|
events.filter_map(move |(event, status)| {
|
||||||
|
future::ready(match event {
|
||||||
|
Event::Window(window::Event::RedrawRequested(_)) => None,
|
||||||
|
_ => f(event, status),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn raw_events<Message>(
|
||||||
|
f: fn(Event, event::Status) -> Option<Message>,
|
||||||
|
) -> Subscription<Message>
|
||||||
|
where
|
||||||
|
Message: 'static + MaybeSend,
|
||||||
|
{
|
||||||
|
#[derive(Hash)]
|
||||||
|
struct RawEvents;
|
||||||
|
|
||||||
|
Subscription::from_recipe(Runner {
|
||||||
|
id: (RawEvents, f),
|
||||||
spawn: move |events| {
|
spawn: move |events| {
|
||||||
use futures::future;
|
use futures::future;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
|
|
@ -155,7 +184,7 @@ where
|
||||||
/// Check out the [`websocket`] example, which showcases this pattern to maintain a WebSocket
|
/// Check out the [`websocket`] example, which showcases this pattern to maintain a WebSocket
|
||||||
/// connection open.
|
/// connection open.
|
||||||
///
|
///
|
||||||
/// [`websocket`]: https://github.com/iced-rs/iced/tree/0.6/examples/websocket
|
/// [`websocket`]: https://github.com/iced-rs/iced/tree/0.7/examples/websocket
|
||||||
pub fn unfold<I, T, Fut, Message>(
|
pub fn unfold<I, T, Fut, Message>(
|
||||||
id: I,
|
id: I,
|
||||||
initial: T,
|
initial: T,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use crate::layout;
|
||||||
use crate::mouse;
|
use crate::mouse;
|
||||||
use crate::renderer;
|
use crate::renderer;
|
||||||
use crate::widget;
|
use crate::widget;
|
||||||
|
use crate::window;
|
||||||
use crate::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size};
|
use crate::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size};
|
||||||
|
|
||||||
/// A set of interactive graphical elements with a specific [`Layout`].
|
/// A set of interactive graphical elements with a specific [`Layout`].
|
||||||
|
|
@ -18,8 +19,8 @@ use crate::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size};
|
||||||
/// The [`integration_opengl`] & [`integration_wgpu`] examples use a
|
/// The [`integration_opengl`] & [`integration_wgpu`] examples use a
|
||||||
/// [`UserInterface`] to integrate Iced in an existing graphical application.
|
/// [`UserInterface`] to integrate Iced in an existing graphical application.
|
||||||
///
|
///
|
||||||
/// [`integration_opengl`]: https://github.com/iced-rs/iced/tree/0.6/examples/integration_opengl
|
/// [`integration_opengl`]: https://github.com/iced-rs/iced/tree/0.7/examples/integration_opengl
|
||||||
/// [`integration_wgpu`]: https://github.com/iced-rs/iced/tree/0.6/examples/integration_wgpu
|
/// [`integration_wgpu`]: https://github.com/iced-rs/iced/tree/0.7/examples/integration_wgpu
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct UserInterface<'a, Message, Renderer> {
|
pub struct UserInterface<'a, Message, Renderer> {
|
||||||
root: Element<'a, Message, Renderer>,
|
root: Element<'a, Message, Renderer>,
|
||||||
|
|
@ -188,7 +189,9 @@ where
|
||||||
) -> (State, Vec<event::Status>) {
|
) -> (State, Vec<event::Status>) {
|
||||||
use std::mem::ManuallyDrop;
|
use std::mem::ManuallyDrop;
|
||||||
|
|
||||||
let mut state = State::Updated;
|
let mut outdated = false;
|
||||||
|
let mut redraw_request = None;
|
||||||
|
|
||||||
let mut manual_overlay =
|
let mut manual_overlay =
|
||||||
ManuallyDrop::new(self.root.as_widget_mut().overlay(
|
ManuallyDrop::new(self.root.as_widget_mut().overlay(
|
||||||
&mut self.state,
|
&mut self.state,
|
||||||
|
|
@ -217,6 +220,16 @@ where
|
||||||
|
|
||||||
event_statuses.push(event_status);
|
event_statuses.push(event_status);
|
||||||
|
|
||||||
|
match (redraw_request, shell.redraw_request()) {
|
||||||
|
(None, Some(at)) => {
|
||||||
|
redraw_request = Some(at);
|
||||||
|
}
|
||||||
|
(Some(current), Some(new)) if new < current => {
|
||||||
|
redraw_request = Some(new);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
if shell.is_layout_invalid() {
|
if shell.is_layout_invalid() {
|
||||||
let _ = ManuallyDrop::into_inner(manual_overlay);
|
let _ = ManuallyDrop::into_inner(manual_overlay);
|
||||||
|
|
||||||
|
|
@ -244,7 +257,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
if shell.are_widgets_invalid() {
|
if shell.are_widgets_invalid() {
|
||||||
state = State::Outdated;
|
outdated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,6 +302,16 @@ where
|
||||||
self.overlay = None;
|
self.overlay = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match (redraw_request, shell.redraw_request()) {
|
||||||
|
(None, Some(at)) => {
|
||||||
|
redraw_request = Some(at);
|
||||||
|
}
|
||||||
|
(Some(current), Some(new)) if new < current => {
|
||||||
|
redraw_request = Some(new);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
shell.revalidate_layout(|| {
|
shell.revalidate_layout(|| {
|
||||||
self.base = renderer.layout(
|
self.base = renderer.layout(
|
||||||
&self.root,
|
&self.root,
|
||||||
|
|
@ -299,14 +322,21 @@ where
|
||||||
});
|
});
|
||||||
|
|
||||||
if shell.are_widgets_invalid() {
|
if shell.are_widgets_invalid() {
|
||||||
state = State::Outdated;
|
outdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
event_status.merge(overlay_status)
|
event_status.merge(overlay_status)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
(state, event_statuses)
|
(
|
||||||
|
if outdated {
|
||||||
|
State::Outdated
|
||||||
|
} else {
|
||||||
|
State::Updated { redraw_request }
|
||||||
|
},
|
||||||
|
event_statuses,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the [`UserInterface`] with the provided [`Renderer`].
|
/// Draws the [`UserInterface`] with the provided [`Renderer`].
|
||||||
|
|
@ -559,5 +589,8 @@ pub enum State {
|
||||||
|
|
||||||
/// The [`UserInterface`] is up-to-date and can be reused without
|
/// The [`UserInterface`] is up-to-date and can be reused without
|
||||||
/// rebuilding.
|
/// rebuilding.
|
||||||
Updated,
|
Updated {
|
||||||
|
/// The [`Instant`] when a redraw should be performed.
|
||||||
|
redraw_request: Option<window::RedrawRequest>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,12 +110,12 @@ use crate::{Clipboard, Layout, Length, Point, Rectangle, Shell};
|
||||||
/// - [`geometry`], a custom widget showcasing how to draw geometry with the
|
/// - [`geometry`], a custom widget showcasing how to draw geometry with the
|
||||||
/// `Mesh2D` primitive in [`iced_wgpu`].
|
/// `Mesh2D` primitive in [`iced_wgpu`].
|
||||||
///
|
///
|
||||||
/// [examples]: https://github.com/iced-rs/iced/tree/0.6/examples
|
/// [examples]: https://github.com/iced-rs/iced/tree/0.7/examples
|
||||||
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.6/examples/bezier_tool
|
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.7/examples/bezier_tool
|
||||||
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.6/examples/custom_widget
|
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.7/examples/custom_widget
|
||||||
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.6/examples/geometry
|
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.7/examples/geometry
|
||||||
/// [`lyon`]: https://github.com/nical/lyon
|
/// [`lyon`]: https://github.com/nical/lyon
|
||||||
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.6/wgpu
|
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.7/wgpu
|
||||||
pub trait Widget<Message, Renderer>
|
pub trait Widget<Message, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: crate::Renderer,
|
Renderer: crate::Renderer,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use crate::widget::Id;
|
||||||
|
|
||||||
use iced_futures::MaybeSend;
|
use iced_futures::MaybeSend;
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// An operation to be performed on the widget tree.
|
/// An operation to be performed on the widget tree.
|
||||||
|
|
@ -84,6 +85,10 @@ where
|
||||||
) {
|
) {
|
||||||
self.operation.focusable(state, id);
|
self.operation.focusable(state, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
|
||||||
|
self.operation.custom(state, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Self { operation, .. } = self;
|
let Self { operation, .. } = self;
|
||||||
|
|
@ -118,6 +123,10 @@ where
|
||||||
self.operation.text_input(state, id);
|
self.operation.text_input(state, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
|
||||||
|
self.operation.custom(state, id);
|
||||||
|
}
|
||||||
|
|
||||||
fn finish(&self) -> operation::Outcome<B> {
|
fn finish(&self) -> operation::Outcome<B> {
|
||||||
match self.operation.finish() {
|
match self.operation.finish() {
|
||||||
operation::Outcome::None => operation::Outcome::None,
|
operation::Outcome::None => operation::Outcome::None,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ pub use text_input::TextInput;
|
||||||
|
|
||||||
use crate::widget::Id;
|
use crate::widget::Id;
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// A piece of logic that can traverse the widget tree of an application in
|
/// A piece of logic that can traverse the widget tree of an application in
|
||||||
|
|
@ -33,6 +34,9 @@ pub trait Operation<T> {
|
||||||
/// 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, _state: &mut dyn TextInput, _id: Option<&Id>) {}
|
||||||
|
|
||||||
|
/// Operates on a custom widget with some state.
|
||||||
|
fn custom(&mut self, _state: &mut dyn Any, _id: Option<&Id>) {}
|
||||||
|
|
||||||
/// Finishes the [`Operation`] and returns its [`Outcome`].
|
/// Finishes the [`Operation`] and returns its [`Outcome`].
|
||||||
fn finish(&self) -> Outcome<T> {
|
fn finish(&self) -> Outcome<T> {
|
||||||
Outcome::None
|
Outcome::None
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
|
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
|
||||||
//! drag and drop, and hotkey support.
|
//! drag and drop, and hotkey support.
|
||||||
//!
|
//!
|
||||||
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.6/examples/pane_grid
|
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.7/examples/pane_grid
|
||||||
mod axis;
|
mod axis;
|
||||||
mod configuration;
|
mod configuration;
|
||||||
mod content;
|
mod content;
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,12 @@ use crate::layout;
|
||||||
use crate::mouse::{self, click};
|
use crate::mouse::{self, click};
|
||||||
use crate::renderer;
|
use crate::renderer;
|
||||||
use crate::text::{self, Text};
|
use crate::text::{self, Text};
|
||||||
|
use crate::time::{Duration, Instant};
|
||||||
use crate::touch;
|
use crate::touch;
|
||||||
use crate::widget;
|
use crate::widget;
|
||||||
use crate::widget::operation::{self, Operation};
|
use crate::widget::operation::{self, Operation};
|
||||||
use crate::widget::tree::{self, Tree};
|
use crate::widget::tree::{self, Tree};
|
||||||
|
use crate::window;
|
||||||
use crate::{
|
use crate::{
|
||||||
Clipboard, Color, Command, Element, Layout, Length, Padding, Point,
|
Clipboard, Color, Command, Element, Layout, Length, Padding, Point,
|
||||||
Rectangle, Shell, Size, Vector, Widget,
|
Rectangle, Shell, Size, Vector, Widget,
|
||||||
|
|
@ -425,7 +427,18 @@ where
|
||||||
let state = state();
|
let state = state();
|
||||||
let is_clicked = layout.bounds().contains(cursor_position);
|
let is_clicked = layout.bounds().contains(cursor_position);
|
||||||
|
|
||||||
state.is_focused = is_clicked;
|
state.is_focused = if is_clicked {
|
||||||
|
state.is_focused.or_else(|| {
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
Some(Focus {
|
||||||
|
updated_at: now,
|
||||||
|
now,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
if is_clicked {
|
if is_clicked {
|
||||||
let text_layout = layout.children().next().unwrap();
|
let text_layout = layout.children().next().unwrap();
|
||||||
|
|
@ -541,26 +554,30 @@ where
|
||||||
Event::Keyboard(keyboard::Event::CharacterReceived(c)) => {
|
Event::Keyboard(keyboard::Event::CharacterReceived(c)) => {
|
||||||
let state = state();
|
let state = state();
|
||||||
|
|
||||||
if state.is_focused
|
if let Some(focus) = &mut state.is_focused {
|
||||||
&& state.is_pasting.is_none()
|
if state.is_pasting.is_none()
|
||||||
&& !state.keyboard_modifiers.command()
|
&& !state.keyboard_modifiers.command()
|
||||||
&& !c.is_control()
|
&& !c.is_control()
|
||||||
{
|
{
|
||||||
let mut editor = Editor::new(value, &mut state.cursor);
|
let mut editor = Editor::new(value, &mut state.cursor);
|
||||||
|
|
||||||
editor.insert(c);
|
editor.insert(c);
|
||||||
|
|
||||||
let message = (on_change)(editor.contents());
|
let message = (on_change)(editor.contents());
|
||||||
shell.publish(message);
|
shell.publish(message);
|
||||||
|
|
||||||
return event::Status::Captured;
|
focus.updated_at = Instant::now();
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => {
|
Event::Keyboard(keyboard::Event::KeyPressed { key_code, .. }) => {
|
||||||
let state = state();
|
let state = state();
|
||||||
|
|
||||||
if state.is_focused {
|
if let Some(focus) = &mut state.is_focused {
|
||||||
let modifiers = state.keyboard_modifiers;
|
let modifiers = state.keyboard_modifiers;
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
|
|
||||||
match key_code {
|
match key_code {
|
||||||
keyboard::KeyCode::Enter
|
keyboard::KeyCode::Enter
|
||||||
|
|
@ -721,7 +738,7 @@ where
|
||||||
state.cursor.select_all(value);
|
state.cursor.select_all(value);
|
||||||
}
|
}
|
||||||
keyboard::KeyCode::Escape => {
|
keyboard::KeyCode::Escape => {
|
||||||
state.is_focused = false;
|
state.is_focused = None;
|
||||||
state.is_dragging = false;
|
state.is_dragging = false;
|
||||||
state.is_pasting = None;
|
state.is_pasting = None;
|
||||||
|
|
||||||
|
|
@ -742,7 +759,7 @@ where
|
||||||
Event::Keyboard(keyboard::Event::KeyReleased { key_code, .. }) => {
|
Event::Keyboard(keyboard::Event::KeyReleased { key_code, .. }) => {
|
||||||
let state = state();
|
let state = state();
|
||||||
|
|
||||||
if state.is_focused {
|
if state.is_focused.is_some() {
|
||||||
match key_code {
|
match key_code {
|
||||||
keyboard::KeyCode::V => {
|
keyboard::KeyCode::V => {
|
||||||
state.is_pasting = None;
|
state.is_pasting = None;
|
||||||
|
|
@ -765,6 +782,21 @@ where
|
||||||
|
|
||||||
state.keyboard_modifiers = modifiers;
|
state.keyboard_modifiers = modifiers;
|
||||||
}
|
}
|
||||||
|
Event::Window(window::Event::RedrawRequested(now)) => {
|
||||||
|
let state = state();
|
||||||
|
|
||||||
|
if let Some(focus) = &mut state.is_focused {
|
||||||
|
focus.now = now;
|
||||||
|
|
||||||
|
let millis_until_redraw = CURSOR_BLINK_INTERVAL_MILLIS
|
||||||
|
- (now - focus.updated_at).as_millis()
|
||||||
|
% CURSOR_BLINK_INTERVAL_MILLIS;
|
||||||
|
|
||||||
|
shell.request_redraw(window::RedrawRequest::At(
|
||||||
|
now + Duration::from_millis(millis_until_redraw as u64),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -820,7 +852,7 @@ pub fn draw<Renderer>(
|
||||||
let text = value.to_string();
|
let text = value.to_string();
|
||||||
let size = size.unwrap_or_else(|| renderer.default_size());
|
let size = size.unwrap_or_else(|| renderer.default_size());
|
||||||
|
|
||||||
let (cursor, offset) = if state.is_focused() {
|
let (cursor, offset) = if let Some(focus) = &state.is_focused {
|
||||||
match state.cursor.state(value) {
|
match state.cursor.state(value) {
|
||||||
cursor::State::Index(position) => {
|
cursor::State::Index(position) => {
|
||||||
let (text_value_width, offset) =
|
let (text_value_width, offset) =
|
||||||
|
|
@ -833,7 +865,13 @@ pub fn draw<Renderer>(
|
||||||
font.clone(),
|
font.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
let is_cursor_visible = ((focus.now - focus.updated_at)
|
||||||
|
.as_millis()
|
||||||
|
/ CURSOR_BLINK_INTERVAL_MILLIS)
|
||||||
|
% 2
|
||||||
|
== 0;
|
||||||
|
|
||||||
|
let cursor = if is_cursor_visible {
|
||||||
Some((
|
Some((
|
||||||
renderer::Quad {
|
renderer::Quad {
|
||||||
bounds: Rectangle {
|
bounds: Rectangle {
|
||||||
|
|
@ -847,9 +885,12 @@ pub fn draw<Renderer>(
|
||||||
border_color: Color::TRANSPARENT,
|
border_color: Color::TRANSPARENT,
|
||||||
},
|
},
|
||||||
theme.value_color(style),
|
theme.value_color(style),
|
||||||
)),
|
))
|
||||||
offset,
|
} else {
|
||||||
)
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
(cursor, offset)
|
||||||
}
|
}
|
||||||
cursor::State::Selection { start, end } => {
|
cursor::State::Selection { start, end } => {
|
||||||
let left = start.min(end);
|
let left = start.min(end);
|
||||||
|
|
@ -958,7 +999,7 @@ pub fn mouse_interaction(
|
||||||
/// The state of a [`TextInput`].
|
/// The state of a [`TextInput`].
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
is_focused: bool,
|
is_focused: Option<Focus>,
|
||||||
is_dragging: bool,
|
is_dragging: bool,
|
||||||
is_pasting: Option<Value>,
|
is_pasting: Option<Value>,
|
||||||
last_click: Option<mouse::Click>,
|
last_click: Option<mouse::Click>,
|
||||||
|
|
@ -967,6 +1008,12 @@ pub struct State {
|
||||||
// TODO: Add stateful horizontal scrolling offset
|
// TODO: Add stateful horizontal scrolling offset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Focus {
|
||||||
|
updated_at: Instant,
|
||||||
|
now: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
/// Creates a new [`State`], representing an unfocused [`TextInput`].
|
/// Creates a new [`State`], representing an unfocused [`TextInput`].
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
|
@ -976,7 +1023,7 @@ impl State {
|
||||||
/// Creates a new [`State`], representing a focused [`TextInput`].
|
/// Creates a new [`State`], representing a focused [`TextInput`].
|
||||||
pub fn focused() -> Self {
|
pub fn focused() -> Self {
|
||||||
Self {
|
Self {
|
||||||
is_focused: true,
|
is_focused: None,
|
||||||
is_dragging: false,
|
is_dragging: false,
|
||||||
is_pasting: None,
|
is_pasting: None,
|
||||||
last_click: None,
|
last_click: None,
|
||||||
|
|
@ -987,7 +1034,7 @@ impl State {
|
||||||
|
|
||||||
/// Returns whether the [`TextInput`] is currently focused or not.
|
/// Returns whether the [`TextInput`] is currently focused or not.
|
||||||
pub fn is_focused(&self) -> bool {
|
pub fn is_focused(&self) -> bool {
|
||||||
self.is_focused
|
self.is_focused.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [`Cursor`] of the [`TextInput`].
|
/// Returns the [`Cursor`] of the [`TextInput`].
|
||||||
|
|
@ -997,13 +1044,19 @@ impl State {
|
||||||
|
|
||||||
/// Focuses the [`TextInput`].
|
/// Focuses the [`TextInput`].
|
||||||
pub fn focus(&mut self) {
|
pub fn focus(&mut self) {
|
||||||
self.is_focused = true;
|
let now = Instant::now();
|
||||||
|
|
||||||
|
self.is_focused = Some(Focus {
|
||||||
|
updated_at: now,
|
||||||
|
now,
|
||||||
|
});
|
||||||
|
|
||||||
self.move_cursor_to_end();
|
self.move_cursor_to_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unfocuses the [`TextInput`].
|
/// Unfocuses the [`TextInput`].
|
||||||
pub fn unfocus(&mut self) {
|
pub fn unfocus(&mut self) {
|
||||||
self.is_focused = false;
|
self.is_focused = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the [`Cursor`] of the [`TextInput`] to the front of the input text.
|
/// Moves the [`Cursor`] of the [`TextInput`] to the front of the input text.
|
||||||
|
|
@ -1156,3 +1209,5 @@ where
|
||||||
)
|
)
|
||||||
.map(text::Hit::cursor)
|
.map(text::Hit::cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CURSOR_BLINK_INTERVAL_MILLIS: u128 = 500;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ mod id;
|
||||||
mod mode;
|
mod mode;
|
||||||
mod position;
|
mod position;
|
||||||
mod settings;
|
mod settings;
|
||||||
|
mod redraw_request;
|
||||||
mod user_attention;
|
mod user_attention;
|
||||||
|
|
||||||
pub use action::Action;
|
pub use action::Action;
|
||||||
|
|
@ -15,4 +16,23 @@ pub use id::Id;
|
||||||
pub use mode::Mode;
|
pub use mode::Mode;
|
||||||
pub use position::Position;
|
pub use position::Position;
|
||||||
pub use settings::Settings;
|
pub use settings::Settings;
|
||||||
|
pub use redraw_request::RedrawRequest;
|
||||||
pub use user_attention::UserAttention;
|
pub use user_attention::UserAttention;
|
||||||
|
|
||||||
|
use crate::subscription::{self, Subscription};
|
||||||
|
use crate::time::Instant;
|
||||||
|
|
||||||
|
/// Subscribes to the frames of the window of the running application.
|
||||||
|
///
|
||||||
|
/// The resulting [`Subscription`] will produce items at a rate equal to the
|
||||||
|
/// refresh rate of the window. Note that this rate may be variable, as it is
|
||||||
|
/// normally managed by the graphics driver and/or the OS.
|
||||||
|
///
|
||||||
|
/// In any case, this [`Subscription`] is useful to smoothly draw application-driven
|
||||||
|
/// animations without missing any frames.
|
||||||
|
pub fn frames() -> Subscription<Instant> {
|
||||||
|
subscription::raw_events(|event, _status| match event {
|
||||||
|
crate::Event::Window(Event::RedrawRequested(at)) => Some(at),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::time::Instant;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// A window-related event.
|
/// A window-related event.
|
||||||
|
|
@ -19,6 +21,11 @@ pub enum Event {
|
||||||
height: u32,
|
height: u32,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// A window redraw was requested.
|
||||||
|
///
|
||||||
|
/// The [`Instant`] contains the current time.
|
||||||
|
RedrawRequested(Instant),
|
||||||
|
|
||||||
/// The user has requested for the window to close.
|
/// The user has requested for the window to close.
|
||||||
///
|
///
|
||||||
/// Usually, you will want to terminate the execution whenever this event
|
/// Usually, you will want to terminate the execution whenever this event
|
||||||
|
|
|
||||||
38
native/src/window/redraw_request.rs
Normal file
38
native/src/window/redraw_request.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
use crate::time::Instant;
|
||||||
|
|
||||||
|
/// A request to redraw a window.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum RedrawRequest {
|
||||||
|
/// Redraw the next frame.
|
||||||
|
NextFrame,
|
||||||
|
|
||||||
|
/// Redraw at the given time.
|
||||||
|
At(Instant),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ordering() {
|
||||||
|
let now = Instant::now();
|
||||||
|
let later = now + Duration::from_millis(10);
|
||||||
|
|
||||||
|
assert_eq!(RedrawRequest::NextFrame, RedrawRequest::NextFrame);
|
||||||
|
assert_eq!(RedrawRequest::At(now), RedrawRequest::At(now));
|
||||||
|
|
||||||
|
assert!(RedrawRequest::NextFrame < RedrawRequest::At(now));
|
||||||
|
assert!(RedrawRequest::At(now) > RedrawRequest::NextFrame);
|
||||||
|
assert!(RedrawRequest::At(now) < RedrawRequest::At(later));
|
||||||
|
assert!(RedrawRequest::At(later) > RedrawRequest::At(now));
|
||||||
|
|
||||||
|
assert!(RedrawRequest::NextFrame <= RedrawRequest::NextFrame);
|
||||||
|
assert!(RedrawRequest::NextFrame <= RedrawRequest::At(now));
|
||||||
|
assert!(RedrawRequest::At(now) >= RedrawRequest::NextFrame);
|
||||||
|
assert!(RedrawRequest::At(now) <= RedrawRequest::At(now));
|
||||||
|
assert!(RedrawRequest::At(now) <= RedrawRequest::At(later));
|
||||||
|
assert!(RedrawRequest::At(later) >= RedrawRequest::At(now));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -39,15 +39,15 @@ pub use iced_native::application::{Appearance, StyleSheet};
|
||||||
/// to listen to time.
|
/// to listen to time.
|
||||||
/// - [`todos`], a todos tracker inspired by [TodoMVC].
|
/// - [`todos`], a todos tracker inspired by [TodoMVC].
|
||||||
///
|
///
|
||||||
/// [The repository has a bunch of examples]: https://github.com/iced-rs/iced/tree/0.6/examples
|
/// [The repository has a bunch of examples]: https://github.com/iced-rs/iced/tree/0.7/examples
|
||||||
/// [`clock`]: https://github.com/iced-rs/iced/tree/0.6/examples/clock
|
/// [`clock`]: https://github.com/iced-rs/iced/tree/0.7/examples/clock
|
||||||
/// [`download_progress`]: https://github.com/iced-rs/iced/tree/0.6/examples/download_progress
|
/// [`download_progress`]: https://github.com/iced-rs/iced/tree/0.7/examples/download_progress
|
||||||
/// [`events`]: https://github.com/iced-rs/iced/tree/0.6/examples/events
|
/// [`events`]: https://github.com/iced-rs/iced/tree/0.7/examples/events
|
||||||
/// [`game_of_life`]: https://github.com/iced-rs/iced/tree/0.6/examples/game_of_life
|
/// [`game_of_life`]: https://github.com/iced-rs/iced/tree/0.7/examples/game_of_life
|
||||||
/// [`pokedex`]: https://github.com/iced-rs/iced/tree/0.6/examples/pokedex
|
/// [`pokedex`]: https://github.com/iced-rs/iced/tree/0.7/examples/pokedex
|
||||||
/// [`solar_system`]: https://github.com/iced-rs/iced/tree/0.6/examples/solar_system
|
/// [`solar_system`]: https://github.com/iced-rs/iced/tree/0.7/examples/solar_system
|
||||||
/// [`stopwatch`]: https://github.com/iced-rs/iced/tree/0.6/examples/stopwatch
|
/// [`stopwatch`]: https://github.com/iced-rs/iced/tree/0.7/examples/stopwatch
|
||||||
/// [`todos`]: https://github.com/iced-rs/iced/tree/0.6/examples/todos
|
/// [`todos`]: https://github.com/iced-rs/iced/tree/0.7/examples/todos
|
||||||
/// [`Sandbox`]: crate::Sandbox
|
/// [`Sandbox`]: crate::Sandbox
|
||||||
/// [`Canvas`]: crate::widget::Canvas
|
/// [`Canvas`]: crate::widget::Canvas
|
||||||
/// [PokéAPI]: https://pokeapi.co/
|
/// [PokéAPI]: https://pokeapi.co/
|
||||||
|
|
@ -180,13 +180,6 @@ pub trait Application: Sized {
|
||||||
1.0
|
1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the [`Application`] should be terminated.
|
|
||||||
///
|
|
||||||
/// By default, it returns `false`.
|
|
||||||
fn should_exit(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs the [`Application`].
|
/// Runs the [`Application`].
|
||||||
///
|
///
|
||||||
/// On native platforms, this method will take control of the current thread
|
/// On native platforms, this method will take control of the current thread
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,13 @@
|
||||||
//! [scrollables]: https://gfycat.com/perkybaggybaboon-rust-gui
|
//! [scrollables]: https://gfycat.com/perkybaggybaboon-rust-gui
|
||||||
//! [Debug overlay with performance metrics]: https://gfycat.com/incredibledarlingbee
|
//! [Debug overlay with performance metrics]: https://gfycat.com/incredibledarlingbee
|
||||||
//! [Modular ecosystem]: https://github.com/iced-rs/iced/blob/master/ECOSYSTEM.md
|
//! [Modular ecosystem]: https://github.com/iced-rs/iced/blob/master/ECOSYSTEM.md
|
||||||
//! [renderer-agnostic native runtime]: https://github.com/iced-rs/iced/tree/0.6/native
|
//! [renderer-agnostic native runtime]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
|
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
|
||||||
//! [built-in renderer]: https://github.com/iced-rs/iced/tree/0.6/wgpu
|
//! [built-in renderer]: https://github.com/iced-rs/iced/tree/0.7/wgpu
|
||||||
//! [windowing shell]: https://github.com/iced-rs/iced/tree/0.6/winit
|
//! [windowing shell]: https://github.com/iced-rs/iced/tree/0.7/winit
|
||||||
//! [`dodrio`]: https://github.com/fitzgen/dodrio
|
//! [`dodrio`]: https://github.com/fitzgen/dodrio
|
||||||
//! [web runtime]: https://github.com/iced-rs/iced_web
|
//! [web runtime]: https://github.com/iced-rs/iced_web
|
||||||
//! [examples]: https://github.com/iced-rs/iced/tree/0.6/examples
|
//! [examples]: https://github.com/iced-rs/iced/tree/0.7/examples
|
||||||
//! [repository]: https://github.com/iced-rs/iced
|
//! [repository]: https://github.com/iced-rs/iced
|
||||||
//!
|
//!
|
||||||
//! # Overview
|
//! # Overview
|
||||||
|
|
@ -97,6 +97,7 @@
|
||||||
//! text(self.value).size(50),
|
//! text(self.value).size(50),
|
||||||
//!
|
//!
|
||||||
//! // The decrement button. We tell it to produce a
|
//! // The decrement button. We tell it to produce a
|
||||||
|
//! // `DecrementPressed` message when pressed
|
||||||
//! button("-").on_press(Message::DecrementPressed),
|
//! button("-").on_press(Message::DecrementPressed),
|
||||||
//! ]
|
//! ]
|
||||||
//! }
|
//! }
|
||||||
|
|
|
||||||
|
|
@ -34,19 +34,19 @@ use crate::{Application, Command, Element, Error, Settings, Subscription};
|
||||||
/// - [`tour`], a simple UI tour that can run both on native platforms and the
|
/// - [`tour`], a simple UI tour that can run both on native platforms and the
|
||||||
/// web!
|
/// web!
|
||||||
///
|
///
|
||||||
/// [The repository has a bunch of examples]: https://github.com/iced-rs/iced/tree/0.6/examples
|
/// [The repository has a bunch of examples]: https://github.com/iced-rs/iced/tree/0.7/examples
|
||||||
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.6/examples/bezier_tool
|
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.7/examples/bezier_tool
|
||||||
/// [`counter`]: https://github.com/iced-rs/iced/tree/0.6/examples/counter
|
/// [`counter`]: https://github.com/iced-rs/iced/tree/0.7/examples/counter
|
||||||
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.6/examples/custom_widget
|
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.7/examples/custom_widget
|
||||||
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.6/examples/geometry
|
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.7/examples/geometry
|
||||||
/// [`pane_grid`]: https://github.com/iced-rs/iced/tree/0.6/examples/pane_grid
|
/// [`pane_grid`]: https://github.com/iced-rs/iced/tree/0.7/examples/pane_grid
|
||||||
/// [`progress_bar`]: https://github.com/iced-rs/iced/tree/0.6/examples/progress_bar
|
/// [`progress_bar`]: https://github.com/iced-rs/iced/tree/0.7/examples/progress_bar
|
||||||
/// [`styling`]: https://github.com/iced-rs/iced/tree/0.6/examples/styling
|
/// [`styling`]: https://github.com/iced-rs/iced/tree/0.7/examples/styling
|
||||||
/// [`svg`]: https://github.com/iced-rs/iced/tree/0.6/examples/svg
|
/// [`svg`]: https://github.com/iced-rs/iced/tree/0.7/examples/svg
|
||||||
/// [`tour`]: https://github.com/iced-rs/iced/tree/0.6/examples/tour
|
/// [`tour`]: https://github.com/iced-rs/iced/tree/0.7/examples/tour
|
||||||
/// [`Canvas widget`]: crate::widget::Canvas
|
/// [`Canvas widget`]: crate::widget::Canvas
|
||||||
/// [the overview]: index.html#overview
|
/// [the overview]: index.html#overview
|
||||||
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.6/wgpu
|
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.7/wgpu
|
||||||
/// [`Svg` widget]: crate::widget::Svg
|
/// [`Svg` widget]: crate::widget::Svg
|
||||||
/// [Ghostscript Tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg
|
/// [Ghostscript Tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg
|
||||||
///
|
///
|
||||||
|
|
@ -140,13 +140,6 @@ pub trait Sandbox {
|
||||||
1.0
|
1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the [`Sandbox`] should be terminated.
|
|
||||||
///
|
|
||||||
/// By default, it returns `false`.
|
|
||||||
fn should_exit(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs the [`Sandbox`].
|
/// Runs the [`Sandbox`].
|
||||||
///
|
///
|
||||||
/// On native platforms, this method will take control of the current thread
|
/// On native platforms, this method will take control of the current thread
|
||||||
|
|
@ -203,8 +196,4 @@ where
|
||||||
fn scale_factor(&self) -> f64 {
|
fn scale_factor(&self) -> f64 {
|
||||||
T::scale_factor(self)
|
T::scale_factor(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_exit(&self) -> bool {
|
|
||||||
T::should_exit(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ pub mod pane_grid {
|
||||||
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
|
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
|
||||||
//! drag and drop, and hotkey support.
|
//! drag and drop, and hotkey support.
|
||||||
//!
|
//!
|
||||||
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.6/examples/pane_grid
|
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.7/examples/pane_grid
|
||||||
pub use iced_native::widget::pane_grid::{
|
pub use iced_native::widget::pane_grid::{
|
||||||
Axis, Configuration, Direction, DragEvent, Line, Node, Pane,
|
Axis, Configuration, Direction, DragEvent, Line, Node, Pane,
|
||||||
ResizeEvent, Split, State, StyleSheet,
|
ResizeEvent, Split, State, StyleSheet,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "iced_style"
|
name = "iced_style"
|
||||||
version = "0.5.1"
|
version = "0.6.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "The default set of styles of Iced"
|
description = "The default set of styles of Iced"
|
||||||
|
|
@ -11,7 +11,7 @@ keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
||||||
categories = ["gui"]
|
categories = ["gui"]
|
||||||
|
|
||||||
[dependencies.iced_core]
|
[dependencies.iced_core]
|
||||||
version = "0.6"
|
version = "0.7"
|
||||||
path = "../core"
|
path = "../core"
|
||||||
features = ["palette"]
|
features = ["palette"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "iced_wgpu"
|
name = "iced_wgpu"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A wgpu renderer for Iced"
|
description = "A wgpu renderer for Iced"
|
||||||
|
|
@ -42,11 +42,11 @@ version = "1.9"
|
||||||
features = ["derive"]
|
features = ["derive"]
|
||||||
|
|
||||||
[dependencies.iced_native]
|
[dependencies.iced_native]
|
||||||
version = "0.7"
|
version = "0.8"
|
||||||
path = "../native"
|
path = "../native"
|
||||||
|
|
||||||
[dependencies.iced_graphics]
|
[dependencies.iced_graphics]
|
||||||
version = "0.5"
|
version = "0.6"
|
||||||
path = "../graphics"
|
path = "../graphics"
|
||||||
features = ["font-fallback", "font-icons"]
|
features = ["font-fallback", "font-icons"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ Currently, `iced_wgpu` supports the following primitives:
|
||||||
Add `iced_wgpu` as a dependency in your `Cargo.toml`:
|
Add `iced_wgpu` as a dependency in your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
iced_wgpu = "0.4"
|
iced_wgpu = "0.8"
|
||||||
```
|
```
|
||||||
|
|
||||||
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
//! - Meshes of triangles, useful to draw geometry freely.
|
//! - Meshes of triangles, useful to draw geometry freely.
|
||||||
//!
|
//!
|
||||||
//! [Iced]: https://github.com/iced-rs/iced
|
//! [Iced]: https://github.com/iced-rs/iced
|
||||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.6/native
|
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
|
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
|
||||||
//! [WebGPU API]: https://gpuweb.github.io/gpuweb/
|
//! [WebGPU API]: https://gpuweb.github.io/gpuweb/
|
||||||
//! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph
|
//! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "iced_winit"
|
name = "iced_winit"
|
||||||
version = "0.6.0"
|
version = "0.7.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A winit runtime for Iced"
|
description = "A winit runtime for Iced"
|
||||||
|
|
@ -29,11 +29,11 @@ git = "https://github.com/iced-rs/winit.git"
|
||||||
rev = "940457522e9fb9f5dac228b0ecfafe0138b4048c"
|
rev = "940457522e9fb9f5dac228b0ecfafe0138b4048c"
|
||||||
|
|
||||||
[dependencies.iced_native]
|
[dependencies.iced_native]
|
||||||
version = "0.7"
|
version = "0.8"
|
||||||
path = "../native"
|
path = "../native"
|
||||||
|
|
||||||
[dependencies.iced_graphics]
|
[dependencies.iced_graphics]
|
||||||
version = "0.5"
|
version = "0.6"
|
||||||
path = "../graphics"
|
path = "../graphics"
|
||||||
|
|
||||||
[dependencies.iced_futures]
|
[dependencies.iced_futures]
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ It exposes a renderer-agnostic `Application` trait that can be implemented and t
|
||||||
Add `iced_winit` as a dependency in your `Cargo.toml`:
|
Add `iced_winit` as a dependency in your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
iced_winit = "0.3"
|
iced_winit = "0.7"
|
||||||
```
|
```
|
||||||
|
|
||||||
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use crate::mouse;
|
||||||
use crate::renderer;
|
use crate::renderer;
|
||||||
use crate::widget::operation;
|
use crate::widget::operation;
|
||||||
use crate::{
|
use crate::{
|
||||||
Command, Debug, Error, Executor, Proxy, Runtime, Settings, Size,
|
Command, Debug, Error, Event, Executor, Proxy, Runtime, Settings, Size,
|
||||||
Subscription,
|
Subscription,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -18,6 +18,7 @@ use iced_futures::futures::channel::mpsc;
|
||||||
use iced_graphics::compositor;
|
use iced_graphics::compositor;
|
||||||
use iced_graphics::window;
|
use iced_graphics::window;
|
||||||
use iced_native::program::Program;
|
use iced_native::program::Program;
|
||||||
|
use iced_native::time::Instant;
|
||||||
use iced_native::user_interface::{self, UserInterface};
|
use iced_native::user_interface::{self, UserInterface};
|
||||||
|
|
||||||
pub use iced_native::application::{Appearance, StyleSheet};
|
pub use iced_native::application::{Appearance, StyleSheet};
|
||||||
|
|
@ -184,7 +185,8 @@ where
|
||||||
|
|
||||||
let (compositor, renderer) = C::new(compositor_settings, Some(&window))?;
|
let (compositor, renderer) = C::new(compositor_settings, Some(&window))?;
|
||||||
|
|
||||||
let (mut sender, receiver) = mpsc::unbounded();
|
let (mut event_sender, event_receiver) = mpsc::unbounded();
|
||||||
|
let (control_sender, mut control_receiver) = mpsc::unbounded();
|
||||||
|
|
||||||
let mut instance = Box::pin({
|
let mut instance = Box::pin({
|
||||||
let run_instance = run_instance::<A, E, C>(
|
let run_instance = run_instance::<A, E, C>(
|
||||||
|
|
@ -194,7 +196,8 @@ where
|
||||||
runtime,
|
runtime,
|
||||||
proxy,
|
proxy,
|
||||||
debug,
|
debug,
|
||||||
receiver,
|
event_receiver,
|
||||||
|
control_sender,
|
||||||
init_command,
|
init_command,
|
||||||
window,
|
window,
|
||||||
settings.exit_on_close_request,
|
settings.exit_on_close_request,
|
||||||
|
|
@ -232,13 +235,19 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(event) = event {
|
if let Some(event) = event {
|
||||||
sender.start_send(event).expect("Send event");
|
event_sender.start_send(event).expect("Send event");
|
||||||
|
|
||||||
let poll = instance.as_mut().poll(&mut context);
|
let poll = instance.as_mut().poll(&mut context);
|
||||||
|
|
||||||
*control_flow = match poll {
|
match poll {
|
||||||
task::Poll::Pending => ControlFlow::Wait,
|
task::Poll::Pending => {
|
||||||
task::Poll::Ready(_) => ControlFlow::Exit,
|
if let Ok(Some(flow)) = control_receiver.try_next() {
|
||||||
|
*control_flow = flow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task::Poll::Ready(_) => {
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -251,7 +260,10 @@ async fn run_instance<A, E, C>(
|
||||||
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
|
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
|
||||||
mut proxy: winit::event_loop::EventLoopProxy<A::Message>,
|
mut proxy: winit::event_loop::EventLoopProxy<A::Message>,
|
||||||
mut debug: Debug,
|
mut debug: Debug,
|
||||||
mut receiver: mpsc::UnboundedReceiver<winit::event::Event<'_, A::Message>>,
|
mut event_receiver: mpsc::UnboundedReceiver<
|
||||||
|
winit::event::Event<'_, A::Message>,
|
||||||
|
>,
|
||||||
|
mut control_sender: mpsc::UnboundedSender<winit::event_loop::ControlFlow>,
|
||||||
init_command: Command<A::Message>,
|
init_command: Command<A::Message>,
|
||||||
window: winit::window::Window,
|
window: winit::window::Window,
|
||||||
exit_on_close_request: bool,
|
exit_on_close_request: bool,
|
||||||
|
|
@ -263,6 +275,7 @@ async fn run_instance<A, E, C>(
|
||||||
{
|
{
|
||||||
use iced_futures::futures::stream::StreamExt;
|
use iced_futures::futures::stream::StreamExt;
|
||||||
use winit::event;
|
use winit::event;
|
||||||
|
use winit::event_loop::ControlFlow;
|
||||||
|
|
||||||
let mut clipboard = Clipboard::connect(&window);
|
let mut clipboard = Clipboard::connect(&window);
|
||||||
let mut cache = user_interface::Cache::default();
|
let mut cache = user_interface::Cache::default();
|
||||||
|
|
@ -307,13 +320,22 @@ async fn run_instance<A, E, C>(
|
||||||
let mut mouse_interaction = mouse::Interaction::default();
|
let mut mouse_interaction = mouse::Interaction::default();
|
||||||
let mut events = Vec::new();
|
let mut events = Vec::new();
|
||||||
let mut messages = Vec::new();
|
let mut messages = Vec::new();
|
||||||
|
let mut redraw_pending = false;
|
||||||
|
|
||||||
debug.startup_finished();
|
debug.startup_finished();
|
||||||
|
|
||||||
while let Some(event) = receiver.next().await {
|
while let Some(event) = event_receiver.next().await {
|
||||||
match event {
|
match event {
|
||||||
|
event::Event::NewEvents(start_cause) => {
|
||||||
|
redraw_pending = matches!(
|
||||||
|
start_cause,
|
||||||
|
event::StartCause::Init
|
||||||
|
| event::StartCause::Poll
|
||||||
|
| event::StartCause::ResumeTimeReached { .. }
|
||||||
|
);
|
||||||
|
}
|
||||||
event::Event::MainEventsCleared => {
|
event::Event::MainEventsCleared => {
|
||||||
if events.is_empty() && messages.is_empty() {
|
if !redraw_pending && events.is_empty() && messages.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -336,7 +358,7 @@ async fn run_instance<A, E, C>(
|
||||||
if !messages.is_empty()
|
if !messages.is_empty()
|
||||||
|| matches!(
|
|| matches!(
|
||||||
interface_state,
|
interface_state,
|
||||||
user_interface::State::Outdated,
|
user_interface::State::Outdated
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
let mut cache =
|
let mut cache =
|
||||||
|
|
@ -374,6 +396,23 @@ async fn run_instance<A, E, C>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Avoid redrawing all the time by forcing widgets to
|
||||||
|
// request redraws on state changes
|
||||||
|
//
|
||||||
|
// Then, we can use the `interface_state` here to decide if a redraw
|
||||||
|
// is needed right away, or simply wait until a specific time.
|
||||||
|
let redraw_event = Event::Window(
|
||||||
|
crate::window::Event::RedrawRequested(Instant::now()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (interface_state, _) = user_interface.update(
|
||||||
|
&[redraw_event.clone()],
|
||||||
|
state.cursor_position(),
|
||||||
|
&mut renderer,
|
||||||
|
&mut clipboard,
|
||||||
|
&mut messages,
|
||||||
|
);
|
||||||
|
|
||||||
debug.draw_started();
|
debug.draw_started();
|
||||||
let new_mouse_interaction = user_interface.draw(
|
let new_mouse_interaction = user_interface.draw(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
|
|
@ -394,6 +433,24 @@ async fn run_instance<A, E, C>(
|
||||||
}
|
}
|
||||||
|
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
|
runtime
|
||||||
|
.broadcast((redraw_event, crate::event::Status::Ignored));
|
||||||
|
|
||||||
|
let _ = control_sender.start_send(match interface_state {
|
||||||
|
user_interface::State::Updated {
|
||||||
|
redraw_request: Some(redraw_request),
|
||||||
|
} => match redraw_request {
|
||||||
|
crate::window::RedrawRequest::NextFrame => {
|
||||||
|
ControlFlow::Poll
|
||||||
|
}
|
||||||
|
crate::window::RedrawRequest::At(at) => {
|
||||||
|
ControlFlow::WaitUntil(at)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => ControlFlow::Wait,
|
||||||
|
});
|
||||||
|
|
||||||
|
redraw_pending = false;
|
||||||
}
|
}
|
||||||
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
|
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
|
||||||
event::MacOS::ReceivedUrl(url),
|
event::MacOS::ReceivedUrl(url),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Convert [`winit`] types into [`iced_native`] types, and viceversa.
|
//! Convert [`winit`] types into [`iced_native`] types, and viceversa.
|
||||||
//!
|
//!
|
||||||
//! [`winit`]: https://github.com/rust-windowing/winit
|
//! [`winit`]: https://github.com/rust-windowing/winit
|
||||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.6/native
|
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
use crate::keyboard;
|
use crate::keyboard;
|
||||||
use crate::mouse;
|
use crate::mouse;
|
||||||
use crate::touch;
|
use crate::touch;
|
||||||
|
|
@ -228,7 +228,7 @@ pub fn mode(mode: Option<winit::window::Fullscreen>) -> window::Mode {
|
||||||
/// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
|
/// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
|
||||||
///
|
///
|
||||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||||
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.6/native
|
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
pub fn mouse_interaction(
|
pub fn mouse_interaction(
|
||||||
interaction: mouse::Interaction,
|
interaction: mouse::Interaction,
|
||||||
) -> winit::window::CursorIcon {
|
) -> winit::window::CursorIcon {
|
||||||
|
|
@ -252,7 +252,7 @@ pub fn mouse_interaction(
|
||||||
/// Converts a `MouseButton` from [`winit`] to an [`iced_native`] mouse button.
|
/// Converts a `MouseButton` from [`winit`] to an [`iced_native`] mouse button.
|
||||||
///
|
///
|
||||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||||
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.6/native
|
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
pub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button {
|
pub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button {
|
||||||
match mouse_button {
|
match mouse_button {
|
||||||
winit::event::MouseButton::Left => mouse::Button::Left,
|
winit::event::MouseButton::Left => mouse::Button::Left,
|
||||||
|
|
@ -268,7 +268,7 @@ pub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button {
|
||||||
/// modifiers state.
|
/// modifiers state.
|
||||||
///
|
///
|
||||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||||
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.6/native
|
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
pub fn modifiers(
|
pub fn modifiers(
|
||||||
modifiers: winit::event::ModifiersState,
|
modifiers: winit::event::ModifiersState,
|
||||||
) -> keyboard::Modifiers {
|
) -> keyboard::Modifiers {
|
||||||
|
|
@ -295,7 +295,7 @@ pub fn cursor_position(
|
||||||
/// Converts a `Touch` from [`winit`] to an [`iced_native`] touch event.
|
/// Converts a `Touch` from [`winit`] to an [`iced_native`] touch event.
|
||||||
///
|
///
|
||||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||||
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.6/native
|
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
pub fn touch_event(
|
pub fn touch_event(
|
||||||
touch: winit::event::Touch,
|
touch: winit::event::Touch,
|
||||||
scale_factor: f64,
|
scale_factor: f64,
|
||||||
|
|
@ -326,7 +326,7 @@ pub fn touch_event(
|
||||||
/// Converts a `VirtualKeyCode` from [`winit`] to an [`iced_native`] key code.
|
/// Converts a `VirtualKeyCode` from [`winit`] to an [`iced_native`] key code.
|
||||||
///
|
///
|
||||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||||
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.6/native
|
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
pub fn key_code(
|
pub fn key_code(
|
||||||
virtual_keycode: winit::event::VirtualKeyCode,
|
virtual_keycode: winit::event::VirtualKeyCode,
|
||||||
) -> keyboard::KeyCode {
|
) -> keyboard::KeyCode {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
//! Additionally, a [`conversion`] module is available for users that decide to
|
//! Additionally, a [`conversion`] module is available for users that decide to
|
||||||
//! implement a custom event loop.
|
//! implement a custom event loop.
|
||||||
//!
|
//!
|
||||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.6/native
|
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.7/native
|
||||||
//! [`winit`]: https://github.com/rust-windowing/winit
|
//! [`winit`]: https://github.com/rust-windowing/winit
|
||||||
//! [`conversion`]: crate::conversion
|
//! [`conversion`]: crate::conversion
|
||||||
#![doc(
|
#![doc(
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
use crate::command::{self, Command};
|
use crate::command::{self, Command};
|
||||||
use iced_native::window;
|
use iced_native::window;
|
||||||
|
|
||||||
pub use window::{Event, Id, Mode, UserAttention};
|
pub use window::{Event, Id, Mode, RedrawRequest, frames, UserAttention};
|
||||||
|
|
||||||
/// Closes the window.
|
/// Closes the window.
|
||||||
pub fn close<Message>(id: window::Id) -> Command<Message> {
|
pub fn close<Message>(id: window::Id) -> Command<Message> {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue