Compare commits

..

No commits in common. "master" and "0.2" have entirely different histories.
master ... 0.2

209 changed files with 1701 additions and 6113 deletions

View File

@ -11,11 +11,6 @@ jobs:
- name: Install cargo-deb
run: cargo install cargo-deb
- uses: actions/checkout@master
- name: Install dependencies
run: |
export DEBIAN_FRONTED=noninteractive
sudo apt-get -qq update
sudo apt-get install -y libxkbcommon-dev
- name: Enable Link Time Optimizations
run: |
echo "[profile.release]" >> Cargo.toml

View File

@ -12,12 +12,6 @@ jobs:
with:
rust-version: ${{ matrix.rust }}
- uses: actions/checkout@master
- name: Install dependencies
if: matrix.os == 'ubuntu-latest'
run: |
export DEBIAN_FRONTED=noninteractive
sudo apt-get -qq update
sudo apt-get install -y libxkbcommon-dev
- name: Run tests
run: |
cargo test --verbose --all
@ -35,5 +29,5 @@ jobs:
run: cargo check --package iced --target wasm32-unknown-unknown
- name: Check compilation of `tour` example
run: cargo build --package tour --target wasm32-unknown-unknown
- name: Check compilation of `todos` example
run: cargo build --package todos --target wasm32-unknown-unknown
- name: Check compilation of `pokedex` example
run: cargo build --package pokedex --target wasm32-unknown-unknown

View File

@ -5,115 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.3.0] - 2021-03-31
### Added
- Touch support. [#57] [#650] (thanks to @simlay and @discordance!)
- Clipboard write access for
- `TextInput` widget. [#770]
- `Application::update`. [#773]
- `image::Viewer` widget. It allows panning and scaling of an image. [#319] (thanks to @tarkah!)
- `Tooltip` widget. It annotates content with some text on mouse hover. [#465] (thanks to @yusdacra!)
- Support for the [`smol`] async runtime. [#699] (thanks to @JayceFayne!)
- Support for graceful exiting when using the `Application` trait. [#804]
- Image format features in [`iced_wgpu`] to reduce code bloat. [#392] (thanks to @unrelentingtech!)
- `Focused` and `Unfocused` variant to `window::Event`. [#701] (thanks to @cossonleo!)
- `WGPU_BACKEND` environment variable to configure the internal graphics backend of `iced_wgpu`. [#789] (thanks to @Cupnfish!)
### Changed
- The `TitleBar` of a `PaneGrid` now supports generic elements. [#657] (thanks to @clarkmoody!)
- The `Error` type now implements `Send` and `Sync`. [#719] (thanks to @taiki-e!)
- The `Style` types in `iced_style` now implement `Clone` and `Copy`. [#720] (thanks to @taiki-e!)
- The following dependencies have been updated:
- [`font-kit`] → `0.10` [#669]
- [`glutin`] → `0.26` [#658]
- [`resvg`] → `0.12` [#669]
- [`tokio`] → `1.0` [#672] (thanks to @yusdacra!)
- [`winit`] → `0.24` [#658]
- [`wgpu`] → `0.7` [#725] (thanks to @PolyMeilex)
- The following examples were improved:
- `download_progress` now showcases multiple file downloads at once. [#283] (thanks to @Folyd!)
- `solar_system` uses the new `rand` API. [#760] (thanks to @TriedAngle!)
### Fixed
- Button events not being propagated to contents. [#668]
- Incorrect overlay implementation for the `Button` widget. [#764]
- `Viewport::physical_width` returning the wrong value. [#700]
- Outdated documentation for the `Sandbox` trait. [#710]
[#57]: https://github.com/hecrj/iced/pull/57
[#283]: https://github.com/hecrj/iced/pull/283
[#319]: https://github.com/hecrj/iced/pull/319
[#392]: https://github.com/hecrj/iced/pull/392
[#465]: https://github.com/hecrj/iced/pull/465
[#650]: https://github.com/hecrj/iced/pull/650
[#657]: https://github.com/hecrj/iced/pull/657
[#658]: https://github.com/hecrj/iced/pull/658
[#668]: https://github.com/hecrj/iced/pull/668
[#669]: https://github.com/hecrj/iced/pull/669
[#672]: https://github.com/hecrj/iced/pull/672
[#699]: https://github.com/hecrj/iced/pull/699
[#700]: https://github.com/hecrj/iced/pull/700
[#701]: https://github.com/hecrj/iced/pull/701
[#710]: https://github.com/hecrj/iced/pull/710
[#719]: https://github.com/hecrj/iced/pull/719
[#720]: https://github.com/hecrj/iced/pull/720
[#725]: https://github.com/hecrj/iced/pull/725
[#760]: https://github.com/hecrj/iced/pull/760
[#764]: https://github.com/hecrj/iced/pull/764
[#770]: https://github.com/hecrj/iced/pull/770
[#773]: https://github.com/hecrj/iced/pull/773
[#789]: https://github.com/hecrj/iced/pull/789
[#804]: https://github.com/hecrj/iced/pull/804
[`smol`]: https://github.com/smol-rs/smol
[`winit`]: https://github.com/rust-windowing/winit
[`glutin`]: https://github.com/rust-windowing/glutin
[`font-kit`]: https://github.com/servo/font-kit
## [0.2.0] - 2020-11-26
### Added
- __[`Canvas` interactivity][canvas]__ (#325)
A trait-based approach to react to mouse and keyboard interactions in [the `Canvas` widget][#193].
- __[`iced_graphics` subcrate][opengl]__ (#354)
A backend-agnostic graphics subcrate that can be leveraged to build new renderers.
- __[OpenGL renderer][opengl]__ (#354)
An OpenGL renderer powered by [`iced_graphics`], [`glow`], and [`glutin`]. It is an alternative to the default [`wgpu`] renderer.
- __[Overlay support][pick_list]__ (#444)
Basic support for superpositioning interactive widgets on top of other widgets.
- __[Faster event loop][view]__ (#597)
The event loop now takes advantage of the data dependencies in [The Elm Architecture] and leverages the borrow checker to keep the widget tree alive between iterations, avoiding unnecessary rebuilds.
- __[Event capturing][event]__ (#614)
The runtime now can tell whether a widget has handled an event or not, easing [integration with existing applications].
- __[`PickList` widget][pick_list]__ (#444)
A drop-down selector widget built on top of the new overlay support.
- __[`QRCode` widget][qr_code]__ (#622)
A widget that displays a QR code, powered by [the `qrcode` crate].
[canvas]: https://github.com/hecrj/iced/pull/325
[opengl]: https://github.com/hecrj/iced/pull/354
[`iced_graphics`]: https://github.com/hecrj/iced/pull/354
[pane_grid]: https://github.com/hecrj/iced/pull/397
[pick_list]: https://github.com/hecrj/iced/pull/444
[error]: https://github.com/hecrj/iced/pull/514
[view]: https://github.com/hecrj/iced/pull/597
[event]: https://github.com/hecrj/iced/pull/614
[color]: https://github.com/hecrj/iced/pull/200
[qr_code]: https://github.com/hecrj/iced/pull/622
[#193]: https://github.com/hecrj/iced/pull/193
[`glutin`]: https://github.com/rust-windowing/glutin
[`wgpu`]: https://github.com/gfx-rs/wgpu-rs
[`glow`]: https://github.com/grovesNL/glow
[the `qrcode` crate]: https://docs.rs/qrcode/0.12.0/qrcode/
[integration with existing applications]: https://github.com/hecrj/iced/pull/183
[The Elm Architecture]: https://guide.elm-lang.org/architecture/
- `"system_font"` feature gates reading system fonts. [#370]
[#370]: https://github.com/hecrj/iced/pull/370
## [0.1.1] - 2020-04-15
### Added
@ -207,7 +102,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[`wasm-bindgen-futures`]: https://github.com/rustwasm/wasm-bindgen/tree/master/crates/futures
[`resvg`]: https://github.com/RazrFalcon/resvg
[`raqote`]: https://github.com/jrmuizel/raqote
[`iced_wgpu`]: https://github.com/hecrj/iced/tree/master/wgpu
[`iced_wgpu`]: https://github.com/hecrj/iced/tree/0.1/wgpu
## [0.1.0-beta] - 2019-11-25
@ -219,9 +114,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- First release! :tada:
[Unreleased]: https://github.com/hecrj/iced/compare/0.3.0...HEAD
[0.3.0]: https://github.com/hecrj/iced/compare/0.2.0...0.3.0
[0.2.0]: https://github.com/hecrj/iced/compare/0.1.1...0.2.0
[Unreleased]: https://github.com/hecrj/iced/compare/0.1.1...HEAD
[0.1.1]: https://github.com/hecrj/iced/compare/0.1.0...0.1.1
[0.1.0]: https://github.com/hecrj/iced/compare/0.1.0-beta...0.1.0
[0.1.0-beta]: https://github.com/hecrj/iced/compare/0.1.0-alpha...0.1.0-beta

View File

@ -1,6 +1,6 @@
[package]
name = "iced"
version = "0.3.0"
version = "0.2.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "A cross-platform GUI library inspired by Elm"
@ -41,8 +41,6 @@ tokio = ["iced_futures/tokio"]
tokio_old = ["iced_futures/tokio_old"]
# Enables `async-std` as the `executor::Default` on native platforms
async-std = ["iced_futures/async-std"]
# Enables `smol` as the `executor::Default` on native platforms
smol = ["iced_futures/smol"]
# Enables advanced color conversion via `palette`
palette = ["iced_core/palette"]
@ -83,25 +81,22 @@ members = [
"examples/svg",
"examples/todos",
"examples/tour",
"examples/tour_glow",
"examples/tooltip",
"examples/url_handler",
]
[dependencies]
iced_core = { version = "0.4", path = "core" }
iced_futures = { version = "0.3", path = "futures" }
iced_core = { version = "0.3", path = "core" }
iced_futures = { version = "0.2", path = "futures" }
thiserror = "1.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
iced_winit = { version = "0.3", path = "winit" }
iced_glutin = { version = "0.2", path = "glutin", optional = true }
iced_wgpu = { version = "0.4", path = "wgpu", optional = true }
iced_glow = { version = "0.2", path = "glow", optional = true}
iced_winit = { version = "0.2", path = "winit" }
iced_glutin = { version = "0.1", path = "glutin", optional = true }
iced_wgpu = { version = "0.3", path = "wgpu", optional = true }
iced_glow = { version = "0.1", path = "glow", optional = true}
[target.'cfg(target_arch = "wasm32")'.dependencies]
iced_web = { version = "0.4", path = "web" }
iced_web = { version = "0.3", path = "web" }
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
features = ["image", "svg", "canvas", "qr_code"]
features = ["image", "svg", "canvas"]

View File

@ -55,7 +55,7 @@ __Iced is currently experimental software.__ [Take a look at the roadmap],
Add `iced` as a dependency in your `Cargo.toml`:
```toml
iced = "0.3"
iced = "0.2"
```
__Iced moves fast and the `master` branch can contain breaking changes!__ If
@ -168,7 +168,7 @@ Browse the [documentation] and the [examples] to learn more!
Iced was originally born as an attempt at bringing the simplicity of [Elm] and
[The Elm Architecture] into [Coffee], a 2D game engine I am working on.
The core of the library was implemented during May 2019 in [this pull request].
The core of the library was implemented during May in [this pull request].
[The first alpha version] was eventually released as
[a renderer-agnostic GUI library]. The library did not provide a renderer and
implemented the current [tour example] on top of [`ggez`], a game library.

View File

@ -1,6 +1,6 @@
[package]
name = "iced_core"
version = "0.4.0"
version = "0.3.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "The essential concepts of Iced"

View File

@ -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`:
```toml
iced_core = "0.4"
iced_core = "0.3"
```
__Iced moves fast and the `master` branch can contain breaking changes!__ If

View File

@ -22,7 +22,6 @@ mod background;
mod color;
mod font;
mod length;
mod padding;
mod point;
mod rectangle;
mod size;
@ -33,7 +32,6 @@ pub use background::Background;
pub use color::Color;
pub use font::Font;
pub use length::Length;
pub use padding::Padding;
pub use point::Point;
pub use rectangle::Rectangle;
pub use size::Size;

View File

@ -1,5 +1,3 @@
use crate::Point;
use super::Button;
/// A mouse event.
@ -18,8 +16,11 @@ pub enum Event {
/// The mouse cursor was moved
CursorMoved {
/// The new position of the mouse cursor
position: Point,
/// The X coordinate of the mouse position
x: f32,
/// The Y coordinate of the mouse position
y: f32,
},
/// A mouse button was pressed.

View File

@ -1,107 +0,0 @@
/// An amount of space to pad for each side of a box
///
/// You can leverage the `From` trait to build [`Padding`] conveniently:
///
/// ```
/// # use iced_core::Padding;
/// #
/// let padding = Padding::from(20); // 20px on all sides
/// let padding = Padding::from([10, 20]); // top/bottom, left/right
/// let padding = Padding::from([5, 10, 15, 20]); // top, right, bottom, left
/// ```
///
/// Normally, the `padding` method of a widget will ask for an `Into<Padding>`,
/// so you can easily write:
///
/// ```
/// # use iced_core::Padding;
/// #
/// # struct Widget;
/// #
/// impl Widget {
/// # pub fn new() -> Self { Self }
/// #
/// pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
/// // ...
/// self
/// }
/// }
///
/// let widget = Widget::new().padding(20); // 20px on all sides
/// let widget = Widget::new().padding([10, 20]); // top/bottom, left/right
/// let widget = Widget::new().padding([5, 10, 15, 20]); // top, right, bottom, left
/// ```
#[derive(Debug, Hash, Copy, Clone)]
pub struct Padding {
/// Top padding
pub top: u16,
/// Right padding
pub right: u16,
/// Bottom padding
pub bottom: u16,
/// Left padding
pub left: u16,
}
impl Padding {
/// Padding of zero
pub const ZERO: Padding = Padding {
top: 0,
right: 0,
bottom: 0,
left: 0,
};
/// Create a Padding that is equal on all sides
pub const fn new(padding: u16) -> Padding {
Padding {
top: padding,
right: padding,
bottom: padding,
left: padding,
}
}
/// Returns the total amount of vertical [`Padding`].
pub fn vertical(self) -> u16 {
self.top + self.bottom
}
/// Returns the total amount of horizontal [`Padding`].
pub fn horizontal(self) -> u16 {
self.left + self.right
}
}
impl std::convert::From<u16> for Padding {
fn from(p: u16) -> Self {
Padding {
top: p,
right: p,
bottom: p,
left: p,
}
}
}
impl std::convert::From<[u16; 2]> for Padding {
fn from(p: [u16; 2]) -> Self {
Padding {
top: p[0],
right: p[1],
bottom: p[0],
left: p[1],
}
}
}
impl std::convert::From<[u16; 4]> for Padding {
fn from(p: [u16; 4]) -> Self {
Padding {
top: p[0],
right: p[1],
bottom: p[2],
left: p[3],
}
}
}

View File

@ -105,8 +105,8 @@ impl Rectangle<f32> {
Rectangle {
x: self.x as u32,
y: self.y as u32,
width: self.width as u32,
height: self.height as u32,
width: self.width.ceil() as u32,
height: self.height.ceil() as u32,
}
}
}

View File

@ -1,4 +1,4 @@
use crate::{Padding, Vector};
use crate::Vector;
use std::f32;
/// An amount of space in 2 dimensions.
@ -28,10 +28,10 @@ impl Size {
pub const INFINITY: Size = Size::new(f32::INFINITY, f32::INFINITY);
/// Increments the [`Size`] to account for the given padding.
pub fn pad(&self, padding: Padding) -> Self {
pub fn pad(&self, padding: f32) -> Self {
Size {
width: self.width + padding.horizontal() as f32,
height: self.height + padding.vertical() as f32,
width: self.width + padding * 2.0,
height: self.height + padding * 2.0,
}
}
}

View File

@ -118,7 +118,7 @@ cargo run --package <example>
[Ghostscript Tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg
## [Coffee]
Since [Iced was born in May 2019], it has been powering the user interfaces in
Since [Iced was born in May], it has been powering the user interfaces in
[Coffee], an experimental 2D game engine.
@ -128,6 +128,6 @@ Since [Iced was born in May 2019], it has been powering the user interfaces in
</a>
</div>
[Iced was born in May 2019]: https://github.com/hecrj/coffee/pull/35
[Iced was born in May]: https://github.com/hecrj/coffee/pull/35
[`ui` module]: https://docs.rs/coffee/0.3.2/coffee/ui/index.html
[Coffee]: https://github.com/hecrj/coffee

View File

@ -1,7 +1,7 @@
use iced::{
canvas::{self, Cache, Canvas, Cursor, Geometry, LineCap, Path, Stroke},
executor, time, Application, Clipboard, Color, Command, Container, Element,
Length, Point, Rectangle, Settings, Subscription, Vector,
executor, time, Application, Color, Command, Container, Element, Length,
Point, Rectangle, Settings, Subscription, Vector,
};
pub fn main() -> iced::Result {
@ -40,11 +40,7 @@ impl Application for Clock {
String::from("Clock - Iced")
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Tick(local_time) => {
let now = local_time;

View File

@ -1,12 +1,12 @@
[package]
name = "download_progress"
version = "0.1.0"
authors = ["Songtronix <contact@songtronix.com>", "Folyd <lyshuhow@gmail.com>"]
authors = ["Songtronix <contact@songtronix.com>"]
edition = "2018"
publish = false
[dependencies]
iced = { path = "../..", features = ["tokio"] }
iced = { path = "../..", features = ["tokio_old"] }
iced_native = { path = "../../native" }
iced_futures = { path = "../../futures" }
reqwest = "0.11"
reqwest = "0.10"

View File

@ -1,6 +1,6 @@
## Download progress
A basic application that asynchronously downloads multiple dummy files of 100 MB and tracks the download progress.
A basic application that asynchronously downloads a dummy file of 100 MB and tracks the download progress.
The example implements a custom `Subscription` in the __[`download`](src/download.rs)__ module. This subscription downloads and produces messages that can be used to keep track of its progress.

View File

@ -1,46 +1,37 @@
use iced_futures::futures;
use std::hash::{Hash, Hasher};
// Just a little utility function
pub fn file<I: 'static + Hash + Copy + Send, T: ToString>(
id: I,
url: T,
) -> iced::Subscription<(I, Progress)> {
pub fn file<T: ToString>(url: T) -> iced::Subscription<Progress> {
iced::Subscription::from_recipe(Download {
id,
url: url.to_string(),
})
}
pub struct Download<I> {
id: I,
pub struct Download {
url: String,
}
// Make sure iced can use our download stream
impl<H, I, T> iced_native::subscription::Recipe<H, I> for Download<T>
impl<H, I> iced_native::subscription::Recipe<H, I> for Download
where
T: 'static + Hash + Copy + Send,
H: Hasher,
H: std::hash::Hasher,
{
type Output = (T, Progress);
type Output = Progress;
fn hash(&self, state: &mut H) {
struct Marker;
std::any::TypeId::of::<Marker>().hash(state);
use std::hash::Hash;
self.id.hash(state);
std::any::TypeId::of::<Self>().hash(state);
self.url.hash(state);
}
fn stream(
self: Box<Self>,
_input: futures::stream::BoxStream<'static, I>,
) -> futures::stream::BoxStream<'static, Self::Output> {
let id = self.id;
Box::pin(futures::stream::unfold(
State::Ready(self.url),
move |state| async move {
|state| async move {
match state {
State::Ready(url) => {
let response = reqwest::get(&url).await;
@ -49,7 +40,7 @@ where
Ok(response) => {
if let Some(total) = response.content_length() {
Some((
(id, Progress::Started),
Progress::Started,
State::Downloading {
response,
total,
@ -57,14 +48,11 @@ where
},
))
} else {
Some((
(id, Progress::Errored),
State::Finished,
))
Some((Progress::Errored, State::Finished))
}
}
Err(_) => {
Some(((id, Progress::Errored), State::Finished))
Some((Progress::Errored, State::Finished))
}
}
}
@ -80,7 +68,7 @@ where
(downloaded as f32 / total as f32) * 100.0;
Some((
(id, Progress::Advanced(percentage)),
Progress::Advanced(percentage),
State::Downloading {
response,
total,
@ -88,12 +76,8 @@ where
},
))
}
Ok(None) => {
Some(((id, Progress::Finished), State::Finished))
}
Err(_) => {
Some(((id, Progress::Errored), State::Finished))
}
Ok(None) => Some((Progress::Finished, State::Finished)),
Err(_) => Some((Progress::Errored, State::Finished)),
},
State::Finished => {
// We do not let the stream die, as it would start a

View File

@ -1,6 +1,6 @@
use iced::{
button, executor, Align, Application, Button, Clipboard, Column, Command,
Container, Element, Length, ProgressBar, Settings, Subscription, Text,
button, executor, Align, Application, Button, Column, Command, Container,
Element, Length, ProgressBar, Settings, Subscription, Text,
};
mod download;
@ -10,17 +10,17 @@ pub fn main() -> iced::Result {
}
#[derive(Debug)]
struct Example {
downloads: Vec<Download>,
last_id: usize,
add: button::State,
enum Example {
Idle { button: button::State },
Downloading { progress: f32 },
Finished { button: button::State },
Errored { button: button::State },
}
#[derive(Debug, Clone)]
pub enum Message {
Add,
Download(usize),
DownloadProgressed((usize, download::Progress)),
Download,
DownloadProgressed(download::Progress),
}
impl Application for Example {
@ -30,10 +30,8 @@ impl Application for Example {
fn new(_flags: ()) -> (Example, Command<Message>) {
(
Example {
downloads: vec![Download::new(0)],
last_id: 0,
add: button::State::new(),
Example::Idle {
button: button::State::new(),
},
Command::none(),
)
@ -43,100 +41,18 @@ impl Application for Example {
String::from("Download progress - Iced")
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Add => {
self.last_id = self.last_id + 1;
self.downloads.push(Download::new(self.last_id));
}
Message::Download(index) => {
if let Some(download) = self.downloads.get_mut(index) {
download.start();
}
}
Message::DownloadProgressed((id, progress)) => {
if let Some(download) =
self.downloads.iter_mut().find(|download| download.id == id)
{
download.progress(progress);
}
}
};
Command::none()
}
fn subscription(&self) -> Subscription<Message> {
Subscription::batch(self.downloads.iter().map(Download::subscription))
}
fn view(&mut self) -> Element<Message> {
let downloads = self
.downloads
.iter_mut()
.fold(Column::new().spacing(20), |column, download| {
column.push(download.view())
})
.push(
Button::new(&mut self.add, Text::new("Add another download"))
.on_press(Message::Add)
.padding(10),
)
.align_items(Align::End);
Container::new(downloads)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.padding(20)
.into()
}
}
#[derive(Debug)]
struct Download {
id: usize,
state: State,
}
#[derive(Debug)]
enum State {
Idle { button: button::State },
Downloading { progress: f32 },
Finished { button: button::State },
Errored { button: button::State },
}
impl Download {
pub fn new(id: usize) -> Self {
Download {
id,
state: State::Idle {
button: button::State::new(),
},
}
}
pub fn start(&mut self) {
match self.state {
State::Idle { .. }
| State::Finished { .. }
| State::Errored { .. } => {
self.state = State::Downloading { progress: 0.0 };
Message::Download => match self {
Example::Idle { .. }
| Example::Finished { .. }
| Example::Errored { .. } => {
*self = Example::Downloading { progress: 0.0 };
}
_ => {}
}
}
pub fn progress(&mut self, new_progress: download::Progress) {
match &mut self.state {
State::Downloading { progress } => match new_progress {
},
Message::DownloadProgressed(message) => match self {
Example::Downloading { progress } => match message {
download::Progress::Started => {
*progress = 0.0;
}
@ -144,76 +60,85 @@ impl Download {
*progress = percentage;
}
download::Progress::Finished => {
self.state = State::Finished {
*self = Example::Finished {
button: button::State::new(),
}
}
download::Progress::Errored => {
self.state = State::Errored {
*self = Example::Errored {
button: button::State::new(),
};
}
},
_ => {}
}
},
};
Command::none()
}
pub fn subscription(&self) -> Subscription<Message> {
match self.state {
State::Downloading { .. } => {
download::file(self.id, "https://speed.hetzner.de/100MB.bin?")
fn subscription(&self) -> Subscription<Message> {
match self {
Example::Downloading { .. } => {
download::file("https://speed.hetzner.de/100MB.bin")
.map(Message::DownloadProgressed)
}
_ => Subscription::none(),
}
}
pub fn view(&mut self) -> Element<Message> {
let current_progress = match &self.state {
State::Idle { .. } => 0.0,
State::Downloading { progress } => *progress,
State::Finished { .. } => 100.0,
State::Errored { .. } => 0.0,
fn view(&mut self) -> Element<Message> {
let current_progress = match self {
Example::Idle { .. } => 0.0,
Example::Downloading { progress } => *progress,
Example::Finished { .. } => 100.0,
Example::Errored { .. } => 0.0,
};
let progress_bar = ProgressBar::new(0.0..=100.0, current_progress);
let control: Element<_> = match &mut self.state {
State::Idle { button } => {
let control: Element<_> = match self {
Example::Idle { button } => {
Button::new(button, Text::new("Start the download!"))
.on_press(Message::Download(self.id))
.on_press(Message::Download)
.into()
}
State::Finished { button } => Column::new()
Example::Finished { button } => Column::new()
.spacing(10)
.align_items(Align::Center)
.push(Text::new("Download finished!"))
.push(
Button::new(button, Text::new("Start again"))
.on_press(Message::Download(self.id)),
.on_press(Message::Download),
)
.into(),
State::Downloading { .. } => {
Example::Downloading { .. } => {
Text::new(format!("Downloading... {:.2}%", current_progress))
.into()
}
State::Errored { button } => Column::new()
Example::Errored { button } => Column::new()
.spacing(10)
.align_items(Align::Center)
.push(Text::new("Something went wrong :("))
.push(
Button::new(button, Text::new("Try again"))
.on_press(Message::Download(self.id)),
.on_press(Message::Download),
)
.into(),
};
Column::new()
let content = Column::new()
.spacing(10)
.padding(10)
.align_items(Align::Center)
.push(progress_bar)
.push(control)
.push(control);
Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
}

View File

@ -1,30 +1,22 @@
use iced::{
button, executor, Align, Application, Button, Checkbox, Clipboard, Column,
Command, Container, Element, HorizontalAlignment, Length, Settings,
Subscription, Text,
executor, Align, Application, Checkbox, Column, Command, Container,
Element, Length, Settings, Subscription, Text,
};
use iced_native::{window, Event};
pub fn main() -> iced::Result {
Events::run(Settings {
exit_on_close_request: false,
..Settings::default()
})
Events::run(Settings::default())
}
#[derive(Debug, Default)]
struct Events {
last: Vec<iced_native::Event>,
enabled: bool,
exit: button::State,
should_exit: bool,
}
#[derive(Debug, Clone)]
enum Message {
EventOccurred(iced_native::Event),
Toggled(bool),
Exit,
}
impl Application for Events {
@ -40,41 +32,29 @@ impl Application for Events {
String::from("Events - Iced")
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::EventOccurred(event) if self.enabled => {
Message::EventOccurred(event) => {
self.last.push(event);
if self.last.len() > 5 {
let _ = self.last.remove(0);
}
}
Message::EventOccurred(event) => {
if let Event::Window(window::Event::CloseRequested) = event {
self.should_exit = true;
}
}
Message::Toggled(enabled) => {
self.enabled = enabled;
}
Message::Exit => {
self.should_exit = true;
}
};
Command::none()
}
fn subscription(&self) -> Subscription<Message> {
if self.enabled {
iced_native::subscription::events().map(Message::EventOccurred)
} else {
Subscription::none()
}
fn should_exit(&self) -> bool {
self.should_exit
}
fn view(&mut self) -> Element<Message> {
@ -91,22 +71,11 @@ impl Application for Events {
Message::Toggled,
);
let exit = Button::new(
&mut self.exit,
Text::new("Exit")
.width(Length::Fill)
.horizontal_alignment(HorizontalAlignment::Center),
)
.width(Length::Units(100))
.padding(10)
.on_press(Message::Exit);
let content = Column::new()
.align_items(Align::Center)
.spacing(20)
.push(events)
.push(toggle)
.push(exit);
.push(toggle);
Container::new(content)
.width(Length::Fill)

View File

@ -7,6 +7,6 @@ publish = false
[dependencies]
iced = { path = "../..", features = ["canvas", "tokio", "debug"] }
tokio = { version = "1.0", features = ["sync"] }
tokio = { version = "0.3", features = ["sync"] }
itertools = "0.9"
rustc-hash = "1.1"

View File

@ -10,8 +10,8 @@ use iced::pick_list::{self, PickList};
use iced::slider::{self, Slider};
use iced::time;
use iced::{
Align, Application, Checkbox, Clipboard, Column, Command, Container,
Element, Length, Row, Settings, Subscription, Text,
Align, Application, Checkbox, Column, Command, Container, Element, Length,
Row, Settings, Subscription, Text,
};
use preset::Preset;
use std::time::{Duration, Instant};
@ -65,11 +65,7 @@ impl Application for GameOfLife {
String::from("Game of Life - Iced")
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Grid(message, version) => {
if version == self.version {

View File

@ -1,7 +1,7 @@
use iced_wgpu::Renderer;
use iced_winit::{
slider, Align, Clipboard, Color, Column, Command, Element, Length, Program,
Row, Slider, Text,
slider, Align, Color, Column, Command, Element, Length, Program, Row,
Slider, Text,
};
pub struct Controls {
@ -30,13 +30,8 @@ impl Controls {
impl Program for Controls {
type Renderer = Renderer;
type Message = Message;
type Clipboard = Clipboard;
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::BackgroundColorChanged(color) => {
self.background_color = color;

View File

@ -5,7 +5,7 @@ use controls::Controls;
use scene::Scene;
use iced_wgpu::{wgpu, Backend, Renderer, Settings, Viewport};
use iced_winit::{conversion, futures, program, winit, Clipboard, Debug, Size};
use iced_winit::{conversion, futures, program, winit, Debug, Size};
use futures::task::SpawnExt;
use winit::{
@ -28,7 +28,6 @@ pub fn main() {
);
let mut cursor_position = PhysicalPosition::new(-1.0, -1.0);
let mut modifiers = ModifiersState::default();
let mut clipboard = Clipboard::connect(&window);
// Initialize wgpu
let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY);
@ -37,7 +36,7 @@ pub fn main() {
let (mut device, queue) = futures::executor::block_on(async {
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
power_preference: wgpu::PowerPreference::Default,
compatible_surface: Some(&surface),
})
.await
@ -46,9 +45,9 @@ pub fn main() {
adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
features: wgpu::Features::empty(),
limits: wgpu::Limits::default(),
shader_validation: false,
},
None,
)
@ -64,7 +63,7 @@ pub fn main() {
device.create_swap_chain(
&surface,
&wgpu::SwapChainDescriptor {
usage: wgpu::TextureUsage::RENDER_ATTACHMENT,
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
format: format,
width: size.width,
height: size.height,
@ -142,8 +141,8 @@ pub fn main() {
cursor_position,
viewport.scale_factor(),
),
None,
&mut renderer,
&mut clipboard,
&mut debug,
);
@ -158,7 +157,7 @@ pub fn main() {
swap_chain = device.create_swap_chain(
&surface,
&wgpu::SwapChainDescriptor {
usage: wgpu::TextureUsage::RENDER_ATTACHMENT,
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
format: format,
width: size.width,
height: size.height,

View File

@ -19,9 +19,8 @@ impl Scene {
background_color: Color,
) -> wgpu::RenderPass<'a> {
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
view: target,
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: target,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear({
@ -49,10 +48,10 @@ impl Scene {
fn build_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline {
let vs_module =
device.create_shader_module(&wgpu::include_spirv!("shader/vert.spv"));
device.create_shader_module(wgpu::include_spirv!("shader/vert.spv"));
let fs_module =
device.create_shader_module(&wgpu::include_spirv!("shader/frag.spv"));
device.create_shader_module(wgpu::include_spirv!("shader/frag.spv"));
let pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
@ -65,34 +64,34 @@ fn build_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline {
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: None,
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
vertex_stage: wgpu::ProgrammableStageDescriptor {
module: &vs_module,
entry_point: "main",
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
fragment_stage: Some(wgpu::ProgrammableStageDescriptor {
module: &fs_module,
entry_point: "main",
targets: &[wgpu::ColorTargetState {
format: wgpu::TextureFormat::Bgra8UnormSrgb,
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent::REPLACE,
alpha: wgpu::BlendComponent::REPLACE,
}),
rasterization_state: Some(wgpu::RasterizationStateDescriptor {
front_face: wgpu::FrontFace::Ccw,
cull_mode: wgpu::CullMode::None,
..Default::default()
}),
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
color_states: &[wgpu::ColorStateDescriptor {
format: wgpu::TextureFormat::Bgra8UnormSrgb,
color_blend: wgpu::BlendDescriptor::REPLACE,
alpha_blend: wgpu::BlendDescriptor::REPLACE,
write_mask: wgpu::ColorWrite::ALL,
}],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
front_face: wgpu::FrontFace::Ccw,
..Default::default()
depth_stencil_state: None,
vertex_state: wgpu::VertexStateDescriptor {
index_format: wgpu::IndexFormat::Uint16,
vertex_buffers: &[],
},
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
sample_count: 1,
sample_mask: !0,
alpha_to_coverage_enabled: false,
},
});
pipeline

View File

@ -1,8 +1,7 @@
use iced::{
button, executor, keyboard, pane_grid, scrollable, Align, Application,
Button, Clipboard, Color, Column, Command, Container, Element,
HorizontalAlignment, Length, PaneGrid, Row, Scrollable, Settings,
Subscription, Text,
Button, Column, Command, Container, Element, HorizontalAlignment, Length,
PaneGrid, Scrollable, Settings, Subscription, Text,
};
use iced_native::{event, subscription, Event};
@ -11,7 +10,7 @@ pub fn main() -> iced::Result {
}
struct Example {
panes: pane_grid::State<Pane>,
panes: pane_grid::State<Content>,
panes_created: usize,
focus: Option<pane_grid::Pane>,
}
@ -24,7 +23,6 @@ enum Message {
Clicked(pane_grid::Pane),
Dragged(pane_grid::DragEvent),
Resized(pane_grid::ResizeEvent),
TogglePin(pane_grid::Pane),
Close(pane_grid::Pane),
CloseFocused,
}
@ -35,7 +33,7 @@ impl Application for Example {
type Flags = ();
fn new(_flags: ()) -> (Self, Command<Message>) {
let (panes, _) = pane_grid::State::new(Pane::new(0));
let (panes, _) = pane_grid::State::new(Content::new(0));
(
Example {
@ -51,17 +49,13 @@ impl Application for Example {
String::from("Pane grid - Iced")
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Split(axis, pane) => {
let result = self.panes.split(
axis,
&pane,
Pane::new(self.panes_created),
Content::new(self.panes_created),
);
if let Some((pane, _)) = result {
@ -75,7 +69,7 @@ impl Application for Example {
let result = self.panes.split(
axis,
&pane,
Pane::new(self.panes_created),
Content::new(self.panes_created),
);
if let Some((pane, _)) = result {
@ -107,12 +101,6 @@ impl Application for Example {
self.panes.swap(&pane, &target);
}
Message::Dragged(_) => {}
Message::TogglePin(pane) => {
if let Some(Pane { is_pinned, .. }) = self.panes.get_mut(&pane)
{
*is_pinned = !*is_pinned;
}
}
Message::Close(pane) => {
if let Some((_, sibling)) = self.panes.close(&pane) {
self.focus = Some(sibling);
@ -120,18 +108,12 @@ impl Application for Example {
}
Message::CloseFocused => {
if let Some(pane) = self.focus {
if let Some(Pane { is_pinned, .. }) = self.panes.get(&pane)
{
if !is_pinned {
if let Some((_, sibling)) = self.panes.close(&pane)
{
if let Some((_, sibling)) = self.panes.close(&pane) {
self.focus = Some(sibling);
}
}
}
}
}
}
Command::none()
}
@ -156,39 +138,15 @@ impl Application for Example {
let focus = self.focus;
let total_panes = self.panes.len();
let pane_grid = PaneGrid::new(&mut self.panes, |id, pane| {
let is_focused = focus == Some(id);
let pane_grid = PaneGrid::new(&mut self.panes, |pane, content| {
let is_focused = focus == Some(pane);
let text = if pane.is_pinned { "Unpin" } else { "Pin" };
let pin_button =
Button::new(&mut pane.pin_button, Text::new(text).size(14))
.on_press(Message::TogglePin(id))
.style(style::Button::Pin)
.padding(3);
let title = Row::with_children(vec![
pin_button.into(),
Text::new("Pane").into(),
Text::new(pane.content.id.to_string())
.color(if is_focused {
PANE_ID_COLOR_FOCUSED
} else {
PANE_ID_COLOR_UNFOCUSED
})
.into(),
])
.spacing(5);
let title_bar = pane_grid::TitleBar::new(title)
.controls(pane.controls.view(id, total_panes, pane.is_pinned))
let title_bar =
pane_grid::TitleBar::new(format!("Pane {}", content.id))
.padding(10)
.style(style::TitleBar { is_focused });
pane_grid::Content::new(pane.content.view(
id,
total_panes,
pane.is_pinned,
))
pane_grid::Content::new(content.view(pane, total_panes))
.title_bar(title_bar)
.style(style::Pane { is_focused })
})
@ -207,17 +165,6 @@ impl Application for Example {
}
}
const PANE_ID_COLOR_UNFOCUSED: Color = Color::from_rgb(
0xFF as f32 / 255.0,
0xC7 as f32 / 255.0,
0xC7 as f32 / 255.0,
);
const PANE_ID_COLOR_FOCUSED: Color = Color::from_rgb(
0xFF as f32 / 255.0,
0x47 as f32 / 255.0,
0x47 as f32 / 255.0,
);
fn handle_hotkey(key_code: keyboard::KeyCode) -> Option<Message> {
use keyboard::KeyCode;
use pane_grid::{Axis, Direction};
@ -238,13 +185,6 @@ fn handle_hotkey(key_code: keyboard::KeyCode) -> Option<Message> {
}
}
struct Pane {
pub is_pinned: bool,
pub pin_button: button::State,
pub content: Content,
pub controls: Controls,
}
struct Content {
id: usize,
scroll: scrollable::State,
@ -253,21 +193,6 @@ struct Content {
close: button::State,
}
struct Controls {
close: button::State,
}
impl Pane {
fn new(id: usize) -> Self {
Self {
is_pinned: false,
pin_button: button::State::new(),
content: Content::new(id),
controls: Controls::new(),
}
}
}
impl Content {
fn new(id: usize) -> Self {
Content {
@ -282,7 +207,6 @@ impl Content {
&mut self,
pane: pane_grid::Pane,
total_panes: usize,
is_pinned: bool,
) -> Element<Message> {
let Content {
scroll,
@ -322,7 +246,7 @@ impl Content {
style::Button::Primary,
));
if total_panes > 1 && !is_pinned {
if total_panes > 1 {
controls = controls.push(button(
close,
"Close",
@ -346,32 +270,7 @@ impl Content {
}
}
impl Controls {
fn new() -> Self {
Self {
close: button::State::new(),
}
}
pub fn view(
&mut self,
pane: pane_grid::Pane,
total_panes: usize,
is_pinned: bool,
) -> Element<Message> {
let mut button =
Button::new(&mut self.close, Text::new("Close").size(14))
.style(style::Button::Control)
.padding(3);
if total_panes > 1 && !is_pinned {
button = button.on_press(Message::Close(pane));
}
button.into()
}
}
mod style {
use crate::PANE_ID_COLOR_FOCUSED;
use iced::{button, container, Background, Color, Vector};
const SURFACE: Color = Color::from_rgb(
@ -433,8 +332,6 @@ mod style {
pub enum Button {
Primary,
Destructive,
Control,
Pin,
}
impl button::StyleSheet for Button {
@ -444,8 +341,6 @@ mod style {
Button::Destructive => {
(None, Color::from_rgb8(0xFF, 0x47, 0x47))
}
Button::Control => (Some(PANE_ID_COLOR_FOCUSED), Color::WHITE),
Button::Pin => (Some(ACTIVE), Color::WHITE),
};
button::Style {
@ -466,8 +361,6 @@ mod style {
a: 0.2,
..active.text_color
}),
Button::Control => Some(PANE_ID_COLOR_FOCUSED),
Button::Pin => Some(HOVERED),
};
button::Style {

View File

@ -1,6 +1,6 @@
use iced::{
button, futures, image, Align, Application, Button, Clipboard, Column,
Command, Container, Element, Length, Row, Settings, Text,
button, futures, image, Align, Application, Button, Column, Command,
Container, Element, Image, Length, Row, Settings, Text,
};
pub fn main() -> iced::Result {
@ -48,11 +48,7 @@ impl Application for Pokedex {
format!("{} - Pokédex", subtitle)
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::PokemonFound(Ok(pokemon)) => {
*self = Pokedex::Loaded {
@ -116,20 +112,16 @@ struct Pokemon {
name: String,
description: String,
image: image::Handle,
image_viewer: image::viewer::State,
}
impl Pokemon {
const TOTAL: u16 = 807;
fn view(&mut self) -> Element<Message> {
fn view(&self) -> Element<Message> {
Row::new()
.spacing(20)
.align_items(Align::Center)
.push(image::Viewer::new(
&mut self.image_viewer,
self.image.clone(),
))
.push(Image::new(self.image.clone()))
.push(
Column::new()
.spacing(20)
@ -208,15 +200,11 @@ impl Pokemon {
.map(|c| if c.is_control() { ' ' } else { c })
.collect(),
image,
image_viewer: image::viewer::State::new(),
})
}
async fn fetch_image(id: u16) -> Result<image::Handle, reqwest::Error> {
let url = format!(
"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png",
id
);
let url = format!("https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png", id);
#[cfg(not(target_arch = "wasm32"))]
{

View File

@ -6,4 +6,4 @@ edition = "2018"
publish = false
[dependencies]
iced = { path = "../..", features = ["debug"] }
iced = { path = "../.." }

View File

@ -1,8 +1,8 @@
mod style;
use iced::{
button, scrollable, Button, Column, Container, Element, Length,
ProgressBar, Radio, Row, Rule, Sandbox, Scrollable, Settings, Space, Text,
scrollable, Column, Container, Element, Length, Radio, Row, Rule, Sandbox,
Scrollable, Settings, Space, Text,
};
pub fn main() -> iced::Result {
@ -17,9 +17,6 @@ struct ScrollableDemo {
#[derive(Debug, Clone)]
enum Message {
ThemeChanged(style::Theme),
ScrollToTop(usize),
ScrollToBottom(usize),
Scrolled(usize, f32),
}
impl Sandbox for ScrollableDemo {
@ -39,25 +36,6 @@ impl Sandbox for ScrollableDemo {
fn update(&mut self, message: Message) {
match message {
Message::ThemeChanged(theme) => self.theme = theme,
Message::ScrollToTop(i) => {
if let Some(variant) = self.variants.get_mut(i) {
variant.scrollable.snap_to(0.0);
variant.latest_offset = 0.0;
}
}
Message::ScrollToBottom(i) => {
if let Some(variant) = self.variants.get_mut(i) {
variant.scrollable.snap_to(1.0);
variant.latest_offset = 1.0;
}
}
Message::Scrolled(i, offset) => {
if let Some(variant) = self.variants.get_mut(i) {
variant.latest_offset = offset;
}
}
}
}
@ -84,28 +62,13 @@ impl Sandbox for ScrollableDemo {
let scrollable_row = Row::with_children(
variants
.iter_mut()
.enumerate()
.map(|(i, variant)| {
let mut scrollable =
Scrollable::new(&mut variant.scrollable)
.map(|variant| {
let mut scrollable = Scrollable::new(&mut variant.state)
.padding(10)
.spacing(10)
.width(Length::Fill)
.height(Length::Fill)
.on_scroll(move |offset| {
Message::Scrolled(i, offset)
})
.style(*theme)
.push(Text::new(variant.title))
.push(
Button::new(
&mut variant.scroll_to_bottom,
Text::new("Scroll to bottom"),
)
.width(Length::Fill)
.padding(10)
.on_press(Message::ScrollToBottom(i)),
);
.push(Text::new(variant.title));
if let Some(scrollbar_width) = variant.scrollbar_width {
scrollable = scrollable
@ -145,31 +108,12 @@ impl Sandbox for ScrollableDemo {
.push(Space::with_height(Length::Units(1200)))
.push(Text::new("Middle"))
.push(Space::with_height(Length::Units(1200)))
.push(Text::new("The End."))
.push(
Button::new(
&mut variant.scroll_to_top,
Text::new("Scroll to top"),
)
.width(Length::Fill)
.padding(10)
.on_press(Message::ScrollToTop(i)),
);
.push(Text::new("The End."));
Column::new()
.width(Length::Fill)
.height(Length::Fill)
.spacing(10)
.push(
Container::new(scrollable)
.width(Length::Fill)
.height(Length::Fill)
.style(*theme),
)
.push(ProgressBar::new(
0.0..=1.0,
variant.latest_offset,
))
.style(*theme)
.into()
})
.collect(),
@ -198,13 +142,10 @@ impl Sandbox for ScrollableDemo {
/// A version of a scrollable
struct Variant {
title: &'static str,
scrollable: scrollable::State,
scroll_to_top: button::State,
scroll_to_bottom: button::State,
state: scrollable::State,
scrollbar_width: Option<u16>,
scrollbar_margin: Option<u16>,
scroller_width: Option<u16>,
latest_offset: f32,
}
impl Variant {
@ -212,43 +153,31 @@ impl Variant {
vec![
Self {
title: "Default Scrollbar",
scrollable: scrollable::State::new(),
scroll_to_top: button::State::new(),
scroll_to_bottom: button::State::new(),
state: scrollable::State::new(),
scrollbar_width: None,
scrollbar_margin: None,
scroller_width: None,
latest_offset: 0.0,
},
Self {
title: "Slimmed & Margin",
scrollable: scrollable::State::new(),
scroll_to_top: button::State::new(),
scroll_to_bottom: button::State::new(),
state: scrollable::State::new(),
scrollbar_width: Some(4),
scrollbar_margin: Some(3),
scroller_width: Some(4),
latest_offset: 0.0,
},
Self {
title: "Wide Scroller",
scrollable: scrollable::State::new(),
scroll_to_top: button::State::new(),
scroll_to_bottom: button::State::new(),
state: scrollable::State::new(),
scrollbar_width: Some(4),
scrollbar_margin: None,
scroller_width: Some(10),
latest_offset: 0.0,
},
Self {
title: "Narrow Scroller",
scrollable: scrollable::State::new(),
scroll_to_top: button::State::new(),
scroll_to_bottom: button::State::new(),
state: scrollable::State::new(),
scrollbar_width: Some(10),
scrollbar_margin: None,
scroller_width: Some(4),
latest_offset: 0.0,
},
]
}

View File

@ -7,4 +7,4 @@ publish = false
[dependencies]
iced = { path = "../..", features = ["canvas", "tokio", "debug"] }
rand = "0.8.3"
rand = "0.7"

View File

@ -8,8 +8,8 @@
//! [1]: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations#An_animated_solar_system
use iced::{
canvas::{self, Cursor, Path, Stroke},
executor, time, window, Application, Canvas, Clipboard, Color, Command,
Element, Length, Point, Rectangle, Settings, Size, Subscription, Vector,
executor, time, window, Application, Canvas, Color, Command, Element,
Length, Point, Rectangle, Settings, Size, Subscription, Vector,
};
use std::time::Instant;
@ -48,11 +48,7 @@ impl Application for SolarSystem {
String::from("Solar system - Iced")
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Tick(instant) => {
self.state.update(instant);
@ -121,13 +117,15 @@ impl State {
(
Point::new(
rng.gen_range(
(-(width as f32) / 2.0)..(width as f32 / 2.0),
-(width as f32) / 2.0,
width as f32 / 2.0,
),
rng.gen_range(
(-(height as f32) / 2.0)..(height as f32 / 2.0),
-(height as f32) / 2.0,
height as f32 / 2.0,
),
),
rng.gen_range(0.5..1.0),
rng.gen_range(0.5, 1.0),
)
})
.collect()

View File

@ -6,4 +6,4 @@ edition = "2018"
publish = false
[dependencies]
iced = { path = "../..", features = ["smol"] }
iced = { path = "../..", features = ["tokio"] }

View File

@ -1,6 +1,6 @@
use iced::{
button, executor, time, Align, Application, Button, Clipboard, Column,
Command, Container, Element, HorizontalAlignment, Length, Row, Settings,
button, executor, time, Align, Application, Button, Column, Command,
Container, Element, HorizontalAlignment, Length, Row, Settings,
Subscription, Text,
};
use std::time::{Duration, Instant};
@ -49,11 +49,7 @@ impl Application for Stopwatch {
String::from("Stopwatch - Iced")
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Toggle => match self.state {
State::Idle => {

View File

@ -1,7 +1,7 @@
use iced::{
button, scrollable, slider, text_input, Align, Button, Checkbox, Column,
Container, Element, Length, ProgressBar, Radio, Row, Rule, Sandbox,
Scrollable, Settings, Slider, Space, Text, TextInput, Toggler,
Scrollable, Settings, Slider, Space, Text, TextInput,
};
pub fn main() -> iced::Result {
@ -17,8 +17,7 @@ struct Styling {
button: button::State,
slider: slider::State,
slider_value: f32,
checkbox_value: bool,
toggler_value: bool,
toggle_value: bool,
}
#[derive(Debug, Clone)]
@ -28,7 +27,6 @@ enum Message {
ButtonPressed,
SliderChanged(f32),
CheckboxToggled(bool),
TogglerToggled(bool),
}
impl Sandbox for Styling {
@ -46,10 +44,9 @@ impl Sandbox for Styling {
match message {
Message::ThemeChanged(theme) => self.theme = theme,
Message::InputChanged(value) => self.input_value = value,
Message::ButtonPressed => {}
Message::ButtonPressed => (),
Message::SliderChanged(value) => self.slider_value = value,
Message::CheckboxToggled(value) => self.checkbox_value = value,
Message::TogglerToggled(value) => self.toggler_value = value,
Message::CheckboxToggled(value) => self.toggle_value = value,
}
}
@ -104,19 +101,11 @@ impl Sandbox for Styling {
.push(Text::new("You did it!"));
let checkbox = Checkbox::new(
self.checkbox_value,
"Check me!",
self.toggle_value,
"Toggle me!",
Message::CheckboxToggled,
)
.style(self.theme);
let toggler = Toggler::new(
self.toggler_value,
String::from("Toggle me!"),
Message::TogglerToggled,
)
.width(Length::Shrink)
.spacing(10)
.width(Length::Fill)
.style(self.theme);
let content = Column::new()
@ -135,13 +124,7 @@ impl Sandbox for Styling {
.align_items(Align::Center)
.push(scrollable)
.push(Rule::vertical(38).style(self.theme))
.push(
Column::new()
.width(Length::Shrink)
.spacing(20)
.push(checkbox)
.push(toggler),
),
.push(checkbox),
);
Container::new(content)
@ -157,7 +140,7 @@ impl Sandbox for Styling {
mod style {
use iced::{
button, checkbox, container, progress_bar, radio, rule, scrollable,
slider, text_input, toggler,
slider, text_input,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -248,15 +231,6 @@ mod style {
}
}
impl From<Theme> for Box<dyn toggler::StyleSheet> {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
Theme::Dark => dark::Toggler.into(),
}
}
}
impl From<Theme> for Box<dyn rule::StyleSheet> {
fn from(theme: Theme) -> Self {
match theme {
@ -295,7 +269,7 @@ mod style {
mod dark {
use iced::{
button, checkbox, container, progress_bar, radio, rule, scrollable,
slider, text_input, toggler, Color,
slider, text_input, Color,
};
const SURFACE: Color = Color::from_rgb(
@ -546,35 +520,6 @@ mod style {
}
}
pub struct Toggler;
impl toggler::StyleSheet for Toggler {
fn active(&self, is_active: bool) -> toggler::Style {
toggler::Style {
background: if is_active { ACTIVE } else { SURFACE },
background_border: None,
foreground: if is_active { Color::WHITE } else { ACTIVE },
foreground_border: None,
}
}
fn hovered(&self, is_active: bool) -> toggler::Style {
toggler::Style {
background: if is_active { ACTIVE } else { SURFACE },
background_border: None,
foreground: if is_active {
Color {
a: 0.5,
..Color::WHITE
}
} else {
Color { a: 0.5, ..ACTIVE }
},
foreground_border: None,
}
}
}
pub struct Rule;
impl rule::StyleSheet for Rule {

View File

@ -1,7 +1,7 @@
use iced::{
button, scrollable, text_input, Align, Application, Button, Checkbox,
Clipboard, Column, Command, Container, Element, Font, HorizontalAlignment,
Length, Row, Scrollable, Settings, Text, TextInput,
Column, Command, Container, Element, Font, HorizontalAlignment, Length,
Row, Scrollable, Settings, Text, TextInput,
};
use serde::{Deserialize, Serialize};
@ -58,11 +58,7 @@ impl Application for Todos {
format!("Todos{} - Iced", if dirty { "*" } else { "" })
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
fn update(&mut self, message: Message) -> Command<Message> {
match self {
Todos::Loading => {
match message {
@ -493,6 +489,7 @@ enum LoadError {
#[derive(Debug, Clone)]
enum SaveError {
DirectoryError,
FileError,
WriteError,
FormatError,
@ -541,7 +538,7 @@ impl SavedState {
if let Some(dir) = path.parent() {
async_std::fs::create_dir_all(dir)
.await
.map_err(|_| SaveError::FileError)?;
.map_err(|_| SaveError::DirectoryError)?;
}
{

View File

@ -1,9 +0,0 @@
[package]
name = "tooltip"
version = "0.1.0"
authors = ["Yusuf Bera Ertan <y.bera003.06@protonmail.com>"]
edition = "2018"
publish = false
[dependencies]
iced = { path = "../..", features = ["debug"] }

View File

@ -1,14 +0,0 @@
## Tooltip
A tooltip.
It displays and positions a widget on another based on cursor position.
The __[`main`]__ file contains all the code of the example.
You can run it with `cargo run`:
```
cargo run --package tooltip
```
[`main`]: src/main.rs

View File

@ -1,138 +0,0 @@
use iced::tooltip::{self, Tooltip};
use iced::{
button, Button, Column, Container, Element, HorizontalAlignment, Length,
Row, Sandbox, Settings, Text, VerticalAlignment,
};
pub fn main() {
Example::run(Settings::default()).unwrap()
}
#[derive(Default)]
struct Example {
top: button::State,
bottom: button::State,
right: button::State,
left: button::State,
follow_cursor: button::State,
}
#[derive(Debug, Clone, Copy)]
struct Message;
impl Sandbox for Example {
type Message = Message;
fn new() -> Self {
Self::default()
}
fn title(&self) -> String {
String::from("Tooltip - Iced")
}
fn update(&mut self, _message: Message) {}
fn view(&mut self) -> Element<Message> {
let top =
tooltip("Tooltip at top", &mut self.top, tooltip::Position::Top);
let bottom = tooltip(
"Tooltip at bottom",
&mut self.bottom,
tooltip::Position::Bottom,
);
let left =
tooltip("Tooltip at left", &mut self.left, tooltip::Position::Left);
let right = tooltip(
"Tooltip at right",
&mut self.right,
tooltip::Position::Right,
);
let fixed_tooltips = Row::with_children(vec![
top.into(),
bottom.into(),
left.into(),
right.into(),
])
.width(Length::Fill)
.height(Length::Fill)
.align_items(iced::Align::Center)
.spacing(50);
let follow_cursor = tooltip(
"Tooltip follows cursor",
&mut self.follow_cursor,
tooltip::Position::FollowCursor,
);
let content = Column::with_children(vec![
Container::new(fixed_tooltips)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into(),
follow_cursor.into(),
])
.width(Length::Fill)
.height(Length::Fill)
.spacing(50);
Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.padding(50)
.into()
}
}
fn tooltip<'a>(
label: &str,
button_state: &'a mut button::State,
position: tooltip::Position,
) -> Element<'a, Message> {
Tooltip::new(
Button::new(
button_state,
Text::new(label)
.size(40)
.width(Length::Fill)
.height(Length::Fill)
.horizontal_alignment(HorizontalAlignment::Center)
.vertical_alignment(VerticalAlignment::Center),
)
.on_press(Message)
.width(Length::Fill)
.height(Length::Fill),
"Tooltip",
position,
)
.gap(5)
.padding(10)
.style(style::Tooltip)
.into()
}
mod style {
use iced::container;
use iced::Color;
pub struct Tooltip;
impl container::StyleSheet for Tooltip {
fn style(&self) -> container::Style {
container::Style {
text_color: Some(Color::from_rgb8(0xEE, 0xEE, 0xEE)),
background: Some(Color::from_rgb(0.11, 0.42, 0.87).into()),
border_radius: 12.0,
..container::Style::default()
}
}
}
}

View File

@ -1,7 +1,7 @@
use iced::{
button, scrollable, slider, text_input, Button, Checkbox, Color, Column,
Container, Element, HorizontalAlignment, Image, Length, Radio, Row,
Sandbox, Scrollable, Settings, Slider, Space, Text, TextInput, Toggler,
Sandbox, Scrollable, Settings, Slider, Space, Text, TextInput,
};
pub fn main() -> iced::Result {
@ -135,9 +135,6 @@ impl Steps {
color: Color::BLACK,
},
Step::Radio { selection: None },
Step::Toggler {
can_continue: false,
},
Step::Image {
width: 300,
slider: slider::State::new(),
@ -209,9 +206,6 @@ enum Step {
Radio {
selection: Option<Language>,
},
Toggler {
can_continue: bool,
},
Image {
width: u16,
slider: slider::State,
@ -238,7 +232,6 @@ pub enum StepMessage {
InputChanged(String),
ToggleSecureInput(bool),
DebugToggled(bool),
TogglerChanged(bool),
}
impl<'a> Step {
@ -294,11 +287,6 @@ impl<'a> Step {
*is_secure = toggle;
}
}
StepMessage::TogglerChanged(value) => {
if let Step::Toggler { can_continue, .. } = self {
*can_continue = value;
}
}
};
}
@ -306,7 +294,6 @@ impl<'a> Step {
match self {
Step::Welcome => "Welcome",
Step::Radio { .. } => "Radio button",
Step::Toggler { .. } => "Toggler",
Step::Slider { .. } => "Slider",
Step::Text { .. } => "Text",
Step::Image { .. } => "Image",
@ -322,7 +309,6 @@ impl<'a> Step {
match self {
Step::Welcome => true,
Step::Radio { selection } => *selection == Some(Language::Rust),
Step::Toggler { can_continue } => *can_continue,
Step::Slider { .. } => true,
Step::Text { .. } => true,
Step::Image { .. } => true,
@ -338,7 +324,6 @@ impl<'a> Step {
match self {
Step::Welcome => Self::welcome(),
Step::Radio { selection } => Self::radio(*selection),
Step::Toggler { can_continue } => Self::toggler(*can_continue),
Step::Slider { state, value } => Self::slider(state, *value),
Step::Text {
size_slider,
@ -560,21 +545,6 @@ impl<'a> Step {
))
}
fn toggler(can_continue: bool) -> Column<'a, StepMessage> {
Self::container("Toggler")
.push(Text::new(
"A toggler is mostly used to enable or disable something.",
))
.push(
Container::new(Toggler::new(
can_continue,
String::from("Toggle me to continue..."),
StepMessage::TogglerChanged,
))
.padding([0, 40]),
)
}
fn image(
width: u16,
slider: &'a mut slider::State,

View File

@ -1,10 +0,0 @@
[package]
name = "tour_glow"
version = "0.1.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
publish = false
[dependencies]
iced = { path = "../..", features = ["glow", "debug"] }
env_logger = "0.8"

View File

@ -1,28 +0,0 @@
## Tour
A simple UI tour that can run both on native platforms and the web! It showcases different widgets that can be built using Iced.
The __[`main`]__ file contains all the code of the example! All the cross-platform GUI is defined in terms of __state__, __messages__, __update logic__ and __view logic__.
<div align="center">
<a href="https://gfycat.com/politeadorableiberianmole">
<img src="https://thumbs.gfycat.com/PoliteAdorableIberianmole-small.gif">
</a>
</div>
[`main`]: src/main.rs
[`iced_winit`]: ../../winit
[`iced_native`]: ../../native
[`iced_wgpu`]: ../../wgpu
[`iced_web`]: ../../web
[`winit`]: https://github.com/rust-windowing/winit
[`wgpu`]: https://github.com/gfx-rs/wgpu-rs
You can run the native version with `cargo run`:
```
cargo run --package tour
```
The web version can be run by following [the usage instructions of `iced_web`] or by accessing [iced.rs](https://iced.rs/)!
[the usage instructions of `iced_web`]: ../../web#usage

View File

@ -1,809 +0,0 @@
use iced::{
button, scrollable, slider, text_input, Button, Checkbox, Color, Column,
Container, Element, HorizontalAlignment, Length, Radio, Row, Sandbox,
Scrollable, Settings, Slider, Space, Text, TextInput, Toggler,
};
pub fn main() -> iced::Result {
env_logger::init();
Tour::run(Settings::default())
}
pub struct Tour {
steps: Steps,
scroll: scrollable::State,
back_button: button::State,
next_button: button::State,
debug: bool,
}
impl Sandbox for Tour {
type Message = Message;
fn new() -> Tour {
Tour {
steps: Steps::new(),
scroll: scrollable::State::new(),
back_button: button::State::new(),
next_button: button::State::new(),
debug: false,
}
}
fn title(&self) -> String {
format!("{} - Iced", self.steps.title())
}
fn update(&mut self, event: Message) {
match event {
Message::BackPressed => {
self.steps.go_back();
}
Message::NextPressed => {
self.steps.advance();
}
Message::StepMessage(step_msg) => {
self.steps.update(step_msg, &mut self.debug);
}
}
}
fn view(&mut self) -> Element<Message> {
let Tour {
steps,
scroll,
back_button,
next_button,
..
} = self;
let mut controls = Row::new();
if steps.has_previous() {
controls = controls.push(
button(back_button, "Back")
.on_press(Message::BackPressed)
.style(style::Button::Secondary),
);
}
controls = controls.push(Space::with_width(Length::Fill));
if steps.can_continue() {
controls = controls.push(
button(next_button, "Next")
.on_press(Message::NextPressed)
.style(style::Button::Primary),
);
}
let content: Element<_> = Column::new()
.max_width(540)
.spacing(20)
.padding(20)
.push(steps.view(self.debug).map(Message::StepMessage))
.push(controls)
.into();
let content = if self.debug {
content.explain(Color::BLACK)
} else {
content
};
let scrollable = Scrollable::new(scroll)
.push(Container::new(content).width(Length::Fill).center_x());
Container::new(scrollable)
.height(Length::Fill)
.center_y()
.into()
}
}
#[derive(Debug, Clone)]
pub enum Message {
BackPressed,
NextPressed,
StepMessage(StepMessage),
}
struct Steps {
steps: Vec<Step>,
current: usize,
}
impl Steps {
fn new() -> Steps {
Steps {
steps: vec![
Step::Welcome,
Step::Slider {
state: slider::State::new(),
value: 50,
},
Step::RowsAndColumns {
layout: Layout::Row,
spacing_slider: slider::State::new(),
spacing: 20,
},
Step::Text {
size_slider: slider::State::new(),
size: 30,
color_sliders: [slider::State::new(); 3],
color: Color::BLACK,
},
Step::Radio { selection: None },
Step::Toggler {
can_continue: false,
},
Step::Image {
width: 300,
slider: slider::State::new(),
},
Step::Scrollable,
Step::TextInput {
value: String::new(),
is_secure: false,
state: text_input::State::new(),
},
Step::Debugger,
Step::End,
],
current: 0,
}
}
fn update(&mut self, msg: StepMessage, debug: &mut bool) {
self.steps[self.current].update(msg, debug);
}
fn view(&mut self, debug: bool) -> Element<StepMessage> {
self.steps[self.current].view(debug)
}
fn advance(&mut self) {
if self.can_continue() {
self.current += 1;
}
}
fn go_back(&mut self) {
if self.has_previous() {
self.current -= 1;
}
}
fn has_previous(&self) -> bool {
self.current > 0
}
fn can_continue(&self) -> bool {
self.current + 1 < self.steps.len()
&& self.steps[self.current].can_continue()
}
fn title(&self) -> &str {
self.steps[self.current].title()
}
}
enum Step {
Welcome,
Slider {
state: slider::State,
value: u8,
},
RowsAndColumns {
layout: Layout,
spacing_slider: slider::State,
spacing: u16,
},
Text {
size_slider: slider::State,
size: u16,
color_sliders: [slider::State; 3],
color: Color,
},
Radio {
selection: Option<Language>,
},
Toggler {
can_continue: bool,
},
Image {
width: u16,
slider: slider::State,
},
Scrollable,
TextInput {
value: String,
is_secure: bool,
state: text_input::State,
},
Debugger,
End,
}
#[derive(Debug, Clone)]
pub enum StepMessage {
SliderChanged(u8),
LayoutChanged(Layout),
SpacingChanged(u16),
TextSizeChanged(u16),
TextColorChanged(Color),
LanguageSelected(Language),
ImageWidthChanged(u16),
InputChanged(String),
ToggleSecureInput(bool),
DebugToggled(bool),
TogglerChanged(bool),
}
impl<'a> Step {
fn update(&mut self, msg: StepMessage, debug: &mut bool) {
match msg {
StepMessage::DebugToggled(value) => {
if let Step::Debugger = self {
*debug = value;
}
}
StepMessage::LanguageSelected(language) => {
if let Step::Radio { selection } = self {
*selection = Some(language);
}
}
StepMessage::SliderChanged(new_value) => {
if let Step::Slider { value, .. } = self {
*value = new_value;
}
}
StepMessage::TextSizeChanged(new_size) => {
if let Step::Text { size, .. } = self {
*size = new_size;
}
}
StepMessage::TextColorChanged(new_color) => {
if let Step::Text { color, .. } = self {
*color = new_color;
}
}
StepMessage::LayoutChanged(new_layout) => {
if let Step::RowsAndColumns { layout, .. } = self {
*layout = new_layout;
}
}
StepMessage::SpacingChanged(new_spacing) => {
if let Step::RowsAndColumns { spacing, .. } = self {
*spacing = new_spacing;
}
}
StepMessage::ImageWidthChanged(new_width) => {
if let Step::Image { width, .. } = self {
*width = new_width;
}
}
StepMessage::InputChanged(new_value) => {
if let Step::TextInput { value, .. } = self {
*value = new_value;
}
}
StepMessage::ToggleSecureInput(toggle) => {
if let Step::TextInput { is_secure, .. } = self {
*is_secure = toggle;
}
}
StepMessage::TogglerChanged(value) => {
if let Step::Toggler { can_continue, .. } = self {
*can_continue = value;
}
}
};
}
fn title(&self) -> &str {
match self {
Step::Welcome => "Welcome",
Step::Radio { .. } => "Radio button",
Step::Toggler { .. } => "Toggler",
Step::Slider { .. } => "Slider",
Step::Text { .. } => "Text",
Step::Image { .. } => "Image",
Step::RowsAndColumns { .. } => "Rows and columns",
Step::Scrollable => "Scrollable",
Step::TextInput { .. } => "Text input",
Step::Debugger => "Debugger",
Step::End => "End",
}
}
fn can_continue(&self) -> bool {
match self {
Step::Welcome => true,
Step::Radio { selection } => *selection == Some(Language::Rust),
Step::Toggler { can_continue } => *can_continue,
Step::Slider { .. } => true,
Step::Text { .. } => true,
Step::Image { .. } => true,
Step::RowsAndColumns { .. } => true,
Step::Scrollable => true,
Step::TextInput { value, .. } => !value.is_empty(),
Step::Debugger => true,
Step::End => false,
}
}
fn view(&mut self, debug: bool) -> Element<StepMessage> {
match self {
Step::Welcome => Self::welcome(),
Step::Radio { selection } => Self::radio(*selection),
Step::Toggler { can_continue } => Self::toggler(*can_continue),
Step::Slider { state, value } => Self::slider(state, *value),
Step::Text {
size_slider,
size,
color_sliders,
color,
} => Self::text(size_slider, *size, color_sliders, *color),
Step::Image { width, slider } => Self::image(*width, slider),
Step::RowsAndColumns {
layout,
spacing_slider,
spacing,
} => Self::rows_and_columns(*layout, spacing_slider, *spacing),
Step::Scrollable => Self::scrollable(),
Step::TextInput {
value,
is_secure,
state,
} => Self::text_input(value, *is_secure, state),
Step::Debugger => Self::debugger(debug),
Step::End => Self::end(),
}
.into()
}
fn container(title: &str) -> Column<'a, StepMessage> {
Column::new().spacing(20).push(Text::new(title).size(50))
}
fn welcome() -> Column<'a, StepMessage> {
Self::container("Welcome!")
.push(Text::new(
"This is a simple tour meant to showcase a bunch of widgets \
that can be easily implemented on top of Iced.",
))
.push(Text::new(
"Iced is a cross-platform GUI library for Rust focused on \
simplicity and type-safety. It is heavily inspired by Elm.",
))
.push(Text::new(
"It was originally born as part of Coffee, an opinionated \
2D game engine for Rust.",
))
.push(Text::new(
"On native platforms, Iced provides by default a renderer \
built on top of wgpu, a graphics library supporting Vulkan, \
Metal, DX11, and DX12.",
))
.push(Text::new(
"Additionally, this tour can also run on WebAssembly thanks \
to dodrio, an experimental VDOM library for Rust.",
))
.push(Text::new(
"You will need to interact with the UI in order to reach the \
end!",
))
}
fn slider(
state: &'a mut slider::State,
value: u8,
) -> Column<'a, StepMessage> {
Self::container("Slider")
.push(Text::new(
"A slider allows you to smoothly select a value from a range \
of values.",
))
.push(Text::new(
"The following slider lets you choose an integer from \
0 to 100:",
))
.push(Slider::new(
state,
0..=100,
value,
StepMessage::SliderChanged,
))
.push(
Text::new(&value.to_string())
.width(Length::Fill)
.horizontal_alignment(HorizontalAlignment::Center),
)
}
fn rows_and_columns(
layout: Layout,
spacing_slider: &'a mut slider::State,
spacing: u16,
) -> Column<'a, StepMessage> {
let row_radio = Radio::new(
Layout::Row,
"Row",
Some(layout),
StepMessage::LayoutChanged,
);
let column_radio = Radio::new(
Layout::Column,
"Column",
Some(layout),
StepMessage::LayoutChanged,
);
let layout_section: Element<_> = match layout {
Layout::Row => Row::new()
.spacing(spacing)
.push(row_radio)
.push(column_radio)
.into(),
Layout::Column => Column::new()
.spacing(spacing)
.push(row_radio)
.push(column_radio)
.into(),
};
let spacing_section = Column::new()
.spacing(10)
.push(Slider::new(
spacing_slider,
0..=80,
spacing,
StepMessage::SpacingChanged,
))
.push(
Text::new(&format!("{} px", spacing))
.width(Length::Fill)
.horizontal_alignment(HorizontalAlignment::Center),
);
Self::container("Rows and columns")
.spacing(spacing)
.push(Text::new(
"Iced uses a layout model based on flexbox to position UI \
elements.",
))
.push(Text::new(
"Rows and columns can be used to distribute content \
horizontally or vertically, respectively.",
))
.push(layout_section)
.push(Text::new(
"You can also easily change the spacing between elements:",
))
.push(spacing_section)
}
fn text(
size_slider: &'a mut slider::State,
size: u16,
color_sliders: &'a mut [slider::State; 3],
color: Color,
) -> Column<'a, StepMessage> {
let size_section = Column::new()
.padding(20)
.spacing(20)
.push(Text::new("You can change its size:"))
.push(
Text::new(&format!("This text is {} pixels", size)).size(size),
)
.push(Slider::new(
size_slider,
10..=70,
size,
StepMessage::TextSizeChanged,
));
let [red, green, blue] = color_sliders;
let color_sliders = Row::new()
.spacing(10)
.push(color_slider(red, color.r, move |r| Color { r, ..color }))
.push(color_slider(green, color.g, move |g| Color { g, ..color }))
.push(color_slider(blue, color.b, move |b| Color { b, ..color }));
let color_section = Column::new()
.padding(20)
.spacing(20)
.push(Text::new("And its color:"))
.push(Text::new(&format!("{:?}", color)).color(color))
.push(color_sliders);
Self::container("Text")
.push(Text::new(
"Text is probably the most essential widget for your UI. \
It will try to adapt to the dimensions of its container.",
))
.push(size_section)
.push(color_section)
}
fn radio(selection: Option<Language>) -> Column<'a, StepMessage> {
let question = Column::new()
.padding(20)
.spacing(10)
.push(Text::new("Iced is written in...").size(24))
.push(Language::all().iter().cloned().fold(
Column::new().padding(10).spacing(20),
|choices, language| {
choices.push(Radio::new(
language,
language,
selection,
StepMessage::LanguageSelected,
))
},
));
Self::container("Radio button")
.push(Text::new(
"A radio button is normally used to represent a choice... \
Surprise test!",
))
.push(question)
.push(Text::new(
"Iced works very well with iterators! The list above is \
basically created by folding a column over the different \
choices, creating a radio button for each one of them!",
))
}
fn toggler(can_continue: bool) -> Column<'a, StepMessage> {
Self::container("Toggler")
.push(Text::new(
"A toggler is mostly used to enable or disable something.",
))
.push(
Container::new(Toggler::new(
can_continue,
String::from("Toggle me to continue..."),
StepMessage::TogglerChanged,
))
.padding([0, 40]),
)
}
fn image(
width: u16,
slider: &'a mut slider::State,
) -> Column<'a, StepMessage> {
Self::container("Image")
.push(Text::new("An image that tries to keep its aspect ratio."))
.push(ferris(width))
.push(Slider::new(
slider,
100..=500,
width,
StepMessage::ImageWidthChanged,
))
.push(
Text::new(&format!("Width: {} px", width.to_string()))
.width(Length::Fill)
.horizontal_alignment(HorizontalAlignment::Center),
)
}
fn scrollable() -> Column<'a, StepMessage> {
Self::container("Scrollable")
.push(Text::new(
"Iced supports scrollable content. Try it out! Find the \
button further below.",
))
.push(
Text::new(
"Tip: You can use the scrollbar to scroll down faster!",
)
.size(16),
)
.push(Column::new().height(Length::Units(4096)))
.push(
Text::new("You are halfway there!")
.width(Length::Fill)
.size(30)
.horizontal_alignment(HorizontalAlignment::Center),
)
.push(Column::new().height(Length::Units(4096)))
.push(ferris(300))
.push(
Text::new("You made it!")
.width(Length::Fill)
.size(50)
.horizontal_alignment(HorizontalAlignment::Center),
)
}
fn text_input(
value: &str,
is_secure: bool,
state: &'a mut text_input::State,
) -> Column<'a, StepMessage> {
let text_input = TextInput::new(
state,
"Type something to continue...",
value,
StepMessage::InputChanged,
)
.padding(10)
.size(30);
Self::container("Text input")
.push(Text::new(
"Use a text input to ask for different kinds of information.",
))
.push(if is_secure {
text_input.password()
} else {
text_input
})
.push(Checkbox::new(
is_secure,
"Enable password mode",
StepMessage::ToggleSecureInput,
))
.push(Text::new(
"A text input produces a message every time it changes. It is \
very easy to keep track of its contents:",
))
.push(
Text::new(if value.is_empty() {
"You have not typed anything yet..."
} else {
value
})
.width(Length::Fill)
.horizontal_alignment(HorizontalAlignment::Center),
)
}
fn debugger(debug: bool) -> Column<'a, StepMessage> {
Self::container("Debugger")
.push(Text::new(
"You can ask Iced to visually explain the layouting of the \
different elements comprising your UI!",
))
.push(Text::new(
"Give it a shot! Check the following checkbox to be able to \
see element boundaries.",
))
.push(if cfg!(target_arch = "wasm32") {
Element::new(
Text::new("Not available on web yet!")
.color([0.7, 0.7, 0.7])
.horizontal_alignment(HorizontalAlignment::Center),
)
} else {
Element::new(Checkbox::new(
debug,
"Explain layout",
StepMessage::DebugToggled,
))
})
.push(Text::new("Feel free to go back and take a look."))
}
fn end() -> Column<'a, StepMessage> {
Self::container("You reached the end!")
.push(Text::new(
"This tour will be updated as more features are added.",
))
.push(Text::new("Make sure to keep an eye on it!"))
}
}
fn ferris<'a>(_width: u16) -> Container<'a, StepMessage> {
Container::new(
// This should go away once we unify resource loading on native
// platforms
Text::new("sorry ferris, you can't come out in glow."),
)
.width(Length::Fill)
.center_x()
}
fn button<'a, Message: Clone>(
state: &'a mut button::State,
label: &str,
) -> Button<'a, Message> {
Button::new(
state,
Text::new(label).horizontal_alignment(HorizontalAlignment::Center),
)
.padding(12)
.min_width(100)
}
fn color_slider(
state: &mut slider::State,
component: f32,
update: impl Fn(f32) -> Color + 'static,
) -> Slider<f64, StepMessage> {
Slider::new(state, 0.0..=1.0, f64::from(component), move |c| {
StepMessage::TextColorChanged(update(c as f32))
})
.step(0.01)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Language {
Rust,
Elm,
Ruby,
Haskell,
C,
Other,
}
impl Language {
fn all() -> [Language; 6] {
[
Language::C,
Language::Elm,
Language::Ruby,
Language::Haskell,
Language::Rust,
Language::Other,
]
}
}
impl From<Language> for String {
fn from(language: Language) -> String {
String::from(match language {
Language::Rust => "Rust",
Language::Elm => "Elm",
Language::Ruby => "Ruby",
Language::Haskell => "Haskell",
Language::C => "C",
Language::Other => "Other",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Layout {
Row,
Column,
}
mod style {
use iced::{button, Background, Color, Vector};
pub enum Button {
Primary,
Secondary,
}
impl button::StyleSheet for Button {
fn active(&self) -> button::Style {
button::Style {
background: Some(Background::Color(match self {
Button::Primary => Color::from_rgb(0.11, 0.42, 0.87),
Button::Secondary => Color::from_rgb(0.5, 0.5, 0.5),
})),
border_radius: 12.0,
shadow_offset: Vector::new(1.0, 1.0),
text_color: Color::from_rgb8(0xEE, 0xEE, 0xEE),
..button::Style::default()
}
}
fn hovered(&self) -> button::Style {
button::Style {
text_color: Color::WHITE,
shadow_offset: Vector::new(1.0, 2.0),
..self.active()
}
}
}
}

View File

@ -1,10 +0,0 @@
[package]
name = "url_handler"
version = "0.1.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
publish = false
[dependencies]
iced = { path = "../.." }
iced_native = { path = "../../native" }

View File

@ -1,73 +0,0 @@
use iced::{
executor, Application, Clipboard, Command, Container, Element, Length,
Settings, Subscription, Text,
};
use iced_native::{
event::{MacOS, PlatformSpecific},
Event,
};
pub fn main() -> iced::Result {
App::run(Settings::default())
}
#[derive(Debug, Default)]
struct App {
url: Option<String>,
}
#[derive(Debug, Clone)]
enum Message {
EventOccurred(iced_native::Event),
}
impl Application for App {
type Executor = executor::Default;
type Message = Message;
type Flags = ();
fn new(_flags: ()) -> (App, Command<Message>) {
(App::default(), Command::none())
}
fn title(&self) -> String {
String::from("Url - Iced")
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
match message {
Message::EventOccurred(event) => {
if let Event::PlatformSpecific(PlatformSpecific::MacOS(
MacOS::ReceivedUrl(url),
)) = event
{
self.url = Some(url);
}
}
};
Command::none()
}
fn subscription(&self) -> Subscription<Message> {
iced_native::subscription::events().map(Message::EventOccurred)
}
fn view(&mut self) -> Element<Message> {
let content = match &self.url {
Some(url) => Text::new(format!("{}", url)),
None => Text::new("No URL received yet!"),
};
Container::new(content.size(48))
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "iced_futures"
version = "0.3.0"
version = "0.2.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "Commands, subscriptions, and runtimes for Iced"
@ -26,20 +26,15 @@ optional = true
features = ["rt-core", "rt-threaded", "time", "stream"]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio]
package = "tokio"
version = "1.0"
version = "0.3"
optional = true
features = ["rt", "rt-multi-thread", "time"]
features = ["rt-multi-thread", "time", "stream"]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.async-std]
version = "1.0"
optional = true
features = ["unstable"]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.smol]
version = "1.2"
optional = true
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen-futures = "0.4"

View File

@ -13,9 +13,6 @@ mod tokio_old;
#[cfg(all(not(target_arch = "wasm32"), feature = "async-std"))]
mod async_std;
#[cfg(all(not(target_arch = "wasm32"), feature = "smol"))]
mod smol;
#[cfg(target_arch = "wasm32")]
mod wasm_bindgen;
@ -33,9 +30,6 @@ pub use self::tokio_old::TokioOld;
#[cfg(all(not(target_arch = "wasm32"), feature = "async-std"))]
pub use self::async_std::AsyncStd;
#[cfg(all(not(target_arch = "wasm32"), feature = "smol"))]
pub use self::smol::Smol;
#[cfg(target_arch = "wasm32")]
pub use wasm_bindgen::WasmBindgen;

View File

@ -1,18 +0,0 @@
use crate::Executor;
use futures::Future;
/// A `smol` runtime.
#[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
#[derive(Debug)]
pub struct Smol;
impl Executor for Smol {
fn new() -> Result<Self, futures::io::Error> {
Ok(Self)
}
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static) {
smol::spawn(future).detach();
}
}

View File

@ -17,22 +17,10 @@ pub mod executor;
pub mod subscription;
#[cfg(all(
any(
feature = "tokio",
feature = "tokio_old",
feature = "async-std",
feature = "smol"
),
any(feature = "tokio", feature = "tokio_old", feature = "async-std"),
not(target_arch = "wasm32")
))]
#[cfg_attr(
docsrs,
doc(cfg(any(
feature = "tokio",
feature = "async-std",
feature = "smol"
)))
)]
#[cfg_attr(docsrs, doc(cfg(any(feature = "tokio", feature = "async-std"))))]
pub mod time;
pub use command::Command;

View File

@ -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
/// to listen to time.
///
/// [examples]: https://github.com/hecrj/iced/tree/0.3/examples
/// [`download_progress`]: https://github.com/hecrj/iced/tree/0.3/examples/download_progress
/// [`stopwatch`]: https://github.com/hecrj/iced/tree/0.3/examples/stopwatch
/// [examples]: https://github.com/hecrj/iced/tree/0.2/examples
/// [`download_progress`]: https://github.com/hecrj/iced/tree/0.2/examples/download_progress
/// [`stopwatch`]: https://github.com/hecrj/iced/tree/0.2/examples/stopwatch
pub trait Recipe<Hasher: std::hash::Hasher, Event> {
/// The events that will be produced by a [`Subscription`] with this
/// [`Recipe`].

View File

@ -135,7 +135,7 @@ where
.filter_map(|connection| connection.listener.as_mut())
.for_each(|listener| {
if let Err(error) = listener.try_send(event.clone()) {
log::warn!(
log::error!(
"Error sending event to subscription: {:?}",
error
);

View File

@ -13,33 +13,6 @@ pub fn every<H: std::hash::Hasher, E>(
struct Every(std::time::Duration);
#[cfg(all(
not(any(feature = "tokio_old", feature = "tokio", feature = "async-std")),
feature = "smol"
))]
impl<H, E> subscription::Recipe<H, E> for Every
where
H: std::hash::Hasher,
{
type Output = std::time::Instant;
fn hash(&self, state: &mut H) {
use std::hash::Hash;
std::any::TypeId::of::<Self>().hash(state);
self.0.hash(state);
}
fn stream(
self: Box<Self>,
_input: futures::stream::BoxStream<'static, E>,
) -> futures::stream::BoxStream<'static, Self::Output> {
use futures::stream::StreamExt;
smol::Timer::interval(self.0).boxed()
}
}
#[cfg(feature = "async-std")]
impl<H, E> subscription::Recipe<H, E> for Every
where
@ -68,7 +41,7 @@ where
#[cfg(all(
any(feature = "tokio", feature = "tokio_old"),
not(any(feature = "async-std", feature = "smol"))
not(feature = "async-std")
))]
impl<H, E> subscription::Recipe<H, E> for Every
where
@ -94,20 +67,8 @@ where
let start = tokio::time::Instant::now() + self.0;
let stream = {
#[cfg(feature = "tokio")]
{
futures::stream::unfold(
tokio::time::interval_at(start, self.0),
|mut interval| async move {
Some((interval.tick().await, interval))
},
)
}
#[cfg(feature = "tokio_old")]
tokio::time::interval_at(start, self.0)
};
stream.map(tokio::time::Instant::into_std).boxed()
.map(|_| std::time::Instant::now())
.boxed()
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "iced_glow"
version = "0.2.0"
version = "0.1.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "A glow renderer for iced"
@ -17,18 +17,18 @@ svg = []
[dependencies]
glow = "0.6"
glow_glyph = { version = "0.4", git = "https://bics.ga/reivilibre/glow_glyph_compat.git", commit = "13ce059bdfe1b3745fa222d73fb2faaf0ec0311d" }
glow_glyph = "0.4"
glyph_brush = "0.7"
euclid = "0.22"
bytemuck = "1.4"
log = "0.4"
[dependencies.iced_native]
version = "0.4"
version = "0.3"
path = "../native"
[dependencies.iced_graphics]
version = "0.2"
version = "0.1"
path = "../graphics"
features = ["font-fallback", "font-icons", "opengl"]

View File

@ -17,7 +17,7 @@ pub unsafe fn create(
gl.compile_shader(shader);
if !gl.get_shader_compile_status(shader) {
panic!("{}", gl.get_shader_info_log(shader));
panic!(gl.get_shader_info_log(shader));
}
gl.attach_shader(program, shader);
@ -27,7 +27,7 @@ pub unsafe fn create(
gl.link_program(program);
if !gl.get_program_link_status(program) {
panic!("{}", gl.get_program_info_log(program));
panic!(gl.get_program_info_log(program));
}
for shader in shaders {

View File

@ -6,13 +6,6 @@ use iced_native::Rectangle;
const MAX_INSTANCES: usize = 100_000;
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct QuadWithQPos(layer::Quad, [f32; 2]);
unsafe impl bytemuck::Zeroable for QuadWithQPos {}
unsafe impl bytemuck::Pod for QuadWithQPos {}
#[derive(Debug)]
pub struct Pipeline {
program: <glow::Context as HasContext>::Program,
@ -140,34 +133,23 @@ impl Pipeline {
let mut i = 0;
let total = instances.len();
let mut tagged_instances: Vec<QuadWithQPos> = Vec::new();
let pos_map = [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]];
while i < total {
let end = (i + MAX_INSTANCES).min(total);
let amount = end - i;
unsafe {
tagged_instances.clear();
tagged_instances.reserve((end - i) * 4);
for quad in instances[i..end].iter() {
tagged_instances.push(QuadWithQPos(*quad, pos_map[0]));
tagged_instances.push(QuadWithQPos(*quad, pos_map[1]));
tagged_instances.push(QuadWithQPos(*quad, pos_map[2]));
tagged_instances.push(QuadWithQPos(*quad, pos_map[3]));
}
gl.buffer_sub_data_u8_slice(
glow::ARRAY_BUFFER,
0,
bytemuck::cast_slice(&tagged_instances),
bytemuck::cast_slice(&instances[i..end]),
);
for j in 0..amount as i32 {
gl.draw_arrays(glow::TRIANGLE_STRIP, j * 4, 4);
}
gl.draw_arrays_instanced(
glow::TRIANGLE_STRIP,
0,
4,
amount as i32,
);
}
i += MAX_INSTANCES;
@ -195,20 +177,23 @@ unsafe fn create_instance_buffer(
gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer));
gl.buffer_data_size(
glow::ARRAY_BUFFER,
(size * std::mem::size_of::<QuadWithQPos>()) as i32,
(size * std::mem::size_of::<layer::Quad>()) as i32,
glow::DYNAMIC_DRAW,
);
let stride = std::mem::size_of::<QuadWithQPos>() as i32;
let stride = std::mem::size_of::<layer::Quad>() as i32;
gl.enable_vertex_attrib_array(0);
gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0);
gl.vertex_attrib_divisor(0, 1);
gl.enable_vertex_attrib_array(1);
gl.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, stride, 4 * 2);
gl.vertex_attrib_divisor(1, 1);
gl.enable_vertex_attrib_array(2);
gl.vertex_attrib_pointer_f32(2, 4, glow::FLOAT, false, stride, 4 * (2 + 2));
gl.vertex_attrib_divisor(2, 1);
gl.enable_vertex_attrib_array(3);
gl.vertex_attrib_pointer_f32(
@ -219,6 +204,7 @@ unsafe fn create_instance_buffer(
stride,
4 * (2 + 2 + 4),
);
gl.vertex_attrib_divisor(3, 1);
gl.enable_vertex_attrib_array(4);
gl.vertex_attrib_pointer_f32(
@ -229,6 +215,7 @@ unsafe fn create_instance_buffer(
stride,
4 * (2 + 2 + 4 + 4),
);
gl.vertex_attrib_divisor(4, 1);
gl.enable_vertex_attrib_array(5);
gl.vertex_attrib_pointer_f32(
@ -239,17 +226,7 @@ unsafe fn create_instance_buffer(
stride,
4 * (2 + 2 + 4 + 4 + 1),
);
// q_Pos
gl.enable_vertex_attrib_array(6);
gl.vertex_attrib_pointer_f32(
6,
2,
glow::FLOAT,
false,
stride,
4 * (2 + 2 + 4 + 4 + 1 + 1),
);
gl.vertex_attrib_divisor(5, 1);
gl.bind_vertex_array(None);
gl.bind_buffer(glow::ARRAY_BUFFER, None);

View File

@ -29,12 +29,3 @@ impl Default for Settings {
}
}
}
impl Settings {
/// Creates new [`Settings`] using environment configuration.
///
/// Currently, this is equivalent to calling [`Settings::default`].
pub fn from_env() -> Self {
Self::default()
}
}

View File

@ -1,13 +1,15 @@
#version 120
#version 330
uniform float u_ScreenHeight;
varying vec4 v_Color;
varying vec4 v_BorderColor;
varying vec2 v_Pos;
varying vec2 v_Scale;
varying float v_BorderRadius;
varying float v_BorderWidth;
in vec4 v_Color;
in vec4 v_BorderColor;
in vec2 v_Pos;
in vec2 v_Scale;
in float v_BorderRadius;
in float v_BorderWidth;
out vec4 o_Color;
float distance(in vec2 frag_coord, in vec2 position, in vec2 size, float radius)
{
@ -64,5 +66,5 @@ void main() {
float radius_alpha =
1.0 - smoothstep(max(v_BorderRadius - 0.5, 0.0), v_BorderRadius + 0.5, d);
gl_FragColor = vec4(mixed_color.xyz, mixed_color.w * radius_alpha);
o_Color = vec4(mixed_color.xyz, mixed_color.w * radius_alpha);
}

View File

@ -1,24 +1,31 @@
#version 120
#version 330
uniform mat4 u_Transform;
uniform float u_Scale;
attribute vec2 i_Pos;
attribute vec2 i_Scale;
attribute vec4 i_Color;
attribute vec4 i_BorderColor;
attribute float i_BorderRadius;
attribute float i_BorderWidth;
attribute vec2 q_Pos;
layout(location = 0) in vec2 i_Pos;
layout(location = 1) in vec2 i_Scale;
layout(location = 2) in vec4 i_Color;
layout(location = 3) in vec4 i_BorderColor;
layout(location = 4) in float i_BorderRadius;
layout(location = 5) in float i_BorderWidth;
varying vec4 v_Color;
varying vec4 v_BorderColor;
varying vec2 v_Pos;
varying vec2 v_Scale;
varying float v_BorderRadius;
varying float v_BorderWidth;
out vec4 v_Color;
out vec4 v_BorderColor;
out vec2 v_Pos;
out vec2 v_Scale;
out float v_BorderRadius;
out float v_BorderWidth;
const vec2 positions[4] = vec2[](
vec2(0.0, 0.0),
vec2(0.0, 1.0),
vec2(1.0, 0.0),
vec2(1.0, 1.0)
);
void main() {
vec2 q_Pos = positions[gl_VertexID];
vec2 p_Pos = i_Pos * u_Scale;
vec2 p_Scale = i_Scale * u_Scale;

View File

@ -1,7 +1,9 @@
#version 120
#version 330
varying vec4 v_Color;
in vec4 v_Color;
out vec4 o_Color;
void main() {
gl_FragColor = v_Color;
o_Color = v_Color;
}

View File

@ -1,11 +1,11 @@
#version 120
#version 330
uniform mat4 u_Transform;
attribute vec2 i_Position;
attribute vec4 i_Color;
layout(location = 0) in vec2 i_Position;
layout(location = 1) in vec4 i_Color;
varying vec4 v_Color;
out vec4 v_Color;
void main() {
gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0);

View File

@ -20,8 +20,6 @@ pub mod rule;
pub mod scrollable;
pub mod slider;
pub mod text_input;
pub mod toggler;
pub mod tooltip;
#[doc(no_inline)]
pub use button::Button;
@ -45,10 +43,6 @@ pub use scrollable::Scrollable;
pub use slider::Slider;
#[doc(no_inline)]
pub use text_input::TextInput;
#[doc(no_inline)]
pub use toggler::Toggler;
#[doc(no_inline)]
pub use tooltip::Tooltip;
#[cfg(feature = "canvas")]
#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))]

View File

@ -6,12 +6,12 @@
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
//! drag and drop, and hotkey support.
//!
//! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.3/examples/pane_grid
//! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.2/examples/pane_grid
use crate::Renderer;
pub use iced_graphics::pane_grid::{
Axis, Configuration, Direction, DragEvent, Line, Node, Pane, ResizeEvent,
Split, State, StyleSheet,
pub use iced_native::pane_grid::{
Axis, Configuration, Direction, DragEvent, Node, Pane, ResizeEvent, Split,
State,
};
/// A collection of panes distributed using either vertical or horizontal splits

View File

@ -1,9 +0,0 @@
//! Show toggle controls using togglers.
use crate::Renderer;
pub use iced_graphics::toggler::{Style, StyleSheet};
/// A toggler that can be toggled.
///
/// This is an alias of an `iced_native` checkbox with an `iced_wgpu::Renderer`.
pub type Toggler<Message> = iced_native::Toggler<Message, Renderer>;

View File

@ -1,6 +0,0 @@
//! Display a widget over another.
/// A widget allowing the selection of a single value from a list of options.
pub type Tooltip<'a, Message> =
iced_native::Tooltip<'a, Message, crate::Renderer>;
pub use iced_native::tooltip::Position;

View File

@ -1,6 +1,6 @@
[package]
name = "iced_glutin"
version = "0.2.0"
version = "0.1.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "A glutin runtime for Iced"
@ -13,20 +13,18 @@ categories = ["gui"]
[features]
debug = ["iced_winit/debug"]
[dependencies.glutin]
version = "0.27"
git = "https://github.com/iced-rs/glutin"
rev = "be6793b5b3defc9452cd1c896cd315ed7442d546"
[dependencies]
glutin = "0.25"
[dependencies.iced_native]
version = "0.4"
version = "0.3"
path = "../native"
[dependencies.iced_winit]
version = "0.3"
version = "0.2"
path = "../winit"
[dependencies.iced_graphics]
version = "0.2"
version = "0.1"
path = "../graphics"
features = ["opengl"]

View File

@ -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`:
```toml
iced_glutin = "0.2"
iced_glutin = "0.1"
```
__Iced moves fast and the `master` branch can contain breaking changes!__ If

View File

@ -92,11 +92,10 @@ where
application,
compositor,
renderer,
context,
runtime,
debug,
receiver,
context,
settings.exit_on_close_request,
));
let mut context = task::Context::from_waker(task::noop_waker_ref());
@ -108,22 +107,7 @@ where
return;
}
let event = match event {
glutin::event::Event::WindowEvent {
event:
glutin::event::WindowEvent::ScaleFactorChanged {
new_inner_size,
..
},
window_id,
} => Some(glutin::event::Event::WindowEvent {
event: glutin::event::WindowEvent::Resized(*new_inner_size),
window_id,
}),
_ => event.to_static(),
};
if let Some(event) = event {
if let Some(event) = event.to_static() {
sender.start_send(event).expect("Send event");
let poll = instance.as_mut().poll(&mut context);
@ -140,11 +124,10 @@ async fn run_instance<A, E, C>(
mut application: A,
mut compositor: C,
mut renderer: A::Renderer,
context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>,
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
mut debug: Debug,
mut receiver: mpsc::UnboundedReceiver<glutin::event::Event<'_, A::Message>>,
context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>,
exit_on_close_request: bool,
) where
A: Application + 'static,
E: Executor + 'static,
@ -153,7 +136,7 @@ async fn run_instance<A, E, C>(
use glutin::event;
use iced_winit::futures::stream::StreamExt;
let mut clipboard = Clipboard::connect(context.window());
let clipboard = Clipboard::new(context.window());
let mut state = application::State::new(&application, context.window());
let mut viewport_version = state.viewport_version();
@ -187,8 +170,8 @@ async fn run_instance<A, E, C>(
let statuses = user_interface.update(
&events,
state.cursor_position(),
clipboard.as_ref().map(|c| c as _),
&mut renderer,
&mut clipboard,
&mut messages,
);
@ -207,15 +190,12 @@ async fn run_instance<A, E, C>(
&mut application,
&mut runtime,
&mut debug,
&mut clipboard,
&mut messages,
);
// Update window
state.synchronize(&application, context.window());
let should_exit = application.should_exit();
user_interface =
ManuallyDrop::new(application::build_user_interface(
&mut application,
@ -224,10 +204,6 @@ async fn run_instance<A, E, C>(
state.logical_size(),
&mut debug,
));
if should_exit {
break;
}
}
debug.draw_started();
@ -237,16 +213,6 @@ async fn run_instance<A, E, C>(
context.window().request_redraw();
}
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
event::MacOS::ReceivedUrl(url),
)) => {
use iced_native::event;
events.push(iced_native::Event::PlatformSpecific(
event::PlatformSpecific::MacOS(event::MacOS::ReceivedUrl(
url,
)),
));
}
event::Event::UserEvent(message) => {
messages.push(message);
}
@ -308,7 +274,6 @@ async fn run_instance<A, E, C>(
..
} => {
if application::requests_exit(&window_event, state.modifiers())
&& exit_on_close_request
{
break;
}

View File

@ -17,7 +17,7 @@ pub use iced_native::*;
pub mod application;
pub use iced_winit::settings;
pub use iced_winit::{Clipboard, Error, Mode};
pub use iced_winit::{Error, Mode};
#[doc(no_inline)]
pub use application::Application;

View File

@ -1,6 +1,6 @@
[package]
name = "iced_graphics"
version = "0.2.0"
version = "0.1.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "A bunch of backend-agnostic types that can be leveraged to build a renderer for Iced"
@ -28,11 +28,11 @@ version = "1.4"
features = ["derive"]
[dependencies.iced_native]
version = "0.4"
version = "0.3"
path = "../native"
[dependencies.iced_style]
version = "0.3"
version = "0.2"
path = "../style"
[dependencies.lyon]
@ -42,10 +42,9 @@ optional = true
[dependencies.qrcode]
version = "0.12"
optional = true
default-features = false
[dependencies.font-kit]
version = "0.10"
version = "0.8"
optional = true
[package.metadata.docs.rs]

View File

@ -82,12 +82,7 @@ impl<'a> Layer<'a> {
let mut layers = vec![first_layer];
Self::process_primitive(
&mut layers,
Vector::new(0.0, 0.0),
primitive,
0,
);
Self::process_primitive(&mut layers, Vector::new(0.0, 0.0), primitive);
layers
}
@ -96,19 +91,13 @@ impl<'a> Layer<'a> {
layers: &mut Vec<Self>,
translation: Vector,
primitive: &'a Primitive,
current_layer: usize,
) {
match primitive {
Primitive::None => {}
Primitive::Group { primitives } => {
// TODO: Inspect a bit and regroup (?)
for primitive in primitives {
Self::process_primitive(
layers,
translation,
primitive,
current_layer,
)
Self::process_primitive(layers, translation, primitive)
}
}
Primitive::Text {
@ -120,7 +109,7 @@ impl<'a> Layer<'a> {
horizontal_alignment,
vertical_alignment,
} => {
let layer = &mut layers[current_layer];
let layer = layers.last_mut().unwrap();
layer.text.push(Text {
content,
@ -139,7 +128,7 @@ impl<'a> Layer<'a> {
border_width,
border_color,
} => {
let layer = &mut layers[current_layer];
let layer = layers.last_mut().unwrap();
// TODO: Move some of these computations to the GPU (?)
layer.quads.push(Quad {
@ -157,7 +146,7 @@ impl<'a> Layer<'a> {
});
}
Primitive::Mesh2D { buffers, size } => {
let layer = &mut layers[current_layer];
let layer = layers.last_mut().unwrap();
let bounds = Rectangle::new(
Point::new(translation.x, translation.y),
@ -178,7 +167,7 @@ impl<'a> Layer<'a> {
offset,
content,
} => {
let layer = &mut layers[current_layer];
let layer = layers.last_mut().unwrap();
let translated_bounds = *bounds + translation;
// Only draw visible content
@ -186,15 +175,16 @@ impl<'a> Layer<'a> {
layer.bounds.intersection(&translated_bounds)
{
let clip_layer = Layer::new(clip_bounds);
layers.push(clip_layer);
let new_layer = Layer::new(layer.bounds);
layers.push(clip_layer);
Self::process_primitive(
layers,
translation
- Vector::new(offset.x as f32, offset.y as f32),
content,
layers.len() - 1,
);
layers.push(new_layer);
}
}
Primitive::Translate {
@ -205,19 +195,13 @@ impl<'a> Layer<'a> {
layers,
translation + *new_translation,
&content,
current_layer,
);
}
Primitive::Cached { cache } => {
Self::process_primitive(
layers,
translation,
&cache,
current_layer,
);
Self::process_primitive(layers, translation, &cache);
}
Primitive::Image { handle, bounds } => {
let layer = &mut layers[current_layer];
let layer = layers.last_mut().unwrap();
layer.images.push(Image::Raster {
handle: handle.clone(),
@ -225,7 +209,7 @@ impl<'a> Layer<'a> {
});
}
Primitive::Svg { handle, bounds } => {
let layer = &mut layers[current_layer];
let layer = layers.last_mut().unwrap();
layer.images.push(Image::Vector {
handle: handle.clone(),

View File

@ -2,8 +2,8 @@
use crate::backend::{self, Backend};
use crate::{Primitive, Renderer};
use iced_native::{
mouse, overlay, Color, Font, HorizontalAlignment, Padding, Point,
Rectangle, VerticalAlignment,
mouse, overlay, Color, Font, HorizontalAlignment, Point, Rectangle,
VerticalAlignment,
};
pub use iced_style::menu::Style;
@ -45,7 +45,7 @@ where
viewport: &Rectangle,
options: &[T],
hovered_option: Option<usize>,
padding: Padding,
padding: u16,
text_size: u16,
font: Font,
style: &Style,
@ -53,7 +53,7 @@ where
use std::f32;
let is_mouse_over = bounds.contains(cursor_position);
let option_height = (text_size + padding.vertical()) as usize;
let option_height = text_size as usize + padding as usize * 2;
let mut primitives = Vec::new();
@ -72,7 +72,7 @@ where
x: bounds.x,
y: bounds.y + (option_height * i) as f32,
width: bounds.width,
height: f32::from(text_size + padding.vertical()),
height: f32::from(text_size + padding * 2),
};
if is_selected {
@ -88,7 +88,7 @@ where
primitives.push(Primitive::Text {
content: option.to_string(),
bounds: Rectangle {
x: bounds.x + padding.left as f32,
x: bounds.x + f32::from(padding),
y: bounds.center_y(),
width: f32::INFINITY,
..bounds

View File

@ -31,7 +31,7 @@ impl Viewport {
/// Returns the physical width of the [`Viewport`].
pub fn physical_width(&self) -> u32 {
self.physical_size.width
self.physical_size.height
}
/// Returns the physical height of the [`Viewport`].

View File

@ -20,8 +20,6 @@ pub mod scrollable;
pub mod slider;
pub mod svg;
pub mod text_input;
pub mod toggler;
pub mod tooltip;
mod column;
mod row;
@ -50,10 +48,6 @@ pub use scrollable::Scrollable;
pub use slider::Slider;
#[doc(no_inline)]
pub use text_input::TextInput;
#[doc(no_inline)]
pub use toggler::Toggler;
#[doc(no_inline)]
pub use tooltip::Tooltip;
pub use column::Column;
pub use image::Image;

View File

@ -5,7 +5,7 @@ use crate::defaults::{self, Defaults};
use crate::{Backend, Primitive, Renderer};
use iced_native::mouse;
use iced_native::{
Background, Color, Element, Layout, Padding, Point, Rectangle, Vector,
Background, Color, Element, Layout, Point, Rectangle, Vector,
};
pub use iced_native::button::State;
@ -21,7 +21,7 @@ impl<B> iced_native::button::Renderer for Renderer<B>
where
B: Backend,
{
const DEFAULT_PADDING: Padding = Padding::new(5);
const DEFAULT_PADDING: u16 = 5;
type Style = Box<dyn StyleSheet>;

View File

@ -154,9 +154,9 @@ where
event: iced_native::Event,
layout: Layout<'_>,
cursor_position: Point,
_renderer: &Renderer<B>,
_clipboard: &mut dyn Clipboard,
messages: &mut Vec<Message>,
_renderer: &Renderer<B>,
_clipboard: Option<&dyn Clipboard>,
) -> event::Status {
let bounds = layout.bounds();

View File

@ -54,7 +54,7 @@ impl Frame {
self.size.width
}
/// Returns the height of the [`Frame`].
/// Returns the width of the [`Frame`].
#[inline]
pub fn height(&self) -> f32 {
self.size.height

View File

@ -34,7 +34,7 @@ pub trait Program<Message> {
/// [`Geometry`] can be easily generated with a [`Frame`] or stored in a
/// [`Cache`].
///
/// [`Frame`]: crate::widget::canvas::Frame
/// [`Frame`]: crate::widget::canvas::Cache
/// [`Cache`]: crate::widget::canvas::Cache
fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec<Geometry>;

View File

@ -1,14 +1,11 @@
//! Display images in your user interface.
pub mod viewer;
use crate::backend::{self, Backend};
use crate::{Primitive, Renderer};
use iced_native::image;
use iced_native::mouse;
use iced_native::Layout;
pub use iced_native::image::{Handle, Image, Viewer};
pub use iced_native::image::{Handle, Image};
impl<B> image::Renderer for Renderer<B>
where

View File

@ -1,55 +0,0 @@
//! Zoom and pan on an image.
use crate::backend::{self, Backend};
use crate::{Primitive, Renderer};
use iced_native::image;
use iced_native::image::viewer;
use iced_native::mouse;
use iced_native::{Rectangle, Size, Vector};
impl<B> viewer::Renderer for Renderer<B>
where
B: Backend + backend::Image,
{
fn draw(
&mut self,
state: &viewer::State,
bounds: Rectangle,
image_size: Size,
translation: Vector,
handle: image::Handle,
is_mouse_over: bool,
) -> Self::Output {
(
{
Primitive::Clip {
bounds,
content: Box::new(Primitive::Translate {
translation,
content: Box::new(Primitive::Image {
handle,
bounds: Rectangle {
x: bounds.x,
y: bounds.y,
..Rectangle::with_size(image_size)
},
}),
}),
offset: Vector::new(0, 0),
}
},
{
if state.is_cursor_grabbed() {
mouse::Interaction::Grabbing
} else if is_mouse_over
&& (image_size.width > bounds.width
|| image_size.height > bounds.height)
{
mouse::Interaction::Grab
} else {
mouse::Interaction::Idle
}
},
)
}
}

View File

@ -6,20 +6,22 @@
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
//! drag and drop, and hotkey support.
//!
//! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.3/examples/pane_grid
//! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.2/examples/pane_grid
use crate::backend::{self, Backend};
use crate::defaults;
use crate::{Backend, Color, Primitive, Renderer};
use iced_native::container;
use crate::{Primitive, Renderer};
use iced_native::mouse;
use iced_native::pane_grid;
use iced_native::{Element, Layout, Point, Rectangle, Vector};
pub use iced_native::pane_grid::{
Axis, Configuration, Content, Direction, DragEvent, Node, Pane,
ResizeEvent, Split, State, TitleBar,
use iced_native::text;
use iced_native::{
Element, HorizontalAlignment, Layout, Point, Rectangle, Vector,
VerticalAlignment,
};
pub use iced_style::pane_grid::{Line, StyleSheet};
pub use iced_native::pane_grid::{
Axis, Configuration, Content, Direction, DragEvent, Pane, ResizeEvent,
Split, State, TitleBar,
};
/// A collection of panes distributed using either vertical or horizontal splits
/// to completely fill the space available.
@ -32,20 +34,16 @@ pub type PaneGrid<'a, Message, Backend> =
impl<B> pane_grid::Renderer for Renderer<B>
where
B: Backend,
B: Backend + backend::Text,
{
type Style = Box<dyn StyleSheet>;
fn draw<Message>(
&mut self,
defaults: &Self::Defaults,
content: &[(Pane, Content<'_, Message, Self>)],
dragging: Option<(Pane, Point)>,
resizing: Option<(Axis, Rectangle, bool)>,
resizing: Option<Axis>,
layout: Layout<'_>,
style_sheet: &<Self as pane_grid::Renderer>::Style,
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output {
let pane_cursor_position = if dragging.is_some() {
// TODO: Remove once cursor availability is encoded in the type
@ -63,13 +61,8 @@ where
.zip(layout.children())
.enumerate()
.map(|(i, ((id, pane), layout))| {
let (primitive, new_mouse_interaction) = pane.draw(
self,
defaults,
layout,
pane_cursor_position,
viewport,
);
let (primitive, new_mouse_interaction) =
pane.draw(self, defaults, layout, pane_cursor_position);
if new_mouse_interaction > mouse_interaction {
mouse_interaction = new_mouse_interaction;
@ -85,8 +78,7 @@ where
})
.collect();
let mut primitives = if let Some((index, layout, origin)) = dragged_pane
{
let primitives = if let Some((index, layout, origin)) = dragged_pane {
let pane = panes.remove(index);
let bounds = layout.bounds();
@ -116,62 +108,15 @@ where
panes
};
let (primitives, mouse_interaction) =
if let Some((axis, split_region, is_picked)) = resizing {
let highlight = if is_picked {
style_sheet.picked_split()
} else {
style_sheet.hovered_split()
};
if let Some(highlight) = highlight {
primitives.push(Primitive::Quad {
bounds: match axis {
Axis::Horizontal => Rectangle {
x: split_region.x,
y: (split_region.y
+ (split_region.height - highlight.width)
/ 2.0)
.round(),
width: split_region.width,
height: highlight.width,
},
Axis::Vertical => Rectangle {
x: (split_region.x
+ (split_region.width - highlight.width)
/ 2.0)
.round(),
y: split_region.y,
width: highlight.width,
height: split_region.height,
},
},
background: highlight.color.into(),
border_radius: 0.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
});
}
(
primitives,
match axis {
Axis::Horizontal => {
mouse::Interaction::ResizingVertically
}
Axis::Vertical => {
mouse::Interaction::ResizingHorizontally
}
},
)
} else {
(primitives, mouse_interaction)
};
(
Primitive::Group { primitives },
if dragging.is_some() {
mouse::Interaction::Grabbing
} else if let Some(axis) = resizing {
match axis {
Axis::Horizontal => mouse::Interaction::ResizingVertically,
Axis::Vertical => mouse::Interaction::ResizingHorizontally,
}
} else {
mouse_interaction
},
@ -182,17 +127,16 @@ where
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
style_sheet: &<Self as container::Renderer>::Style,
style_sheet: &Self::Style,
title_bar: Option<(&TitleBar<'_, Message, Self>, Layout<'_>)>,
body: (&Element<'_, Message, Self>, Layout<'_>),
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output {
let style = style_sheet.style();
let (body, body_layout) = body;
let (body_primitive, body_interaction) =
body.draw(self, defaults, body_layout, cursor_position, viewport);
body.draw(self, defaults, body_layout, cursor_position, &bounds);
let background = crate::widget::container::background(bounds, &style);
@ -206,7 +150,6 @@ where
defaults,
title_bar_layout,
cursor_position,
viewport,
show_controls,
);
@ -218,10 +161,10 @@ where
body_primitive,
],
},
if title_bar_interaction > body_interaction {
title_bar_interaction
} else if is_over_pick_area {
if is_over_pick_area {
mouse::Interaction::Grab
} else if title_bar_interaction > body_interaction {
title_bar_interaction
} else {
body_interaction
},
@ -244,14 +187,15 @@ where
&mut self,
defaults: &Self::Defaults,
bounds: Rectangle,
style_sheet: &<Self as container::Renderer>::Style,
content: (&Element<'_, Message, Self>, Layout<'_>),
style_sheet: &Self::Style,
title: &str,
title_size: u16,
title_font: Self::Font,
title_bounds: Rectangle,
controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>,
cursor_position: Point,
viewport: &Rectangle,
) -> Self::Output {
let style = style_sheet.style();
let (title_content, title_layout) = content;
let defaults = Self::Defaults {
text: defaults::Text {
@ -261,12 +205,16 @@ where
let background = crate::widget::container::background(bounds, &style);
let (title_primitive, title_interaction) = title_content.draw(
let (title_primitive, _) = text::Renderer::draw(
self,
&defaults,
title_layout,
cursor_position,
viewport,
title_bounds,
title,
title_size,
title_font,
None,
HorizontalAlignment::Left,
VerticalAlignment::Top,
);
if let Some((controls, controls_layout)) = controls {
@ -275,7 +223,7 @@ where
&defaults,
controls_layout,
cursor_position,
viewport,
&bounds,
);
(
@ -286,7 +234,7 @@ where
controls_primitive,
],
},
controls_interaction.max(title_interaction),
controls_interaction,
)
} else {
(
@ -297,7 +245,7 @@ where
} else {
title_primitive
},
title_interaction,
mouse::Interaction::default(),
)
}
}

View File

@ -2,8 +2,7 @@
use crate::backend::{self, Backend};
use crate::{Primitive, Renderer};
use iced_native::{
mouse, Font, HorizontalAlignment, Padding, Point, Rectangle,
VerticalAlignment,
mouse, Font, HorizontalAlignment, Point, Rectangle, VerticalAlignment,
};
use iced_style::menu;
@ -20,7 +19,7 @@ where
{
type Style = Box<dyn StyleSheet>;
const DEFAULT_PADDING: Padding = Padding::new(5);
const DEFAULT_PADDING: u16 = 5;
fn menu_style(style: &Box<dyn StyleSheet>) -> menu::Style {
style.menu()
@ -31,7 +30,7 @@ where
bounds: Rectangle,
cursor_position: Point,
selected: Option<String>,
padding: Padding,
padding: u16,
text_size: u16,
font: Font,
style: &Box<dyn StyleSheet>,
@ -57,7 +56,7 @@ where
font: B::ICON_FONT,
size: bounds.height * style.icon_size,
bounds: Rectangle {
x: bounds.x + bounds.width - f32::from(padding.horizontal()),
x: bounds.x + bounds.width - f32::from(padding) * 2.0,
y: bounds.center_y(),
..bounds
},
@ -75,7 +74,7 @@ where
font,
color: style.text_color,
bounds: Rectangle {
x: bounds.x + f32::from(padding.left),
x: bounds.x + f32::from(padding),
y: bounds.center_y(),
..bounds
},

View File

@ -134,16 +134,8 @@ where
Primitive::None
};
let scroll = Primitive::Clip {
bounds,
offset: Vector::new(0, 0),
content: Box::new(Primitive::Group {
primitives: vec![scrollbar, scroller],
}),
};
Primitive::Group {
primitives: vec![clip, scroll],
primitives: vec![clip, scrollbar, scroller],
}
} else {
content

View File

@ -1,99 +0,0 @@
//! Show toggle controls using togglers.
use crate::backend::{self, Backend};
use crate::{Primitive, Renderer};
use iced_native::mouse;
use iced_native::toggler;
use iced_native::Rectangle;
pub use iced_style::toggler::{Style, StyleSheet};
/// Makes sure that the border radius of the toggler looks good at every size.
const BORDER_RADIUS_RATIO: f32 = 32.0 / 13.0;
/// The space ratio between the background Quad and the Toggler bounds, and
/// between the background Quad and foreground Quad.
const SPACE_RATIO: f32 = 0.05;
/// A toggler that can be toggled.
///
/// This is an alias of an `iced_native` toggler with an `iced_wgpu::Renderer`.
pub type Toggler<Message, Backend> =
iced_native::Toggler<Message, Renderer<Backend>>;
impl<B> toggler::Renderer for Renderer<B>
where
B: Backend + backend::Text,
{
type Style = Box<dyn StyleSheet>;
const DEFAULT_SIZE: u16 = 20;
fn draw(
&mut self,
bounds: Rectangle,
is_active: bool,
is_mouse_over: bool,
label: Option<Self::Output>,
style_sheet: &Self::Style,
) -> Self::Output {
let style = if is_mouse_over {
style_sheet.hovered(is_active)
} else {
style_sheet.active(is_active)
};
let border_radius = bounds.height as f32 / BORDER_RADIUS_RATIO;
let space = SPACE_RATIO * bounds.height as f32;
let toggler_background_bounds = Rectangle {
x: bounds.x + space,
y: bounds.y + space,
width: bounds.width - (2.0 * space),
height: bounds.height - (2.0 * space),
};
let toggler_background = Primitive::Quad {
bounds: toggler_background_bounds,
background: style.background.into(),
border_radius,
border_width: 1.0,
border_color: style.background_border.unwrap_or(style.background),
};
let toggler_foreground_bounds = Rectangle {
x: bounds.x
+ if is_active {
bounds.width - 2.0 * space - (bounds.height - (4.0 * space))
} else {
2.0 * space
},
y: bounds.y + (2.0 * space),
width: bounds.height - (4.0 * space),
height: bounds.height - (4.0 * space),
};
let toggler_foreground = Primitive::Quad {
bounds: toggler_foreground_bounds,
background: style.foreground.into(),
border_radius,
border_width: 1.0,
border_color: style.foreground_border.unwrap_or(style.foreground),
};
(
Primitive::Group {
primitives: match label {
Some((l, _)) => {
vec![l, toggler_background, toggler_foreground]
}
None => vec![toggler_background, toggler_foreground],
},
},
if is_mouse_over {
mouse::Interaction::Pointer
} else {
mouse::Interaction::default()
},
)
}
}

View File

@ -1,168 +0,0 @@
//! Decorate content and apply alignment.
use crate::backend::{self, Backend};
use crate::defaults::{self, Defaults};
use crate::{Primitive, Renderer, Vector};
use iced_native::container;
use iced_native::layout::{self, Layout};
use iced_native::{Element, Padding, Point, Rectangle, Size, Text};
/// An element decorating some content.
///
/// This is an alias of an `iced_native` tooltip with a default
/// `Renderer`.
pub type Tooltip<'a, Message, Backend> =
iced_native::Tooltip<'a, Message, Renderer<Backend>>;
pub use iced_native::tooltip::Position;
impl<B> iced_native::tooltip::Renderer for Renderer<B>
where
B: Backend + backend::Text,
{
const DEFAULT_PADDING: u16 = 5;
fn draw<Message>(
&mut self,
defaults: &Defaults,
cursor_position: Point,
content_layout: Layout<'_>,
viewport: &Rectangle,
content: &Element<'_, Message, Self>,
tooltip: &Text<Self>,
position: Position,
style_sheet: &<Self as container::Renderer>::Style,
gap: u16,
padding: u16,
) -> Self::Output {
let (content, mouse_interaction) = content.draw(
self,
&defaults,
content_layout,
cursor_position,
viewport,
);
let bounds = content_layout.bounds();
if bounds.contains(cursor_position) {
use iced_native::Widget;
let gap = f32::from(gap);
let style = style_sheet.style();
let defaults = Defaults {
text: defaults::Text {
color: style.text_color.unwrap_or(defaults.text.color),
},
};
let text_layout = Widget::<(), Self>::layout(
tooltip,
self,
&layout::Limits::new(Size::ZERO, viewport.size())
.pad(Padding::new(padding)),
);
let padding = f32::from(padding);
let text_bounds = text_layout.bounds();
let x_center = bounds.x + (bounds.width - text_bounds.width) / 2.0;
let y_center =
bounds.y + (bounds.height - text_bounds.height) / 2.0;
let mut tooltip_bounds = {
let offset = match position {
Position::Top => Vector::new(
x_center,
bounds.y - text_bounds.height - gap - padding,
),
Position::Bottom => Vector::new(
x_center,
bounds.y + bounds.height + gap + padding,
),
Position::Left => Vector::new(
bounds.x - text_bounds.width - gap - padding,
y_center,
),
Position::Right => Vector::new(
bounds.x + bounds.width + gap + padding,
y_center,
),
Position::FollowCursor => Vector::new(
cursor_position.x,
cursor_position.y - text_bounds.height,
),
};
Rectangle {
x: offset.x - padding,
y: offset.y - padding,
width: text_bounds.width + padding * 2.0,
height: text_bounds.height + padding * 2.0,
}
};
if tooltip_bounds.x < viewport.x {
tooltip_bounds.x = viewport.x;
} else if viewport.x + viewport.width
< tooltip_bounds.x + tooltip_bounds.width
{
tooltip_bounds.x =
viewport.x + viewport.width - tooltip_bounds.width;
}
if tooltip_bounds.y < viewport.y {
tooltip_bounds.y = viewport.y;
} else if viewport.y + viewport.height
< tooltip_bounds.y + tooltip_bounds.height
{
tooltip_bounds.y =
viewport.y + viewport.height - tooltip_bounds.height;
}
let (tooltip, _) = Widget::<(), Self>::draw(
tooltip,
self,
&defaults,
Layout::with_offset(
Vector::new(
tooltip_bounds.x + padding,
tooltip_bounds.y + padding,
),
&text_layout,
),
cursor_position,
viewport,
);
(
Primitive::Group {
primitives: vec![
content,
Primitive::Clip {
bounds: *viewport,
offset: Vector::new(0, 0),
content: Box::new(
if let Some(background) =
crate::container::background(
tooltip_bounds,
&style,
)
{
Primitive::Group {
primitives: vec![background, tooltip],
}
} else {
tooltip
},
),
},
],
},
mouse_interaction,
)
} else {
(content, mouse_interaction)
}
}
}

View File

@ -17,10 +17,7 @@ pub trait Compositor: Sized {
type SwapChain;
/// Creates a new [`Compositor`].
fn new<W: HasRawWindowHandle>(
settings: Self::Settings,
compatible_window: Option<&W>,
) -> Result<(Self, Self::Renderer), Error>;
fn new(settings: Self::Settings) -> Result<(Self, Self::Renderer), Error>;
/// Crates a new [`Surface`] for the given window.
///

View File

@ -1,6 +1,6 @@
[package]
name = "iced_native"
version = "0.4.0"
version = "0.3.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "A renderer-agnostic library for native GUIs"
@ -16,10 +16,10 @@ unicode-segmentation = "1.6"
num-traits = "0.2"
[dependencies.iced_core]
version = "0.4"
version = "0.3"
path = "../core"
[dependencies.iced_futures]
version = "0.3"
version = "0.2"
path = "../futures"
features = ["thread-pool"]

View File

@ -28,7 +28,7 @@ To achieve this, it introduces a bunch of reusable interfaces:
Add `iced_native` as a dependency in your `Cargo.toml`:
```toml
iced_native = "0.4"
iced_native = "0.3"
```
__Iced moves fast and the `master` branch can contain breaking changes!__ If

View File

@ -1,23 +1,6 @@
//! Access the clipboard.
/// A buffer for short-term storage and transfer within and between
/// applications.
pub trait Clipboard {
/// Reads the current content of the [`Clipboard`] as text.
fn read(&self) -> Option<String>;
/// Writes the given text contents to the [`Clipboard`].
fn write(&mut self, contents: String);
}
/// A null implementation of the [`Clipboard`] trait.
#[derive(Debug, Clone, Copy)]
pub struct Null;
impl Clipboard for Null {
fn read(&self) -> Option<String> {
None
}
fn write(&mut self, _contents: String) {}
/// Returns the current content of the [`Clipboard`] as text.
fn content(&self) -> Option<String>;
}

View File

@ -223,17 +223,17 @@ where
event: Event,
layout: Layout<'_>,
cursor_position: Point,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
messages: &mut Vec<Message>,
renderer: &Renderer,
clipboard: Option<&dyn Clipboard>,
) -> event::Status {
self.widget.on_event(
event,
layout,
cursor_position,
messages,
renderer,
clipboard,
messages,
)
}
@ -311,9 +311,9 @@ where
event: Event,
layout: Layout<'_>,
cursor_position: Point,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
messages: &mut Vec<B>,
renderer: &Renderer,
clipboard: Option<&dyn Clipboard>,
) -> event::Status {
let mut original_messages = Vec::new();
@ -321,9 +321,9 @@ where
event,
layout,
cursor_position,
&mut original_messages,
renderer,
clipboard,
&mut original_messages,
);
original_messages
@ -401,17 +401,17 @@ where
event: Event,
layout: Layout<'_>,
cursor_position: Point,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
messages: &mut Vec<Message>,
renderer: &Renderer,
clipboard: Option<&dyn Clipboard>,
) -> event::Status {
self.element.widget.on_event(
event,
layout,
cursor_position,
messages,
renderer,
clipboard,
messages,
)
}

View File

@ -1,8 +1,5 @@
//! Handle events of a user interface.
use crate::keyboard;
use crate::mouse;
use crate::touch;
use crate::window;
use crate::{keyboard, mouse, window};
/// A user interface event.
///
@ -20,30 +17,6 @@ pub enum Event {
/// A window event
Window(window::Event),
/// A touch event
Touch(touch::Event),
/// A platform specific event
PlatformSpecific(PlatformSpecific),
}
/// A platform specific event
#[derive(Debug, Clone, PartialEq)]
pub enum PlatformSpecific {
/// A MacOS specific event
MacOS(MacOS),
}
/// Describes an event specific to MacOS
#[derive(Debug, Clone, PartialEq)]
pub enum MacOS {
/// Triggered when the app receives an URL from the system
///
/// _**Note:** For this event to be triggered, the executable needs to be properly [bundled]!_
///
/// [bundled]: https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW19
ReceivedUrl(String),
}
/// The status of an [`Event`] after being processed.

View File

@ -19,14 +19,11 @@ pub struct Layout<'a> {
}
impl<'a> Layout<'a> {
/// Creates a new [`Layout`] for the given [`Node`] at the origin.
pub fn new(node: &'a Node) -> Self {
pub(crate) fn new(node: &'a Node) -> Self {
Self::with_offset(Vector::new(0.0, 0.0), node)
}
/// Creates a new [`Layout`] for the given [`Node`] with the provided offset
/// from the origin.
pub fn with_offset(offset: Vector, node: &'a Node) -> Self {
pub(crate) fn with_offset(offset: Vector, node: &'a Node) -> Self {
let bounds = node.bounds();
Self {

View File

@ -16,10 +16,9 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{
layout::{Limits, Node},
Align, Element, Padding, Point, Size,
Align, Element, Point, Size,
};
/// The main axis of a flex layout.
@ -63,7 +62,7 @@ pub fn resolve<Message, Renderer>(
axis: Axis,
renderer: &Renderer,
limits: &Limits,
padding: Padding,
padding: f32,
spacing: f32,
align_items: Align,
items: &[Element<'_, Message, Renderer>],
@ -142,15 +141,14 @@ where
}
}
let pad = axis.pack(padding.left as f32, padding.top as f32);
let mut main = pad.0;
let mut main = padding;
for (i, node) in nodes.iter_mut().enumerate() {
if i > 0 {
main += spacing;
}
let (x, y) = axis.pack(main, pad.1);
let (x, y) = axis.pack(main, padding);
node.move_to(Point::new(x, y));
@ -168,7 +166,7 @@ where
main += axis.main(size);
}
let (width, height) = axis.pack(main - pad.0, cross);
let (width, height) = axis.pack(main - padding, cross);
let size = limits.resolve(Size::new(width, height));
Node::with_children(size.pad(padding), nodes)

View File

@ -1,4 +1,4 @@
use crate::{Length, Padding, Size};
use crate::{Length, Size};
/// A set of size constraints for layouting.
#[derive(Debug, Clone, Copy)]
@ -117,11 +117,8 @@ impl Limits {
}
/// Shrinks the current [`Limits`] to account for the given padding.
pub fn pad(&self, padding: Padding) -> Limits {
self.shrink(Size::new(
padding.horizontal() as f32,
padding.vertical() as f32,
))
pub fn pad(&self, padding: f32) -> Limits {
self.shrink(Size::new(padding * 2.0, padding * 2.0))
}
/// Shrinks the current [`Limits`] by the given [`Size`].

View File

@ -33,7 +33,6 @@
#![deny(unused_results)]
#![forbid(unsafe_code)]
#![forbid(rust_2018_idioms)]
pub mod clipboard;
pub mod event;
pub mod keyboard;
pub mod layout;
@ -42,10 +41,10 @@ pub mod overlay;
pub mod program;
pub mod renderer;
pub mod subscription;
pub mod touch;
pub mod widget;
pub mod window;
mod clipboard;
mod element;
mod hasher;
mod runtime;
@ -61,8 +60,8 @@ mod debug;
mod debug;
pub use iced_core::{
Align, Background, Color, Font, HorizontalAlignment, Length, Padding,
Point, Rectangle, Size, Vector, VerticalAlignment,
Align, Background, Color, Font, HorizontalAlignment, Length, Point,
Rectangle, Size, Vector, VerticalAlignment,
};
pub use iced_futures::{executor, futures, Command};

View File

@ -67,9 +67,9 @@ where
_event: Event,
_layout: Layout<'_>,
_cursor_position: Point,
_renderer: &Renderer,
_clipboard: &mut dyn Clipboard,
_messages: &mut Vec<Message>,
_renderer: &Renderer,
_clipboard: Option<&dyn Clipboard>,
) -> event::Status {
event::Status::Ignored
}

View File

@ -53,17 +53,17 @@ where
event: Event,
layout: Layout<'_>,
cursor_position: Point,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
messages: &mut Vec<Message>,
renderer: &Renderer,
clipboard: Option<&dyn Clipboard>,
) -> event::Status {
self.overlay.on_event(
event,
layout,
cursor_position,
messages,
renderer,
clipboard,
messages,
)
}
@ -117,9 +117,9 @@ where
event: Event,
layout: Layout<'_>,
cursor_position: Point,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
messages: &mut Vec<B>,
renderer: &Renderer,
clipboard: Option<&dyn Clipboard>,
) -> event::Status {
let mut original_messages = Vec::new();
@ -127,9 +127,9 @@ where
event,
layout,
cursor_position,
&mut original_messages,
renderer,
clipboard,
&mut original_messages,
);
original_messages

View File

@ -6,10 +6,9 @@ use crate::mouse;
use crate::overlay;
use crate::scrollable;
use crate::text;
use crate::touch;
use crate::{
Clipboard, Container, Element, Hasher, Layout, Length, Padding, Point,
Rectangle, Scrollable, Size, Vector, Widget,
Clipboard, Container, Element, Hasher, Layout, Length, Point, Rectangle,
Scrollable, Size, Vector, Widget,
};
/// A list of selectable options.
@ -20,7 +19,7 @@ pub struct Menu<'a, T, Renderer: self::Renderer> {
hovered_option: &'a mut Option<usize>,
last_selection: &'a mut Option<T>,
width: u16,
padding: Padding,
padding: u16,
text_size: Option<u16>,
font: Renderer::Font,
style: <Renderer as self::Renderer>::Style,
@ -45,7 +44,7 @@ where
hovered_option,
last_selection,
width: 0,
padding: Padding::ZERO,
padding: 0,
text_size: None,
font: Default::default(),
style: Default::default(),
@ -58,9 +57,9 @@ where
self
}
/// Sets the [`Padding`] of the [`Menu`].
pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
self.padding = padding.into();
/// Sets the padding of the [`Menu`].
pub fn padding(mut self, padding: u16) -> Self {
self.padding = padding;
self
}
@ -219,17 +218,17 @@ where
event: Event,
layout: Layout<'_>,
cursor_position: Point,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
messages: &mut Vec<Message>,
renderer: &Renderer,
clipboard: Option<&dyn Clipboard>,
) -> event::Status {
self.container.on_event(
event.clone(),
layout,
cursor_position,
messages,
renderer,
clipboard,
messages,
)
}
@ -261,7 +260,7 @@ struct List<'a, T, Renderer: self::Renderer> {
options: &'a [T],
hovered_option: &'a mut Option<usize>,
last_selection: &'a mut Option<T>,
padding: Padding,
padding: u16,
text_size: Option<u16>,
font: Renderer::Font,
style: <Renderer as self::Renderer>::Style,
@ -294,7 +293,7 @@ where
let size = {
let intrinsic = Size::new(
0.0,
f32::from(text_size + self.padding.vertical())
f32::from(text_size + self.padding * 2)
* self.options.len() as f32,
);
@ -320,9 +319,9 @@ where
event: Event,
layout: Layout<'_>,
cursor_position: Point,
renderer: &Renderer,
_clipboard: &mut dyn Clipboard,
_messages: &mut Vec<Message>,
renderer: &Renderer,
_clipboard: Option<&dyn Clipboard>,
) -> event::Status {
match event {
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
@ -338,36 +337,15 @@ where
}
Event::Mouse(mouse::Event::CursorMoved { .. }) => {
let bounds = layout.bounds();
if bounds.contains(cursor_position) {
let text_size =
self.text_size.unwrap_or(renderer.default_size());
*self.hovered_option = Some(
((cursor_position.y - bounds.y)
/ f32::from(text_size + self.padding.vertical()))
as usize,
);
}
}
Event::Touch(touch::Event::FingerPressed { .. }) => {
let bounds = layout.bounds();
if bounds.contains(cursor_position) {
let text_size =
self.text_size.unwrap_or(renderer.default_size());
*self.hovered_option = Some(
((cursor_position.y - bounds.y)
/ f32::from(text_size + self.padding.vertical()))
/ f32::from(text_size + self.padding * 2))
as usize,
);
if let Some(index) = *self.hovered_option {
if let Some(option) = self.options.get(index) {
*self.last_selection = Some(option.clone());
}
}
}
}
_ => {}
@ -430,7 +408,7 @@ pub trait Renderer:
viewport: &Rectangle,
options: &[T],
hovered_option: Option<usize>,
padding: Padding,
padding: u16,
text_size: u16,
font: Self::Font,
style: &<Self as Renderer>::Style,

View File

@ -1,5 +1,5 @@
//! Build interactive programs using The Elm Architecture.
use crate::{Clipboard, Command, Element, Renderer};
use crate::{Command, Element, Renderer};
mod state;
@ -13,9 +13,6 @@ pub trait Program: Sized {
/// The type of __messages__ your [`Program`] will produce.
type Message: std::fmt::Debug + Send;
/// The type of [`Clipboard`] your [`Program`] will use.
type Clipboard: Clipboard;
/// Handles a __message__ and updates the state of the [`Program`].
///
/// This is where you define your __update logic__. All the __messages__,
@ -24,11 +21,7 @@ pub trait Program: Sized {
///
/// Any [`Command`] returned will be executed immediately in the
/// background by shells.
fn update(
&mut self,
message: Self::Message,
clipboard: &mut Self::Clipboard,
) -> Command<Self::Message>;
fn update(&mut self, message: Self::Message) -> Command<Self::Message>;
/// Returns the widgets to display in the [`Program`].
///

View File

@ -1,5 +1,6 @@
use crate::{
Cache, Command, Debug, Event, Point, Program, Renderer, Size, UserInterface,
Cache, Clipboard, Command, Debug, Event, Point, Program, Renderer, Size,
UserInterface,
};
/// The execution state of a [`Program`]. It leverages caching, event
@ -90,8 +91,8 @@ where
&mut self,
bounds: Size,
cursor_position: Point,
clipboard: Option<&dyn Clipboard>,
renderer: &mut P::Renderer,
clipboard: &mut P::Clipboard,
debug: &mut Debug,
) -> Option<Command<P::Message>> {
let mut user_interface = build_user_interface(
@ -108,8 +109,8 @@ where
let _ = user_interface.update(
&self.queued_events,
cursor_position,
renderer,
clipboard,
renderer,
&mut messages,
);
@ -135,7 +136,7 @@ where
debug.log_message(&message);
debug.update_started();
let command = self.program.update(message, clipboard);
let command = self.program.update(message);
debug.update_finished();
command

View File

@ -1,7 +1,7 @@
use crate::{
button, checkbox, column, container, pane_grid, progress_bar, radio, row,
scrollable, slider, text, text_input, toggler, Color, Element, Font,
HorizontalAlignment, Layout, Padding, Point, Rectangle, Renderer, Size,
scrollable, slider, text, text_input, Color, Element, Font,
HorizontalAlignment, Layout, Point, Rectangle, Renderer, Size,
VerticalAlignment,
};
@ -145,7 +145,7 @@ impl text_input::Renderer for Null {
}
impl button::Renderer for Null {
const DEFAULT_PADDING: Padding = Padding::ZERO;
const DEFAULT_PADDING: u16 = 0;
type Style = ();
@ -246,18 +246,14 @@ impl container::Renderer for Null {
}
impl pane_grid::Renderer for Null {
type Style = ();
fn draw<Message>(
&mut self,
_defaults: &Self::Defaults,
_content: &[(pane_grid::Pane, pane_grid::Content<'_, Message, Self>)],
_dragging: Option<(pane_grid::Pane, Point)>,
_resizing: Option<(pane_grid::Axis, Rectangle, bool)>,
_resizing: Option<pane_grid::Axis>,
_layout: Layout<'_>,
_style: &<Self as pane_grid::Renderer>::Style,
_cursor_position: Point,
_viewport: &Rectangle,
) {
}
@ -265,14 +261,13 @@ impl pane_grid::Renderer for Null {
&mut self,
_defaults: &Self::Defaults,
_bounds: Rectangle,
_style: &<Self as container::Renderer>::Style,
_style: &Self::Style,
_title_bar: Option<(
&pane_grid::TitleBar<'_, Message, Self>,
Layout<'_>,
)>,
_body: (&Element<'_, Message, Self>, Layout<'_>),
_cursor_position: Point,
_viewport: &Rectangle,
) {
}
@ -280,27 +275,13 @@ impl pane_grid::Renderer for Null {
&mut self,
_defaults: &Self::Defaults,
_bounds: Rectangle,
_style: &<Self as container::Renderer>::Style,
_content: (&Element<'_, Message, Self>, Layout<'_>),
_style: &Self::Style,
_title: &str,
_title_size: u16,
_title_font: Self::Font,
_title_bounds: Rectangle,
_controls: Option<(&Element<'_, Message, Self>, Layout<'_>)>,
_cursor_position: Point,
_viewport: &Rectangle,
) {
}
}
impl toggler::Renderer for Null {
type Style = ();
const DEFAULT_SIZE: u16 = 20;
fn draw(
&mut self,
_bounds: Rectangle,
_is_checked: bool,
_is_mouse_over: bool,
_label: Option<Self::Output>,
_style: &Self::Style,
) {
}
}

View File

@ -1,23 +0,0 @@
//! Build touch events.
use crate::Point;
/// A touch interaction.
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(missing_docs)]
pub enum Event {
/// A touch interaction was started.
FingerPressed { id: Finger, position: Point },
/// An on-going touch interaction was moved.
FingerMoved { id: Finger, position: Point },
/// A touch interaction was ended.
FingerLifted { id: Finger, position: Point },
/// A touch interaction was canceled.
FingerLost { id: Finger, position: Point },
}
/// A unique identifier representing a finger on a touch interaction.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Finger(pub u64);

View File

@ -16,7 +16,7 @@ use std::hash::Hasher;
/// The [`integration` example] uses a [`UserInterface`] to integrate Iced in
/// an existing graphical application.
///
/// [`integration` example]: https://github.com/hecrj/iced/tree/0.3/examples/integration
/// [`integration` example]: https://github.com/hecrj/iced/tree/0.2/examples/integration
#[allow(missing_debug_implementations)]
pub struct UserInterface<'a, Message, Renderer> {
root: Element<'a, Message, Renderer>,
@ -134,7 +134,7 @@ where
/// completing [the previous example](#example):
///
/// ```no_run
/// use iced_native::{clipboard, UserInterface, Cache, Size, Point};
/// use iced_native::{UserInterface, Cache, Size, Point};
/// use iced_wgpu::Renderer;
///
/// # mod iced_wgpu {
@ -157,7 +157,6 @@ where
/// let mut renderer = Renderer::new();
/// let mut window_size = Size::new(1024.0, 768.0);
/// let mut cursor_position = Point::default();
/// let mut clipboard = clipboard::Null;
///
/// // Initialize our event storage
/// let mut events = Vec::new();
@ -177,8 +176,8 @@ where
/// let event_statuses = user_interface.update(
/// &events,
/// cursor_position,
/// None,
/// &renderer,
/// &mut clipboard,
/// &mut messages
/// );
///
@ -194,8 +193,8 @@ where
&mut self,
events: &[Event],
cursor_position: Point,
clipboard: Option<&dyn Clipboard>,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
messages: &mut Vec<Message>,
) -> Vec<event::Status> {
let (base_cursor, overlay_statuses) = if let Some(mut overlay) =
@ -216,9 +215,9 @@ where
event,
Layout::new(&layer.layout),
cursor_position,
messages,
renderer,
clipboard,
messages,
)
})
.collect();
@ -247,9 +246,9 @@ where
event,
Layout::new(&self.base.layout),
base_cursor,
messages,
renderer,
clipboard,
messages,
);
event_status.merge(overlay_status)
@ -270,7 +269,7 @@ where
/// [completing the last example](#example-1):
///
/// ```no_run
/// use iced_native::{clipboard, UserInterface, Cache, Size, Point};
/// use iced_native::{UserInterface, Cache, Size, Point};
/// use iced_wgpu::Renderer;
///
/// # mod iced_wgpu {
@ -293,7 +292,6 @@ where
/// let mut renderer = Renderer::new();
/// let mut window_size = Size::new(1024.0, 768.0);
/// let mut cursor_position = Point::default();
/// let mut clipboard = clipboard::Null;
/// let mut events = Vec::new();
/// let mut messages = Vec::new();
///
@ -311,8 +309,8 @@ where
/// let event_statuses = user_interface.update(
/// &events,
/// cursor_position,
/// None,
/// &renderer,
/// &mut clipboard,
/// &mut messages
/// );
///

Some files were not shown because too many files have changed in this diff Show More