├── rustfmt.toml ├── .github ├── FUNDING.yml └── workflows │ ├── format.yml │ ├── test.yml │ └── build.yml ├── .gitignore ├── docs ├── graphs │ ├── web.png │ ├── core.png │ ├── iced.png │ ├── wgpu.png │ ├── winit.png │ ├── native.png │ ├── ecosystem.png │ ├── generate.sh │ ├── web.dot │ ├── core.dot │ ├── wgpu.dot │ ├── winit.dot │ ├── native.dot │ ├── iced.dot │ └── ecosystem.dot └── images │ ├── radio.png │ ├── text.png │ ├── checkbox.png │ ├── text_input.png │ └── todos_desktop.jpg ├── native ├── src │ ├── keyboard.rs │ ├── mouse.rs │ ├── window.rs │ ├── widget │ │ ├── pane_grid │ │ │ ├── pane.rs │ │ │ ├── split.rs │ │ │ ├── direction.rs │ │ │ └── axis.rs │ │ └── text_input │ │ │ └── editor.rs │ ├── clipboard.rs │ ├── hasher.rs │ ├── runtime.rs │ ├── event.rs │ ├── subscription │ │ └── events.rs │ ├── layout │ │ ├── debugger.rs │ │ └── node.rs │ ├── window │ │ ├── event.rs │ │ └── backend.rs │ ├── subscription.rs │ ├── mouse │ │ └── click.rs │ ├── layout.rs │ ├── renderer.rs │ └── lib.rs ├── Cargo.toml └── README.md ├── wgpu ├── src │ ├── text │ │ ├── icons.ttf │ │ └── font.rs │ ├── shader │ │ ├── blit.frag.spv │ │ ├── blit.vert.spv │ │ ├── quad.frag.spv │ │ ├── quad.vert.spv │ │ ├── image.frag.spv │ │ ├── image.vert.spv │ │ ├── triangle.frag.spv │ │ ├── triangle.vert.spv │ │ ├── triangle.frag │ │ ├── blit.frag │ │ ├── image.frag │ │ ├── triangle.vert │ │ ├── blit.vert │ │ ├── image.vert │ │ ├── quad.vert │ │ └── quad.frag │ ├── window.rs │ ├── widget │ │ ├── text.rs │ │ ├── canvas │ │ │ ├── event.rs │ │ │ ├── fill.rs │ │ │ ├── geometry.rs │ │ │ ├── path │ │ │ │ └── arc.rs │ │ │ ├── text.rs │ │ │ ├── path.rs │ │ │ ├── cursor.rs │ │ │ └── program.rs │ │ ├── checkbox.rs │ │ ├── radio.rs │ │ ├── container.rs │ │ ├── scrollable.rs │ │ ├── button.rs │ │ ├── text_input.rs │ │ ├── progress_bar.rs │ │ ├── slider.rs │ │ └── pane_grid.rs │ ├── renderer │ │ ├── widget │ │ │ ├── space.rs │ │ │ ├── image.rs │ │ │ ├── svg.rs │ │ │ ├── row.rs │ │ │ ├── column.rs │ │ │ ├── container.rs │ │ │ ├── progress_bar.rs │ │ │ ├── text.rs │ │ │ ├── radio.rs │ │ │ └── checkbox.rs │ │ └── widget.rs │ ├── image │ │ └── atlas │ │ │ ├── layer.rs │ │ │ ├── entry.rs │ │ │ ├── allocation.rs │ │ │ └── allocator.rs │ ├── target.rs │ ├── defaults.rs │ ├── viewport.rs │ ├── widget.rs │ ├── transformation.rs │ ├── settings.rs │ ├── window │ │ └── swap_chain.rs │ └── lib.rs ├── fonts │ └── Lato-Regular.ttf ├── Cargo.toml └── README.md ├── examples ├── todos │ ├── fonts │ │ └── icons.ttf │ ├── iced-todos.desktop │ ├── Cargo.toml │ └── README.md ├── tour │ ├── images │ │ └── ferris.png │ ├── Cargo.toml │ └── README.md ├── color_palette │ ├── screenshot.png │ ├── Cargo.toml │ └── README.md ├── integration │ ├── src │ │ └── shader │ │ │ ├── frag.spv │ │ │ └── vert.spv │ ├── Cargo.toml │ └── README.md ├── counter │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── main.rs ├── styling │ ├── Cargo.toml │ └── README.md ├── pane_grid │ ├── Cargo.toml │ └── README.md ├── progress_bar │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── main.rs ├── svg │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── main.rs ├── stopwatch │ ├── Cargo.toml │ └── README.md ├── bezier_tool │ ├── Cargo.toml │ └── README.md ├── events │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── main.rs ├── clock │ ├── Cargo.toml │ └── README.md ├── solar_system │ ├── Cargo.toml │ └── README.md ├── geometry │ ├── Cargo.toml │ └── README.md ├── custom_widget │ ├── Cargo.toml │ └── README.md ├── download_progress │ ├── Cargo.toml │ └── README.md ├── game_of_life │ ├── Cargo.toml │ └── README.md └── pokedex │ ├── Cargo.toml │ └── README.md ├── src ├── keyboard.rs ├── mouse.rs ├── window.rs ├── window │ ├── mode.rs │ └── settings.rs ├── element.rs ├── time.rs ├── settings.rs ├── widget.rs └── executor.rs ├── core ├── src │ ├── mouse.rs │ ├── keyboard.rs │ ├── mouse │ │ ├── button.rs │ │ ├── interaction.rs │ │ └── event.rs │ ├── background.rs │ ├── font.rs │ ├── align.rs │ ├── keyboard │ │ ├── event.rs │ │ └── modifiers_state.rs │ ├── lib.rs │ ├── length.rs │ ├── vector.rs │ ├── size.rs │ └── point.rs ├── Cargo.toml └── README.md ├── winit ├── src │ ├── settings │ │ ├── not_windows.rs │ │ └── windows.rs │ ├── mode.rs │ ├── clipboard.rs │ ├── size.rs │ ├── debug │ │ └── null.rs │ ├── settings.rs │ ├── proxy.rs │ └── lib.rs ├── Cargo.toml └── README.md ├── style ├── src │ ├── lib.rs │ ├── progress_bar.rs │ ├── radio.rs │ ├── container.rs │ ├── checkbox.rs │ ├── scrollable.rs │ ├── text_input.rs │ ├── slider.rs │ └── button.rs └── Cargo.toml ├── futures ├── src │ ├── executor │ │ ├── wasm_bindgen.rs │ │ ├── async_std.rs │ │ ├── thread_pool.rs │ │ ├── null.rs │ │ └── tokio.rs │ ├── lib.rs │ ├── executor.rs │ └── time.rs └── Cargo.toml ├── web ├── src │ ├── hasher.rs │ ├── subscription.rs │ ├── bus.rs │ ├── widget │ │ └── space.rs │ ├── widget.rs │ └── element.rs └── Cargo.toml ├── LICENSE ├── CONTRIBUTING.md └── Cargo.toml /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width=80 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: hecrj_ 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | pkg/ 3 | **/*.rs.bk 4 | Cargo.lock 5 | .cargo/ 6 | -------------------------------------------------------------------------------- /docs/graphs/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/graphs/web.png -------------------------------------------------------------------------------- /native/src/keyboard.rs: -------------------------------------------------------------------------------- 1 | //! Track keyboard events. 2 | pub use iced_core::keyboard::*; 3 | -------------------------------------------------------------------------------- /docs/graphs/core.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/graphs/core.png -------------------------------------------------------------------------------- /docs/graphs/iced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/graphs/iced.png -------------------------------------------------------------------------------- /docs/graphs/wgpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/graphs/wgpu.png -------------------------------------------------------------------------------- /docs/graphs/winit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/graphs/winit.png -------------------------------------------------------------------------------- /docs/images/radio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/images/radio.png -------------------------------------------------------------------------------- /docs/images/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/images/text.png -------------------------------------------------------------------------------- /docs/graphs/native.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/graphs/native.png -------------------------------------------------------------------------------- /docs/images/checkbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/images/checkbox.png -------------------------------------------------------------------------------- /wgpu/src/text/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/wgpu/src/text/icons.ttf -------------------------------------------------------------------------------- /docs/graphs/ecosystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/graphs/ecosystem.png -------------------------------------------------------------------------------- /docs/images/text_input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/images/text_input.png -------------------------------------------------------------------------------- /docs/images/todos_desktop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/docs/images/todos_desktop.jpg -------------------------------------------------------------------------------- /wgpu/fonts/Lato-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/wgpu/fonts/Lato-Regular.ttf -------------------------------------------------------------------------------- /wgpu/src/shader/blit.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/wgpu/src/shader/blit.frag.spv -------------------------------------------------------------------------------- /wgpu/src/shader/blit.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/wgpu/src/shader/blit.vert.spv -------------------------------------------------------------------------------- /wgpu/src/shader/quad.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/wgpu/src/shader/quad.frag.spv -------------------------------------------------------------------------------- /wgpu/src/shader/quad.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/wgpu/src/shader/quad.vert.spv -------------------------------------------------------------------------------- /examples/todos/fonts/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/examples/todos/fonts/icons.ttf -------------------------------------------------------------------------------- /examples/todos/iced-todos.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Todos - Iced 3 | Exec=iced-todos 4 | Type=Application 5 | -------------------------------------------------------------------------------- /examples/tour/images/ferris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/examples/tour/images/ferris.png -------------------------------------------------------------------------------- /wgpu/src/shader/image.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/wgpu/src/shader/image.frag.spv -------------------------------------------------------------------------------- /wgpu/src/shader/image.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/wgpu/src/shader/image.vert.spv -------------------------------------------------------------------------------- /wgpu/src/shader/triangle.frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/wgpu/src/shader/triangle.frag.spv -------------------------------------------------------------------------------- /wgpu/src/shader/triangle.vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/wgpu/src/shader/triangle.vert.spv -------------------------------------------------------------------------------- /docs/graphs/generate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | for file in *.dot 4 | do 5 | dot -Tpng ${file} -o ${file%.*}.png 6 | done 7 | -------------------------------------------------------------------------------- /examples/color_palette/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/examples/color_palette/screenshot.png -------------------------------------------------------------------------------- /src/keyboard.rs: -------------------------------------------------------------------------------- 1 | //! Listen and react to keyboard events. 2 | pub use crate::runtime::keyboard::{Event, KeyCode, ModifiersState}; 3 | -------------------------------------------------------------------------------- /src/mouse.rs: -------------------------------------------------------------------------------- 1 | //! Listen and react to mouse events. 2 | pub use crate::runtime::mouse::{Button, Event, Interaction, ScrollDelta}; 3 | -------------------------------------------------------------------------------- /examples/integration/src/shader/frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/examples/integration/src/shader/frag.spv -------------------------------------------------------------------------------- /examples/integration/src/shader/vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timokoesters/iced/master/examples/integration/src/shader/vert.spv -------------------------------------------------------------------------------- /native/src/mouse.rs: -------------------------------------------------------------------------------- 1 | //! Track mouse events. 2 | 3 | pub mod click; 4 | 5 | pub use click::Click; 6 | pub use iced_core::mouse::*; 7 | -------------------------------------------------------------------------------- /native/src/window.rs: -------------------------------------------------------------------------------- 1 | //! Build window-based GUI applications. 2 | mod backend; 3 | mod event; 4 | 5 | pub use backend::Backend; 6 | pub use event::Event; 7 | -------------------------------------------------------------------------------- /wgpu/src/window.rs: -------------------------------------------------------------------------------- 1 | //! Display rendering results on windows. 2 | mod backend; 3 | mod swap_chain; 4 | 5 | pub use backend::Backend; 6 | pub use swap_chain::SwapChain; 7 | -------------------------------------------------------------------------------- /src/window.rs: -------------------------------------------------------------------------------- 1 | //! Configure the window of your application in native platforms. 2 | mod mode; 3 | mod settings; 4 | 5 | pub use mode::Mode; 6 | pub use settings::Settings; 7 | -------------------------------------------------------------------------------- /wgpu/src/shader/triangle.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec4 i_Color; 4 | layout(location = 0) out vec4 o_Color; 5 | 6 | void main() { 7 | o_Color = i_Color; 8 | } 9 | -------------------------------------------------------------------------------- /core/src/mouse.rs: -------------------------------------------------------------------------------- 1 | //! Reuse basic mouse types. 2 | mod button; 3 | mod event; 4 | mod interaction; 5 | 6 | pub use button::Button; 7 | pub use event::{Event, ScrollDelta}; 8 | pub use interaction::Interaction; 9 | -------------------------------------------------------------------------------- /core/src/keyboard.rs: -------------------------------------------------------------------------------- 1 | //! Reuse basic keyboard types. 2 | mod event; 3 | mod key_code; 4 | mod modifiers_state; 5 | 6 | pub use event::Event; 7 | pub use key_code::KeyCode; 8 | pub use modifiers_state::ModifiersState; 9 | -------------------------------------------------------------------------------- /examples/counter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "counter" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../.." } 10 | -------------------------------------------------------------------------------- /examples/styling/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "styling" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../.." } 10 | -------------------------------------------------------------------------------- /native/src/widget/pane_grid/pane.rs: -------------------------------------------------------------------------------- 1 | /// A rectangular region in a [`PaneGrid`] used to display widgets. 2 | /// 3 | /// [`PaneGrid`]: struct.PaneGrid.html 4 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 5 | pub struct Pane(pub(super) usize); 6 | -------------------------------------------------------------------------------- /examples/pane_grid/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pane_grid" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../.." } 10 | -------------------------------------------------------------------------------- /examples/progress_bar/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "progress_bar" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../.." } 10 | -------------------------------------------------------------------------------- /examples/svg/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "svg" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["svg"] } 10 | -------------------------------------------------------------------------------- /native/src/widget/pane_grid/split.rs: -------------------------------------------------------------------------------- 1 | /// A divider that splits a region in a [`PaneGrid`] into two different panes. 2 | /// 3 | /// [`PaneGrid`]: struct.PaneGrid.html 4 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 5 | pub struct Split(pub(super) usize); 6 | -------------------------------------------------------------------------------- /wgpu/src/widget/text.rs: -------------------------------------------------------------------------------- 1 | //! Write some text for your users to read. 2 | use crate::Renderer; 3 | 4 | /// A paragraph of text. 5 | /// 6 | /// This is an alias of an `iced_native` text with an `iced_wgpu::Renderer`. 7 | pub type Text = iced_native::Text; 8 | -------------------------------------------------------------------------------- /examples/stopwatch/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stopwatch" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["tokio"] } 10 | -------------------------------------------------------------------------------- /wgpu/src/widget/canvas/event.rs: -------------------------------------------------------------------------------- 1 | use iced_native::mouse; 2 | 3 | /// A [`Canvas`] event. 4 | /// 5 | /// [`Canvas`]: struct.Event.html 6 | #[derive(Debug, Clone, Copy, PartialEq)] 7 | pub enum Event { 8 | /// A mouse event. 9 | Mouse(mouse::Event), 10 | } 11 | -------------------------------------------------------------------------------- /examples/bezier_tool/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bezier_tool" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["canvas"] } 10 | -------------------------------------------------------------------------------- /native/src/widget/pane_grid/direction.rs: -------------------------------------------------------------------------------- 1 | /// A four cardinal direction. 2 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 3 | pub enum Direction { 4 | /// ↑ 5 | Up, 6 | /// ↓ 7 | Down, 8 | /// ← 9 | Left, 10 | /// → 11 | Right, 12 | } 13 | -------------------------------------------------------------------------------- /winit/src/settings/not_windows.rs: -------------------------------------------------------------------------------- 1 | #![cfg(not(target_os = "windows"))] 2 | //! Platform specific settings for not Windows. 3 | 4 | /// The platform specific window settings of an application. 5 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 6 | pub struct PlatformSpecific {} 7 | -------------------------------------------------------------------------------- /examples/events/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "events" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../.." } 10 | iced_native = { path = "../../native" } 11 | -------------------------------------------------------------------------------- /examples/tour/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tour" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["image", "debug"] } 10 | env_logger = "0.7" 11 | -------------------------------------------------------------------------------- /examples/clock/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "clock" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["canvas", "tokio", "debug"] } 10 | chrono = "0.4" 11 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget/space.rs: -------------------------------------------------------------------------------- 1 | use crate::{Primitive, Renderer}; 2 | use iced_native::{mouse, space, Rectangle}; 3 | 4 | impl space::Renderer for Renderer { 5 | fn draw(&mut self, _bounds: Rectangle) -> Self::Output { 6 | (Primitive::None, mouse::Interaction::default()) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/color_palette/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "color_palette" 3 | version = "0.1.0" 4 | authors = ["Clark Moody "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["canvas", "palette"] } 10 | palette = "0.5.0" 11 | -------------------------------------------------------------------------------- /examples/solar_system/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "solar_system" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["canvas", "tokio", "debug"] } 10 | rand = "0.7" 11 | -------------------------------------------------------------------------------- /winit/src/mode.rs: -------------------------------------------------------------------------------- 1 | /// The mode of a window-based application. 2 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 3 | pub enum Mode { 4 | /// The application appears in its own window. 5 | Windowed, 6 | 7 | /// The application takes the whole screen of its current monitor. 8 | Fullscreen, 9 | } 10 | -------------------------------------------------------------------------------- /native/src/clipboard.rs: -------------------------------------------------------------------------------- 1 | /// A buffer for short-term storage and transfer within and between 2 | /// applications. 3 | pub trait Clipboard { 4 | /// Returns the current content of the [`Clipboard`] as text. 5 | /// 6 | /// [`Clipboard`]: trait.Clipboard.html 7 | fn content(&self) -> Option; 8 | } 9 | -------------------------------------------------------------------------------- /src/window/mode.rs: -------------------------------------------------------------------------------- 1 | /// The mode of a window-based application. 2 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 3 | pub enum Mode { 4 | /// The application appears in its own window. 5 | Windowed, 6 | 7 | /// The application takes the whole screen of its current monitor. 8 | Fullscreen, 9 | } 10 | -------------------------------------------------------------------------------- /examples/integration/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "integration" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced_winit = { path = "../../winit" } 10 | iced_wgpu = { path = "../../wgpu" } 11 | env_logger = "0.7" 12 | -------------------------------------------------------------------------------- /examples/geometry/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "geometry" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../.." } 10 | iced_native = { path = "../../native" } 11 | iced_wgpu = { path = "../../wgpu" } 12 | -------------------------------------------------------------------------------- /src/element.rs: -------------------------------------------------------------------------------- 1 | /// A generic widget. 2 | /// 3 | /// This is an alias of an `iced_native` element with a default `Renderer`. 4 | #[cfg(not(target_arch = "wasm32"))] 5 | pub type Element<'a, Message> = 6 | iced_winit::Element<'a, Message, iced_wgpu::Renderer>; 7 | 8 | #[cfg(target_arch = "wasm32")] 9 | pub use iced_web::Element; 10 | -------------------------------------------------------------------------------- /style/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The styling library of Iced. 2 | //! 3 | //! It contains a set of styles and stylesheets for most of the built-in 4 | //! widgets. 5 | pub mod button; 6 | pub mod checkbox; 7 | pub mod container; 8 | pub mod progress_bar; 9 | pub mod radio; 10 | pub mod scrollable; 11 | pub mod slider; 12 | pub mod text_input; 13 | -------------------------------------------------------------------------------- /docs/graphs/web.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | fontname = "Roboto"; 3 | newrank=true; 4 | node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"]; 5 | edge[color="#333333"]; 6 | 7 | iced_core -> iced_web [style=dashed]; 8 | 9 | iced_web -> iced; 10 | 11 | iced_core [style=dashed]; 12 | } 13 | -------------------------------------------------------------------------------- /examples/custom_widget/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "custom_widget" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../.." } 10 | iced_native = { path = "../../native" } 11 | iced_wgpu = { path = "../../wgpu" } 12 | -------------------------------------------------------------------------------- /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | name: Format 2 | on: [push, pull_request] 3 | jobs: 4 | all: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: hecrj/setup-rust-action@v1 8 | with: 9 | components: rustfmt 10 | - uses: actions/checkout@master 11 | - name: Check format 12 | run: cargo fmt --all -- --check 13 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget.rs: -------------------------------------------------------------------------------- 1 | mod button; 2 | mod checkbox; 3 | mod column; 4 | mod container; 5 | mod pane_grid; 6 | mod progress_bar; 7 | mod radio; 8 | mod row; 9 | mod scrollable; 10 | mod slider; 11 | mod space; 12 | mod text; 13 | mod text_input; 14 | 15 | #[cfg(feature = "svg")] 16 | mod svg; 17 | 18 | #[cfg(feature = "image")] 19 | mod image; 20 | -------------------------------------------------------------------------------- /wgpu/src/shader/blit.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 v_Uv; 4 | 5 | layout(set = 0, binding = 0) uniform sampler u_Sampler; 6 | layout(set = 1, binding = 0) uniform texture2D u_Texture; 7 | 8 | layout(location = 0) out vec4 o_Color; 9 | 10 | void main() { 11 | o_Color = texture(sampler2D(u_Texture, u_Sampler), v_Uv); 12 | } 13 | -------------------------------------------------------------------------------- /core/src/mouse/button.rs: -------------------------------------------------------------------------------- 1 | /// The button of a mouse. 2 | #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] 3 | pub enum Button { 4 | /// The left mouse button. 5 | Left, 6 | 7 | /// The right mouse button. 8 | Right, 9 | 10 | /// The middle (wheel) button. 11 | Middle, 12 | 13 | /// Some other button. 14 | Other(u8), 15 | } 16 | -------------------------------------------------------------------------------- /wgpu/src/image/atlas/layer.rs: -------------------------------------------------------------------------------- 1 | use crate::image::atlas::Allocator; 2 | 3 | #[derive(Debug)] 4 | pub enum Layer { 5 | Empty, 6 | Busy(Allocator), 7 | Full, 8 | } 9 | 10 | impl Layer { 11 | pub fn is_empty(&self) -> bool { 12 | match self { 13 | Layer::Empty => true, 14 | _ => false, 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /wgpu/src/widget/checkbox.rs: -------------------------------------------------------------------------------- 1 | //! Show toggle controls using checkboxes. 2 | use crate::Renderer; 3 | 4 | pub use iced_style::checkbox::{Style, StyleSheet}; 5 | 6 | /// A box that can be checked. 7 | /// 8 | /// This is an alias of an `iced_native` checkbox with an `iced_wgpu::Renderer`. 9 | pub type Checkbox = iced_native::Checkbox; 10 | -------------------------------------------------------------------------------- /winit/src/settings/windows.rs: -------------------------------------------------------------------------------- 1 | #![cfg(target_os = "windows")] 2 | //! Platform specific settings for Windows. 3 | 4 | /// The platform specific window settings of an application. 5 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 6 | pub struct PlatformSpecific { 7 | /// Parent Window 8 | pub parent: Option, 9 | } 10 | -------------------------------------------------------------------------------- /wgpu/src/shader/image.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 v_Uv; 4 | 5 | layout(set = 0, binding = 1) uniform sampler u_Sampler; 6 | layout(set = 1, binding = 0) uniform texture2DArray u_Texture; 7 | 8 | layout(location = 0) out vec4 o_Color; 9 | 10 | void main() { 11 | o_Color = texture(sampler2DArray(u_Texture, u_Sampler), v_Uv); 12 | } 13 | -------------------------------------------------------------------------------- /core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iced_core" 3 | version = "0.2.1" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | description = "The essential concepts of Iced" 7 | license = "MIT" 8 | repository = "https://github.com/hecrj/iced" 9 | 10 | [dependencies] 11 | 12 | [dependencies.palette] 13 | version = "0.5.0" 14 | optional = true 15 | -------------------------------------------------------------------------------- /wgpu/src/widget/radio.rs: -------------------------------------------------------------------------------- 1 | //! Create choices using radio buttons. 2 | use crate::Renderer; 3 | 4 | pub use iced_style::radio::{Style, StyleSheet}; 5 | 6 | /// A circular button representing a choice. 7 | /// 8 | /// This is an alias of an `iced_native` radio button with an 9 | /// `iced_wgpu::Renderer`. 10 | pub type Radio = iced_native::Radio; 11 | -------------------------------------------------------------------------------- /examples/download_progress/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "download_progress" 3 | version = "0.1.0" 4 | authors = ["Songtronix "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["tokio"] } 10 | iced_native = { path = "../../native" } 11 | iced_futures = { path = "../../futures" } 12 | reqwest = "0.10" 13 | -------------------------------------------------------------------------------- /wgpu/src/widget/container.rs: -------------------------------------------------------------------------------- 1 | //! Decorate content and apply alignment. 2 | use crate::Renderer; 3 | 4 | pub use iced_style::container::{Style, StyleSheet}; 5 | 6 | /// An element decorating some content. 7 | /// 8 | /// This is an alias of an `iced_native` container with a default 9 | /// `Renderer`. 10 | pub type Container<'a, Message> = iced_native::Container<'a, Message, Renderer>; 11 | -------------------------------------------------------------------------------- /examples/game_of_life/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "game_of_life" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["canvas", "tokio", "debug"] } 10 | tokio = { version = "0.2", features = ["blocking"] } 11 | itertools = "0.9" 12 | rustc-hash = "1.1" 13 | -------------------------------------------------------------------------------- /wgpu/src/shader/triangle.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 i_Position; 4 | layout(location = 1) in vec4 i_Color; 5 | 6 | layout(location = 0) out vec4 o_Color; 7 | 8 | layout (set = 0, binding = 0) uniform Globals { 9 | mat4 u_Transform; 10 | }; 11 | 12 | void main() { 13 | gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0); 14 | o_Color = i_Color; 15 | } 16 | -------------------------------------------------------------------------------- /core/src/background.rs: -------------------------------------------------------------------------------- 1 | use crate::Color; 2 | 3 | /// The background of some element. 4 | #[derive(Debug, Clone, Copy, PartialEq)] 5 | pub enum Background { 6 | /// A solid color 7 | Color(Color), 8 | // TODO: Add gradient and image variants 9 | } 10 | 11 | impl From for Background { 12 | fn from(color: Color) -> Self { 13 | Background::Color(color) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/graphs/core.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | fontname = "Roboto"; 3 | newrank=true; 4 | node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"]; 5 | edge[color="#333333"]; 6 | 7 | { rank = same; iced_native iced_web } 8 | 9 | iced_core -> iced_native [style=dashed]; 10 | iced_core -> iced_web [style=dashed]; 11 | 12 | iced_core [style=dashed]; 13 | } 14 | -------------------------------------------------------------------------------- /wgpu/src/target.rs: -------------------------------------------------------------------------------- 1 | use crate::Viewport; 2 | 3 | /// A rendering target. 4 | #[derive(Debug)] 5 | pub struct Target<'a> { 6 | /// The texture where graphics will be rendered. 7 | pub texture: &'a wgpu::TextureView, 8 | 9 | /// The viewport of the target. 10 | /// 11 | /// Most of the time, you will want this to match the dimensions of the 12 | /// texture. 13 | pub viewport: &'a Viewport, 14 | } 15 | -------------------------------------------------------------------------------- /futures/src/executor/wasm_bindgen.rs: -------------------------------------------------------------------------------- 1 | use crate::Executor; 2 | 3 | /// A `wasm-bindgen-futures` runtime. 4 | #[derive(Debug)] 5 | pub struct WasmBindgen; 6 | 7 | impl Executor for WasmBindgen { 8 | fn new() -> Result { 9 | Ok(Self) 10 | } 11 | 12 | fn spawn(&self, future: impl futures::Future + 'static) { 13 | wasm_bindgen_futures::spawn_local(future); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /wgpu/src/widget/canvas/fill.rs: -------------------------------------------------------------------------------- 1 | use iced_native::Color; 2 | 3 | /// The style used to fill geometry. 4 | #[derive(Debug, Clone, Copy)] 5 | pub enum Fill { 6 | /// Fill with a color. 7 | Color(Color), 8 | } 9 | 10 | impl Default for Fill { 11 | fn default() -> Fill { 12 | Fill::Color(Color::BLACK) 13 | } 14 | } 15 | 16 | impl From for Fill { 17 | fn from(color: Color) -> Fill { 18 | Fill::Color(color) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/color_palette/README.md: -------------------------------------------------------------------------------- 1 | ## Color palette 2 | 3 | A color palette generator, based on a user-defined root color. 4 | 5 |
6 | 7 | 8 | 9 |
10 | 11 | You can run it with `cargo run`: 12 | 13 | ``` 14 | cargo run --package color_palette 15 | ``` 16 | -------------------------------------------------------------------------------- /examples/svg/README.md: -------------------------------------------------------------------------------- 1 | ## SVG 2 | 3 | An application that renders the [Ghostscript Tiger] by leveraging the `Svg` widget. 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 |
10 | 11 | You can run it with `cargo run`: 12 | ``` 13 | cargo run --package svg 14 | ``` 15 | 16 | [`main`]: src/main.rs 17 | [Ghostscript Tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg 18 | -------------------------------------------------------------------------------- /native/src/hasher.rs: -------------------------------------------------------------------------------- 1 | /// The hasher used to compare layouts. 2 | #[derive(Debug)] 3 | pub struct Hasher(twox_hash::XxHash64); 4 | 5 | impl Default for Hasher { 6 | fn default() -> Self { 7 | Hasher(twox_hash::XxHash64::default()) 8 | } 9 | } 10 | 11 | impl core::hash::Hasher for Hasher { 12 | fn write(&mut self, bytes: &[u8]) { 13 | self.0.write(bytes) 14 | } 15 | 16 | fn finish(&self) -> u64 { 17 | self.0.finish() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/events/README.md: -------------------------------------------------------------------------------- 1 | ## Events 2 | 3 | A log of native events displayed using a conditional `Subscription`. 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run it with `cargo run`: 14 | ``` 15 | cargo run --package events 16 | ``` 17 | 18 | [`main`]: src/main.rs 19 | -------------------------------------------------------------------------------- /examples/clock/README.md: -------------------------------------------------------------------------------- 1 | ## Clock 2 | 3 | An application that uses the `Canvas` widget to draw a clock and its hands to display the current time. 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 |
10 | 11 | You can run it with `cargo run`: 12 | ``` 13 | cargo run --package clock 14 | ``` 15 | 16 | [`main`]: src/main.rs 17 | -------------------------------------------------------------------------------- /examples/counter/README.md: -------------------------------------------------------------------------------- 1 | ## Counter 2 | 3 | The classic counter example explained in the [`README`](../../README.md). 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run it with `cargo run`: 14 | ``` 15 | cargo run --package counter 16 | ``` 17 | 18 | [`main`]: src/main.rs 19 | -------------------------------------------------------------------------------- /core/src/mouse/interaction.rs: -------------------------------------------------------------------------------- 1 | /// The interaction of a mouse cursor. 2 | #[derive(Debug, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)] 3 | #[allow(missing_docs)] 4 | pub enum Interaction { 5 | Idle, 6 | Pointer, 7 | Grab, 8 | Text, 9 | Crosshair, 10 | Working, 11 | Grabbing, 12 | ResizingHorizontally, 13 | ResizingVertically, 14 | } 15 | 16 | impl Default for Interaction { 17 | fn default() -> Interaction { 18 | Interaction::Idle 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /style/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iced_style" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | description = "The default set of styles of Iced" 7 | license = "MIT" 8 | repository = "https://github.com/hecrj/iced" 9 | documentation = "https://docs.rs/iced_style" 10 | keywords = ["gui", "ui", "graphics", "interface", "widgets"] 11 | categories = ["gui"] 12 | 13 | [dependencies] 14 | iced_core = { version = "0.2", path = "../core" } 15 | -------------------------------------------------------------------------------- /futures/src/executor/async_std.rs: -------------------------------------------------------------------------------- 1 | use crate::Executor; 2 | 3 | use futures::Future; 4 | 5 | /// An `async-std` runtime. 6 | #[cfg_attr(docsrs, doc(cfg(feature = "async-std")))] 7 | #[derive(Debug)] 8 | pub struct AsyncStd; 9 | 10 | impl Executor for AsyncStd { 11 | fn new() -> Result { 12 | Ok(Self) 13 | } 14 | 15 | fn spawn(&self, future: impl Future + Send + 'static) { 16 | let _ = async_std::task::spawn(future); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /native/src/runtime.rs: -------------------------------------------------------------------------------- 1 | //! Run commands and subscriptions. 2 | use crate::{Event, Hasher}; 3 | 4 | /// A native runtime with a generic executor and receiver of results. 5 | /// 6 | /// It can be used by shells to easily spawn a [`Command`] or track a 7 | /// [`Subscription`]. 8 | /// 9 | /// [`Command`]: ../struct.Command.html 10 | /// [`Subscription`]: ../struct.Subscription.html 11 | pub type Runtime = 12 | iced_futures::Runtime; 13 | -------------------------------------------------------------------------------- /examples/bezier_tool/README.md: -------------------------------------------------------------------------------- 1 | ## Bézier tool 2 | 3 | A Paint-like tool for drawing Bézier curves using the `Canvas` widget. 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run it with `cargo run`: 14 | ``` 15 | cargo run --package bezier_tool 16 | ``` 17 | 18 | [`main`]: src/main.rs 19 | -------------------------------------------------------------------------------- /examples/custom_widget/README.md: -------------------------------------------------------------------------------- 1 | ## Custom widget 2 | 3 | A demonstration of how to build a custom widget that draws a circle. 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run it with `cargo run`: 14 | ``` 15 | cargo run --package custom_widget 16 | ``` 17 | 18 | [`main`]: src/main.rs 19 | -------------------------------------------------------------------------------- /examples/integration/README.md: -------------------------------------------------------------------------------- 1 | ## Integration 2 | 3 | A demonstration of how to integrate Iced in an existing graphical application. 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run it with `cargo run`: 14 | ``` 15 | cargo run --package integration 16 | ``` 17 | 18 | [`main`]: src/main.rs 19 | -------------------------------------------------------------------------------- /examples/progress_bar/README.md: -------------------------------------------------------------------------------- 1 | ## Progress bar 2 | 3 | A simple progress bar that can be filled by using a slider. 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run it with `cargo run`: 14 | ``` 15 | cargo run --package progress_bar 16 | ``` 17 | 18 | [`main`]: src/main.rs 19 | -------------------------------------------------------------------------------- /examples/stopwatch/README.md: -------------------------------------------------------------------------------- 1 | ## Stopwatch 2 | 3 | A watch with start/stop and reset buttons showcasing how to listen to time. 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run it with `cargo run`: 14 | ``` 15 | cargo run --package stopwatch 16 | ``` 17 | 18 | [`main`]: src/main.rs 19 | -------------------------------------------------------------------------------- /src/time.rs: -------------------------------------------------------------------------------- 1 | //! Listen and react to time. 2 | use crate::Subscription; 3 | 4 | /// Returns a [`Subscription`] that produces messages at a set interval. 5 | /// 6 | /// The first message is produced after a `duration`, and then continues to 7 | /// produce more messages every `duration` after that. 8 | /// 9 | /// [`Subscription`]: ../subscription/struct.Subscription.html 10 | pub fn every( 11 | duration: std::time::Duration, 12 | ) -> Subscription { 13 | iced_futures::time::every(duration) 14 | } 15 | -------------------------------------------------------------------------------- /web/src/hasher.rs: -------------------------------------------------------------------------------- 1 | use std::collections::hash_map::DefaultHasher; 2 | 3 | /// The hasher used to compare subscriptions. 4 | #[derive(Debug)] 5 | pub struct Hasher(DefaultHasher); 6 | 7 | impl Default for Hasher { 8 | fn default() -> Self { 9 | Hasher(DefaultHasher::default()) 10 | } 11 | } 12 | 13 | impl core::hash::Hasher for Hasher { 14 | fn write(&mut self, bytes: &[u8]) { 15 | self.0.write(bytes) 16 | } 17 | 18 | fn finish(&self) -> u64 { 19 | self.0.finish() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/geometry/README.md: -------------------------------------------------------------------------------- 1 | ## Geometry 2 | 3 | A custom widget showcasing how to draw geometry with the `Mesh2D` primitive in [`iced_wgpu`](../../wgpu). 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run it with `cargo run`: 14 | ``` 15 | cargo run --package geometry 16 | ``` 17 | 18 | [`main`]: src/main.rs 19 | -------------------------------------------------------------------------------- /wgpu/src/widget/scrollable.rs: -------------------------------------------------------------------------------- 1 | //! Navigate an endless amount of content with a scrollbar. 2 | use crate::Renderer; 3 | 4 | pub use iced_native::scrollable::State; 5 | pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet}; 6 | 7 | /// A widget that can vertically display an infinite amount of content 8 | /// with a scrollbar. 9 | /// 10 | /// This is an alias of an `iced_native` scrollable with a default 11 | /// `Renderer`. 12 | pub type Scrollable<'a, Message> = 13 | iced_native::Scrollable<'a, Message, Renderer>; 14 | -------------------------------------------------------------------------------- /examples/pokedex/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pokedex" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["image", "debug", "tokio"] } 10 | serde_json = "1.0" 11 | 12 | [dependencies.serde] 13 | version = "1.0" 14 | features = ["derive"] 15 | 16 | [dependencies.reqwest] 17 | version = "0.10.2" 18 | features = ["json"] 19 | 20 | [dependencies.rand] 21 | version = "0.7" 22 | features = ["wasm-bindgen"] 23 | -------------------------------------------------------------------------------- /futures/src/executor/thread_pool.rs: -------------------------------------------------------------------------------- 1 | use crate::Executor; 2 | 3 | use futures::Future; 4 | 5 | /// A thread pool runtime for futures. 6 | #[cfg_attr(docsrs, doc(cfg(feature = "thread-pool")))] 7 | pub type ThreadPool = futures::executor::ThreadPool; 8 | 9 | impl Executor for futures::executor::ThreadPool { 10 | fn new() -> Result { 11 | futures::executor::ThreadPool::new() 12 | } 13 | 14 | fn spawn(&self, future: impl Future + Send + 'static) { 15 | self.spawn_ok(future); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/solar_system/README.md: -------------------------------------------------------------------------------- 1 | ## Solar system 2 | 3 | An animated solar system drawn using the `Canvas` widget and showcasing how to compose different transforms. 4 | 5 | The __[`main`]__ file contains all the code of the example. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run it with `cargo run`: 14 | ``` 15 | cargo run --package solar_system 16 | ``` 17 | 18 | [`main`]: src/main.rs 19 | -------------------------------------------------------------------------------- /examples/pokedex/README.md: -------------------------------------------------------------------------------- 1 | # Pokédex 2 | An application that loads a random Pokédex entry using the [PokéAPI]. 3 | 4 | All the example code can be found in the __[`main`](src/main.rs)__ file. 5 | 6 |
7 | 8 | 9 | 10 |
11 | 12 | You can run it on native platforms with `cargo run`: 13 | ``` 14 | cargo run --package pokedex 15 | ``` 16 | 17 | [PokéAPI]: https://pokeapi.co/ 18 | -------------------------------------------------------------------------------- /examples/styling/README.md: -------------------------------------------------------------------------------- 1 | # Styling 2 | An example showcasing custom styling with a light and dark theme. 3 | 4 | All the example code is located in the __[`main`](src/main.rs)__ file. 5 | 6 |
7 | 8 | 9 | 10 |
11 | 12 | You can run it with `cargo run`: 13 | ``` 14 | cargo run --package styling 15 | ``` 16 | -------------------------------------------------------------------------------- /futures/src/executor/null.rs: -------------------------------------------------------------------------------- 1 | use crate::Executor; 2 | 3 | use futures::Future; 4 | 5 | /// An executor that drops all the futures, instead of spawning them. 6 | #[derive(Debug)] 7 | pub struct Null; 8 | 9 | impl Executor for Null { 10 | fn new() -> Result { 11 | Ok(Self) 12 | } 13 | 14 | #[cfg(not(target_arch = "wasm32"))] 15 | fn spawn(&self, _future: impl Future + Send + 'static) {} 16 | 17 | #[cfg(target_arch = "wasm32")] 18 | fn spawn(&self, _future: impl Future + 'static) {} 19 | } 20 | -------------------------------------------------------------------------------- /wgpu/src/widget/button.rs: -------------------------------------------------------------------------------- 1 | //! Allow your users to perform actions by pressing a button. 2 | //! 3 | //! A [`Button`] has some local [`State`]. 4 | //! 5 | //! [`Button`]: type.Button.html 6 | //! [`State`]: struct.State.html 7 | use crate::Renderer; 8 | 9 | pub use iced_native::button::State; 10 | pub use iced_style::button::{Style, StyleSheet}; 11 | 12 | /// A widget that produces a message when clicked. 13 | /// 14 | /// This is an alias of an `iced_native` button with an `iced_wgpu::Renderer`. 15 | pub type Button<'a, Message> = iced_native::Button<'a, Message, Renderer>; 16 | -------------------------------------------------------------------------------- /native/src/event.rs: -------------------------------------------------------------------------------- 1 | use crate::{keyboard, mouse, window}; 2 | 3 | /// A user interface event. 4 | /// 5 | /// _**Note:** This type is largely incomplete! If you need to track 6 | /// additional events, feel free to [open an issue] and share your use case!_ 7 | /// 8 | /// [open an issue]: https://github.com/hecrj/iced/issues 9 | #[derive(PartialEq, Clone, Debug)] 10 | pub enum Event { 11 | /// A keyboard event 12 | Keyboard(keyboard::Event), 13 | 14 | /// A mouse event 15 | Mouse(mouse::Event), 16 | 17 | /// A window event 18 | Window(window::Event), 19 | } 20 | -------------------------------------------------------------------------------- /wgpu/src/widget/text_input.rs: -------------------------------------------------------------------------------- 1 | //! Display fields that can be filled with text. 2 | //! 3 | //! A [`TextInput`] has some local [`State`]. 4 | //! 5 | //! [`TextInput`]: struct.TextInput.html 6 | //! [`State`]: struct.State.html 7 | use crate::Renderer; 8 | 9 | pub use iced_native::text_input::State; 10 | pub use iced_style::text_input::{Style, StyleSheet}; 11 | 12 | /// A field that can be filled with text. 13 | /// 14 | /// This is an alias of an `iced_native` text input with an `iced_wgpu::Renderer`. 15 | pub type TextInput<'a, Message> = iced_native::TextInput<'a, Message, Renderer>; 16 | -------------------------------------------------------------------------------- /core/src/font.rs: -------------------------------------------------------------------------------- 1 | /// A font. 2 | #[derive(Debug, Clone, Copy)] 3 | pub enum Font { 4 | /// The default font. 5 | /// 6 | /// This is normally a font configured in a renderer or loaded from the 7 | /// system. 8 | Default, 9 | 10 | /// An external font. 11 | External { 12 | /// The name of the external font 13 | name: &'static str, 14 | 15 | /// The bytes of the external font 16 | bytes: &'static [u8], 17 | }, 18 | } 19 | 20 | impl Default for Font { 21 | fn default() -> Font { 22 | Font::Default 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /native/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iced_native" 3 | version = "0.2.2" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | description = "A renderer-agnostic library for native GUIs" 7 | license = "MIT" 8 | repository = "https://github.com/hecrj/iced" 9 | 10 | [dependencies] 11 | twox-hash = "1.5" 12 | raw-window-handle = "0.3" 13 | unicode-segmentation = "1.6" 14 | 15 | [dependencies.iced_core] 16 | version = "0.2" 17 | path = "../core" 18 | 19 | [dependencies.iced_futures] 20 | version = "0.1" 21 | path = "../futures" 22 | features = ["thread-pool"] 23 | -------------------------------------------------------------------------------- /wgpu/src/widget/progress_bar.rs: -------------------------------------------------------------------------------- 1 | //! Allow your users to visually track the progress of a computation. 2 | //! 3 | //! A [`ProgressBar`] has a range of possible values and a current value, 4 | //! as well as a length, height and style. 5 | //! 6 | //! [`ProgressBar`]: type.ProgressBar.html 7 | use crate::Renderer; 8 | 9 | pub use iced_style::progress_bar::{Style, StyleSheet}; 10 | 11 | /// A bar that displays progress. 12 | /// 13 | /// This is an alias of an `iced_native` progress bar with an 14 | /// `iced_wgpu::Renderer`. 15 | pub type ProgressBar = iced_native::ProgressBar; 16 | -------------------------------------------------------------------------------- /native/src/subscription/events.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | subscription::{EventStream, Recipe}, 3 | Event, Hasher, 4 | }; 5 | use iced_futures::BoxStream; 6 | 7 | pub struct Events; 8 | 9 | impl Recipe for Events { 10 | type Output = Event; 11 | 12 | fn hash(&self, state: &mut Hasher) { 13 | use std::hash::Hash; 14 | 15 | std::any::TypeId::of::().hash(state); 16 | } 17 | 18 | fn stream( 19 | self: Box, 20 | event_stream: EventStream, 21 | ) -> BoxStream { 22 | event_stream 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /wgpu/src/shader/blit.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) out vec2 o_Uv; 4 | 5 | const vec2 positions[6] = vec2[6]( 6 | vec2(-1.0, 1.0), 7 | vec2(-1.0, -1.0), 8 | vec2(1.0, -1.0), 9 | vec2(-1.0, 1.0), 10 | vec2(1.0, 1.0), 11 | vec2(1.0, -1.0) 12 | ); 13 | 14 | const vec2 uvs[6] = vec2[6]( 15 | vec2(0.0, 0.0), 16 | vec2(0.0, 1.0), 17 | vec2(1.0, 1.0), 18 | vec2(0.0, 0.0), 19 | vec2(1.0, 0.0), 20 | vec2(1.0, 1.0) 21 | ); 22 | 23 | void main() { 24 | o_Uv = uvs[gl_VertexIndex]; 25 | gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); 26 | } 27 | -------------------------------------------------------------------------------- /futures/src/executor/tokio.rs: -------------------------------------------------------------------------------- 1 | use crate::Executor; 2 | 3 | use futures::Future; 4 | 5 | /// A `tokio` runtime. 6 | #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] 7 | pub type Tokio = tokio::runtime::Runtime; 8 | 9 | impl Executor for Tokio { 10 | fn new() -> Result { 11 | tokio::runtime::Runtime::new() 12 | } 13 | 14 | fn spawn(&self, future: impl Future + Send + 'static) { 15 | let _ = tokio::runtime::Runtime::spawn(self, future); 16 | } 17 | 18 | fn enter(&self, f: impl FnOnce() -> R) -> R { 19 | tokio::runtime::Runtime::enter(self, f) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget/image.rs: -------------------------------------------------------------------------------- 1 | use crate::{Primitive, Renderer}; 2 | use iced_native::{image, mouse, Layout}; 3 | 4 | impl image::Renderer for Renderer { 5 | fn dimensions(&self, handle: &image::Handle) -> (u32, u32) { 6 | self.image_pipeline.dimensions(handle) 7 | } 8 | 9 | fn draw( 10 | &mut self, 11 | handle: image::Handle, 12 | layout: Layout<'_>, 13 | ) -> Self::Output { 14 | ( 15 | Primitive::Image { 16 | handle, 17 | bounds: layout.bounds(), 18 | }, 19 | mouse::Interaction::default(), 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget/svg.rs: -------------------------------------------------------------------------------- 1 | use crate::{Primitive, Renderer}; 2 | use iced_native::{mouse, svg, Layout}; 3 | 4 | impl svg::Renderer for Renderer { 5 | fn dimensions(&self, handle: &svg::Handle) -> (u32, u32) { 6 | self.image_pipeline.viewport_dimensions(handle) 7 | } 8 | 9 | fn draw( 10 | &mut self, 11 | handle: svg::Handle, 12 | layout: Layout<'_>, 13 | ) -> Self::Output { 14 | ( 15 | Primitive::Svg { 16 | handle, 17 | bounds: layout.bounds(), 18 | }, 19 | mouse::Interaction::default(), 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/window/settings.rs: -------------------------------------------------------------------------------- 1 | /// The window settings of an application. 2 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 3 | pub struct Settings { 4 | /// The size of the window. 5 | pub size: (u32, u32), 6 | 7 | /// Whether the window should be resizable or not. 8 | pub resizable: bool, 9 | 10 | /// Whether the window should have a border, a title bar, etc. or not. 11 | pub decorations: bool, 12 | } 13 | 14 | impl Default for Settings { 15 | fn default() -> Settings { 16 | Settings { 17 | size: (1024, 768), 18 | resizable: true, 19 | decorations: true, 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /wgpu/src/widget/slider.rs: -------------------------------------------------------------------------------- 1 | //! Display an interactive selector of a single value from a range of values. 2 | //! 3 | //! A [`Slider`] has some local [`State`]. 4 | //! 5 | //! [`Slider`]: struct.Slider.html 6 | //! [`State`]: struct.State.html 7 | use crate::Renderer; 8 | 9 | pub use iced_native::slider::State; 10 | pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet}; 11 | 12 | /// An horizontal bar and a handle that selects a single value from a range of 13 | /// values. 14 | /// 15 | /// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`. 16 | pub type Slider<'a, Message> = iced_native::Slider<'a, Message, Renderer>; 17 | -------------------------------------------------------------------------------- /wgpu/src/image/atlas/entry.rs: -------------------------------------------------------------------------------- 1 | use crate::image::atlas; 2 | 3 | #[derive(Debug)] 4 | pub enum Entry { 5 | Contiguous(atlas::Allocation), 6 | Fragmented { 7 | size: (u32, u32), 8 | fragments: Vec, 9 | }, 10 | } 11 | 12 | impl Entry { 13 | #[cfg(feature = "image")] 14 | pub fn size(&self) -> (u32, u32) { 15 | match self { 16 | Entry::Contiguous(allocation) => allocation.size(), 17 | Entry::Fragmented { size, .. } => *size, 18 | } 19 | } 20 | } 21 | 22 | #[derive(Debug)] 23 | pub struct Fragment { 24 | pub position: (u32, u32), 25 | pub allocation: atlas::Allocation, 26 | } 27 | -------------------------------------------------------------------------------- /winit/src/clipboard.rs: -------------------------------------------------------------------------------- 1 | /// A buffer for short-term storage and transfer within and between 2 | /// applications. 3 | #[allow(missing_debug_implementations)] 4 | pub struct Clipboard(window_clipboard::Clipboard); 5 | 6 | impl Clipboard { 7 | /// Creates a new [`Clipboard`] for the given window. 8 | /// 9 | /// [`Clipboard`]: struct.Clipboard.html 10 | pub fn new(window: &winit::window::Window) -> Option { 11 | window_clipboard::Clipboard::new(window).map(Clipboard).ok() 12 | } 13 | } 14 | 15 | impl iced_native::Clipboard for Clipboard { 16 | fn content(&self) -> Option { 17 | self.0.read().ok() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/download_progress/README.md: -------------------------------------------------------------------------------- 1 | ## Download progress 2 | 3 | A basic application that asynchronously downloads a dummy file of 100 MB and tracks the download progress. 4 | 5 | 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. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run it with `cargo run`: 14 | 15 | ``` 16 | cargo run --package download_progress 17 | ``` 18 | -------------------------------------------------------------------------------- /winit/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iced_winit" 3 | version = "0.1.1" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | description = "A winit runtime for Iced" 7 | license = "MIT" 8 | repository = "https://github.com/hecrj/iced" 9 | documentation = "https://docs.rs/iced_winit" 10 | keywords = ["gui", "ui", "graphics", "interface", "widgets"] 11 | categories = ["gui"] 12 | 13 | [features] 14 | debug = [] 15 | 16 | [dependencies] 17 | winit = "0.22" 18 | window_clipboard = "0.1" 19 | log = "0.4" 20 | 21 | [dependencies.iced_native] 22 | version = "0.2" 23 | path = "../native" 24 | 25 | [target.'cfg(target_os = "windows")'.dependencies.winapi] 26 | version = "0.3.6" 27 | -------------------------------------------------------------------------------- /docs/graphs/wgpu.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | fontname = "Roboto"; 3 | newrank=true; 4 | node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"]; 5 | edge[color="#333333"]; 6 | 7 | subgraph cluster_1 { 8 | label = "renderers "; 9 | labelloc = "b"; 10 | labeljust = "r"; 11 | fontcolor = "#0366d6"; 12 | color="#f6f8fa"; 13 | bgcolor="#f6f8fa"; 14 | style=rounded; 15 | 16 | etc_1 [label="...", style=solid, shape=none]; 17 | iced_wgpu; 18 | } 19 | 20 | subgraph cluster_3 { 21 | style=invis; 22 | margin=20; 23 | iced; 24 | } 25 | 26 | { rank = same; iced_wgpu etc_1 } 27 | 28 | iced_native -> iced_wgpu; 29 | 30 | iced_wgpu -> iced; 31 | } 32 | -------------------------------------------------------------------------------- /docs/graphs/winit.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | fontname = "Roboto"; 3 | newrank=true; 4 | node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"]; 5 | edge[color="#333333"]; 6 | 7 | subgraph cluster_2 { 8 | label = "shells "; 9 | labelloc = "b"; 10 | labeljust = "r"; 11 | fontcolor = "#0366d6"; 12 | color="#f6f8fa"; 13 | bgcolor="#f6f8fa"; 14 | style=rounded; 15 | 16 | etc_2 [label="...", style=solid, shape=none]; 17 | iced_winit; 18 | } 19 | 20 | subgraph cluster_3 { 21 | style=invis; 22 | margin=20; 23 | iced; 24 | } 25 | 26 | { rank = same; iced_winit etc_2 } 27 | 28 | iced_native -> iced_winit; 29 | 30 | iced_winit -> iced; 31 | } 32 | -------------------------------------------------------------------------------- /wgpu/src/defaults.rs: -------------------------------------------------------------------------------- 1 | //! Use default styling attributes to inherit styles. 2 | use iced_native::Color; 3 | 4 | /// Some default styling attributes. 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Defaults { 7 | /// Text styling 8 | pub text: Text, 9 | } 10 | 11 | impl Default for Defaults { 12 | fn default() -> Defaults { 13 | Defaults { 14 | text: Text::default(), 15 | } 16 | } 17 | } 18 | 19 | /// Some default text styling attributes. 20 | #[derive(Debug, Clone, Copy)] 21 | pub struct Text { 22 | /// The default color of text 23 | pub color: Color, 24 | } 25 | 26 | impl Default for Text { 27 | fn default() -> Text { 28 | Text { 29 | color: Color::BLACK, 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/todos/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "todos" 3 | version = "0.1.0" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [dependencies] 9 | iced = { path = "../..", features = ["async-std"] } 10 | serde = { version = "1.0", features = ["derive"] } 11 | serde_json = "1.0" 12 | 13 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 14 | async-std = "1.0" 15 | directories = "2.0" 16 | 17 | [target.'cfg(target_arch = "wasm32")'.dependencies] 18 | web-sys = { version = "0.3", features = ["Window", "Storage"] } 19 | wasm-timer = "0.2" 20 | 21 | [package.metadata.deb] 22 | assets = [ 23 | ["target/release/todos", "usr/bin/iced-todos", "755"], 24 | ["iced-todos.desktop", "usr/share/applications/", "644"], 25 | ] 26 | -------------------------------------------------------------------------------- /winit/src/size.rs: -------------------------------------------------------------------------------- 1 | pub struct Size { 2 | physical: winit::dpi::PhysicalSize, 3 | logical: winit::dpi::LogicalSize, 4 | scale_factor: f64, 5 | } 6 | 7 | impl Size { 8 | pub fn new( 9 | physical: winit::dpi::PhysicalSize, 10 | scale_factor: f64, 11 | ) -> Size { 12 | Size { 13 | logical: physical.to_logical(scale_factor), 14 | physical, 15 | scale_factor, 16 | } 17 | } 18 | 19 | pub fn physical(&self) -> winit::dpi::PhysicalSize { 20 | self.physical 21 | } 22 | 23 | pub fn logical(&self) -> winit::dpi::LogicalSize { 24 | self.logical 25 | } 26 | 27 | pub fn scale_factor(&self) -> f64 { 28 | self.scale_factor 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/todos/README.md: -------------------------------------------------------------------------------- 1 | ## Todos 2 | 3 | A todos tracker inspired by [TodoMVC]. It showcases dynamic layout, text input, checkboxes, scrollables, icons, and async actions! It automatically saves your tasks in the background, even if you did not finish typing them. 4 | 5 | All the example code is located in the __[`main`]__ file. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | You can run the native version with `cargo run`: 14 | ``` 15 | cargo run --package todos 16 | ``` 17 | We have not yet implemented a `LocalStorage` version of the auto-save feature. Therefore, it does not work on web _yet_! 18 | 19 | [`main`]: src/main.rs 20 | [TodoMVC]: http://todomvc.com/ 21 | -------------------------------------------------------------------------------- /wgpu/src/shader/image.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 v_Pos; 4 | layout(location = 1) in vec2 i_Pos; 5 | layout(location = 2) in vec2 i_Scale; 6 | layout(location = 3) in vec2 i_Atlas_Pos; 7 | layout(location = 4) in vec2 i_Atlas_Scale; 8 | layout(location = 5) in uint i_Layer; 9 | 10 | layout (set = 0, binding = 0) uniform Globals { 11 | mat4 u_Transform; 12 | }; 13 | 14 | layout(location = 0) out vec3 o_Uv; 15 | 16 | void main() { 17 | o_Uv = vec3(v_Pos * i_Atlas_Scale + i_Atlas_Pos, i_Layer); 18 | 19 | mat4 i_Transform = mat4( 20 | vec4(i_Scale.x, 0.0, 0.0, 0.0), 21 | vec4(0.0, i_Scale.y, 0.0, 0.0), 22 | vec4(0.0, 0.0, 1.0, 0.0), 23 | vec4(i_Pos, 0.0, 1.0) 24 | ); 25 | 26 | gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0); 27 | } 28 | -------------------------------------------------------------------------------- /examples/pane_grid/README.md: -------------------------------------------------------------------------------- 1 | ## Pane grid 2 | 3 | A grid of panes that can be split, resized, and reorganized. 4 | 5 | This example showcases the `PaneGrid` widget, which features: 6 | 7 | * Vertical and horizontal splits 8 | * Tracking of the last active pane 9 | * Mouse-based resizing 10 | * Drag and drop to reorganize panes 11 | * Hotkey support 12 | * Configurable modifier keys 13 | * API to perform actions programmatically (`split`, `swap`, `resize`, etc.) 14 | 15 | The __[`main`]__ file contains all the code of the example. 16 | 17 |
18 | 19 | 20 | 21 |
22 | 23 | You can run it with `cargo run`: 24 | ``` 25 | cargo run --package pane_grid 26 | ``` 27 | 28 | [`main`]: src/main.rs 29 | -------------------------------------------------------------------------------- /wgpu/src/viewport.rs: -------------------------------------------------------------------------------- 1 | use crate::Transformation; 2 | 3 | /// A viewing region for displaying computer graphics. 4 | #[derive(Debug)] 5 | pub struct Viewport { 6 | width: u32, 7 | height: u32, 8 | transformation: Transformation, 9 | } 10 | 11 | impl Viewport { 12 | /// Creates a new [`Viewport`] with the given dimensions. 13 | pub fn new(width: u32, height: u32) -> Viewport { 14 | Viewport { 15 | width, 16 | height, 17 | transformation: Transformation::orthographic(width, height), 18 | } 19 | } 20 | 21 | /// Returns the dimensions of the [`Viewport`]. 22 | pub fn dimensions(&self) -> (u32, u32) { 23 | (self.width, self.height) 24 | } 25 | 26 | pub(crate) fn transformation(&self) -> Transformation { 27 | self.transformation 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/game_of_life/README.md: -------------------------------------------------------------------------------- 1 | ## Game of Life 2 | 3 | An interactive version of the [Game of Life], invented by [John Horton Conway]. 4 | 5 | It runs a simulation in a background thread while allowing interaction with a `Canvas` that displays an infinite grid with zooming, panning, and drawing support. 6 | 7 | The __[`main`]__ file contains the relevant code of the example. 8 | 9 |
10 | 11 | 12 | 13 |
14 | 15 | You can run it with `cargo run`: 16 | ``` 17 | cargo run --package game_of_life 18 | ``` 19 | 20 | [`main`]: src/main.rs 21 | [Game of Life]: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life 22 | [John Horton Conway]: https://en.wikipedia.org/wiki/John_Horton_Conway 23 | -------------------------------------------------------------------------------- /web/src/subscription.rs: -------------------------------------------------------------------------------- 1 | //! Listen to external events in your application. 2 | use crate::Hasher; 3 | 4 | /// A request to listen to external events. 5 | /// 6 | /// Besides performing async actions on demand with [`Command`], most 7 | /// applications also need to listen to external events passively. 8 | /// 9 | /// A [`Subscription`] is normally provided to some runtime, like a [`Command`], 10 | /// and it will generate events as long as the user keeps requesting it. 11 | /// 12 | /// For instance, you can use a [`Subscription`] to listen to a WebSocket 13 | /// connection, keyboard presses, mouse events, time ticks, etc. 14 | /// 15 | /// [`Command`]: ../struct.Command.html 16 | /// [`Subscription`]: struct.Subscription.html 17 | pub type Subscription = iced_futures::Subscription; 18 | 19 | pub use iced_futures::subscription::Recipe; 20 | -------------------------------------------------------------------------------- /core/src/align.rs: -------------------------------------------------------------------------------- 1 | /// Alignment on an axis of a container. 2 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 3 | pub enum Align { 4 | /// Align at the start of the axis. 5 | Start, 6 | 7 | /// Align at the center of the axis. 8 | Center, 9 | 10 | /// Align at the end of the axis. 11 | End, 12 | } 13 | 14 | /// The horizontal alignment of some resource. 15 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 16 | pub enum HorizontalAlignment { 17 | /// Align left 18 | Left, 19 | 20 | /// Horizontally centered 21 | Center, 22 | 23 | /// Align right 24 | Right, 25 | } 26 | 27 | /// The vertical alignment of some resource. 28 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 29 | pub enum VerticalAlignment { 30 | /// Align top 31 | Top, 32 | 33 | /// Vertically centered 34 | Center, 35 | 36 | /// Align bottom 37 | Bottom, 38 | } 39 | -------------------------------------------------------------------------------- /core/src/keyboard/event.rs: -------------------------------------------------------------------------------- 1 | use super::{KeyCode, ModifiersState}; 2 | 3 | /// A keyboard event. 4 | /// 5 | /// _**Note:** This type is largely incomplete! If you need to track 6 | /// additional events, feel free to [open an issue] and share your use case!_ 7 | /// 8 | /// [open an issue]: https://github.com/hecrj/iced/issues 9 | #[derive(Debug, Clone, Copy, PartialEq)] 10 | pub enum Event { 11 | /// A keyboard key was pressed. 12 | KeyPressed { 13 | /// The key identifier 14 | key_code: KeyCode, 15 | 16 | /// The state of the modifier keys 17 | modifiers: ModifiersState, 18 | }, 19 | 20 | /// A keyboard key was released. 21 | KeyReleased { 22 | /// The key identifier 23 | key_code: KeyCode, 24 | 25 | /// The state of the modifier keys 26 | modifiers: ModifiersState, 27 | }, 28 | 29 | /// A unicode character was received. 30 | CharacterReceived(char), 31 | } 32 | -------------------------------------------------------------------------------- /examples/svg/src/main.rs: -------------------------------------------------------------------------------- 1 | use iced::{Container, Element, Length, Sandbox, Settings, Svg}; 2 | 3 | pub fn main() { 4 | Tiger::run(Settings::default()) 5 | } 6 | 7 | struct Tiger; 8 | 9 | impl Sandbox for Tiger { 10 | type Message = (); 11 | 12 | fn new() -> Self { 13 | Tiger 14 | } 15 | 16 | fn title(&self) -> String { 17 | String::from("SVG - Iced") 18 | } 19 | 20 | fn update(&mut self, _message: ()) {} 21 | 22 | fn view(&mut self) -> Element<()> { 23 | let svg = Svg::from_path(format!( 24 | "{}/resources/tiger.svg", 25 | env!("CARGO_MANIFEST_DIR") 26 | )) 27 | .width(Length::Fill) 28 | .height(Length::Fill); 29 | 30 | Container::new(svg) 31 | .width(Length::Fill) 32 | .height(Length::Fill) 33 | .padding(20) 34 | .center_x() 35 | .center_y() 36 | .into() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /wgpu/src/image/atlas/allocation.rs: -------------------------------------------------------------------------------- 1 | use crate::image::atlas::{self, allocator}; 2 | 3 | #[derive(Debug)] 4 | pub enum Allocation { 5 | Partial { 6 | layer: usize, 7 | region: allocator::Region, 8 | }, 9 | Full { 10 | layer: usize, 11 | }, 12 | } 13 | 14 | impl Allocation { 15 | pub fn position(&self) -> (u32, u32) { 16 | match self { 17 | Allocation::Partial { region, .. } => region.position(), 18 | Allocation::Full { .. } => (0, 0), 19 | } 20 | } 21 | 22 | pub fn size(&self) -> (u32, u32) { 23 | match self { 24 | Allocation::Partial { region, .. } => region.size(), 25 | Allocation::Full { .. } => (atlas::SIZE, atlas::SIZE), 26 | } 27 | } 28 | 29 | pub fn layer(&self) -> usize { 30 | match self { 31 | Allocation::Partial { layer, .. } => *layer, 32 | Allocation::Full { layer } => *layer, 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /wgpu/src/widget/canvas/geometry.rs: -------------------------------------------------------------------------------- 1 | use crate::Primitive; 2 | 3 | /// A bunch of shapes that can be drawn. 4 | /// 5 | /// [`Geometry`] can be easily generated with a [`Frame`] or stored in a 6 | /// [`Cache`]. 7 | /// 8 | /// [`Geometry`]: struct.Geometry.html 9 | /// [`Frame`]: struct.Frame.html 10 | /// [`Cache`]: struct.Cache.html 11 | #[derive(Debug, Clone)] 12 | pub struct Geometry(Primitive); 13 | 14 | impl Geometry { 15 | pub(crate) fn from_primitive(primitive: Primitive) -> Self { 16 | Self(primitive) 17 | } 18 | 19 | /// Turns the [`Geometry`] into a [`Primitive`]. 20 | /// 21 | /// This can be useful if you are building a custom widget. 22 | /// 23 | /// [`Geometry`]: struct.Geometry.html 24 | /// [`Primitive`]: ../enum.Primitive.html 25 | pub fn into_primitive(self) -> Primitive { 26 | self.0 27 | } 28 | } 29 | 30 | impl From for Primitive { 31 | fn from(geometry: Geometry) -> Primitive { 32 | geometry.0 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /native/src/layout/debugger.rs: -------------------------------------------------------------------------------- 1 | use crate::{Color, Layout, Point, Renderer, Widget}; 2 | 3 | /// A renderer able to graphically explain a [`Layout`]. 4 | /// 5 | /// [`Layout`]: struct.Layout.html 6 | pub trait Debugger: Renderer { 7 | /// Explains the [`Layout`] of an [`Element`] for debugging purposes. 8 | /// 9 | /// This will be called when [`Element::explain`] has been used. It should 10 | /// _explain_ the given [`Layout`] graphically. 11 | /// 12 | /// A common approach consists in recursively rendering the bounds of the 13 | /// [`Layout`] and its children. 14 | /// 15 | /// [`Layout`]: struct.Layout.html 16 | /// [`Element`]: ../struct.Element.html 17 | /// [`Element::explain`]: ../struct.Element.html#method.explain 18 | fn explain( 19 | &mut self, 20 | defaults: &Self::Defaults, 21 | widget: &dyn Widget, 22 | layout: Layout<'_>, 23 | cursor_position: Point, 24 | color: Color, 25 | ) -> Self::Output; 26 | } 27 | -------------------------------------------------------------------------------- /native/src/window/event.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | /// A window-related event. 4 | #[derive(PartialEq, Clone, Debug)] 5 | pub enum Event { 6 | /// A window was resized 7 | Resized { 8 | /// The new width of the window (in units) 9 | width: u32, 10 | 11 | /// The new height of the window (in units) 12 | height: u32, 13 | }, 14 | 15 | /// A file is being hovered over the window. 16 | /// 17 | /// When the user hovers multiple files at once, this event will be emitted 18 | /// for each file separately. 19 | FileHovered(PathBuf), 20 | 21 | /// A file has beend dropped into the window. 22 | /// 23 | /// When the user drops multiple files at once, this event will be emitted 24 | /// for each file separately. 25 | FileDropped(PathBuf), 26 | 27 | /// A file was hovered, but has exited the window. 28 | /// 29 | /// There will be a single `FilesHoveredLeft` event triggered even if 30 | /// multiple files were hovered. 31 | FilesHoveredLeft, 32 | } 33 | -------------------------------------------------------------------------------- /docs/graphs/native.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | fontname = "Roboto"; 3 | newrank=true; 4 | node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"]; 5 | edge[color="#333333"]; 6 | 7 | subgraph cluster_1 { 8 | label = "renderers "; 9 | labelloc = "b"; 10 | labeljust = "r"; 11 | fontcolor = "#0366d6"; 12 | color="#f6f8fa"; 13 | bgcolor="#f6f8fa"; 14 | style=rounded; 15 | 16 | etc_1 [label="...", style=solid, shape=none]; 17 | iced_wgpu; 18 | } 19 | 20 | subgraph cluster_2 { 21 | label = "shells "; 22 | labelloc = "b"; 23 | labeljust = "r"; 24 | fontcolor = "#0366d6"; 25 | color="#f6f8fa"; 26 | bgcolor="#f6f8fa"; 27 | style=rounded; 28 | 29 | etc_2 [label="...", style=solid, shape=none]; 30 | iced_winit; 31 | } 32 | 33 | 34 | { rank = same; iced_wgpu iced_winit etc_1 etc_2 } 35 | 36 | iced_core -> iced_native [style=dashed]; 37 | iced_native -> iced_wgpu; 38 | iced_native -> iced_winit; 39 | 40 | iced_core [style=dashed]; 41 | } 42 | -------------------------------------------------------------------------------- /docs/graphs/iced.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | fontname = "Roboto"; 3 | newrank=true; 4 | node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"]; 5 | edge[color="#333333"]; 6 | 7 | subgraph cluster_1 { 8 | label = "renderers "; 9 | labelloc = "b"; 10 | labeljust = "r"; 11 | fontcolor = "#0366d6"; 12 | color="#f6f8fa"; 13 | bgcolor="#f6f8fa"; 14 | style=rounded; 15 | 16 | etc_1 [label="...", style=solid, shape=none]; 17 | iced_wgpu; 18 | } 19 | 20 | subgraph cluster_2 { 21 | label = "shells "; 22 | labelloc = "b"; 23 | labeljust = "r"; 24 | fontcolor = "#0366d6"; 25 | color="#f6f8fa"; 26 | bgcolor="#f6f8fa"; 27 | style=rounded; 28 | 29 | etc_2 [label="...", style=solid, shape=none]; 30 | iced_winit; 31 | } 32 | 33 | subgraph cluster_3 { 34 | style=invis; 35 | margin=20; 36 | iced; 37 | } 38 | 39 | { rank = same; iced_wgpu iced_winit etc_1 etc_2 } 40 | 41 | iced_winit -> iced; 42 | iced_wgpu -> iced; 43 | iced_web -> iced; 44 | 45 | iced; 46 | } 47 | -------------------------------------------------------------------------------- /winit/src/debug/null.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub struct Debug; 3 | 4 | impl Debug { 5 | pub fn new() -> Self { 6 | Self 7 | } 8 | 9 | pub fn startup_started(&mut self) {} 10 | 11 | pub fn startup_finished(&mut self) {} 12 | 13 | pub fn update_started(&mut self) {} 14 | 15 | pub fn update_finished(&mut self) {} 16 | 17 | pub fn view_started(&mut self) {} 18 | 19 | pub fn view_finished(&mut self) {} 20 | 21 | pub fn layout_started(&mut self) {} 22 | 23 | pub fn layout_finished(&mut self) {} 24 | 25 | pub fn event_processing_started(&mut self) {} 26 | 27 | pub fn event_processing_finished(&mut self) {} 28 | 29 | pub fn draw_started(&mut self) {} 30 | 31 | pub fn draw_finished(&mut self) {} 32 | 33 | pub fn render_started(&mut self) {} 34 | 35 | pub fn render_finished(&mut self) {} 36 | 37 | pub fn log_message( 38 | &mut self, 39 | _message: &Message, 40 | ) { 41 | } 42 | 43 | pub fn overlay(&self) -> Vec { 44 | Vec::new() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/README.md: -------------------------------------------------------------------------------- 1 | # `iced_core` 2 | [![Documentation](https://docs.rs/iced_core/badge.svg)][documentation] 3 | [![Crates.io](https://img.shields.io/crates/v/iced_core.svg)](https://crates.io/crates/iced_core) 4 | [![License](https://img.shields.io/crates/l/iced_core.svg)](https://github.com/hecrj/iced/blob/master/LICENSE) 5 | [![project chat](https://img.shields.io/badge/chat-on_zulip-brightgreen.svg)](https://iced.zulipchat.com) 6 | 7 | `iced_core` holds basic reusable types of the public API. For instance, basic data types like `Point`, `Rectangle`, `Length`, etc. 8 | 9 | This crate is meant to be a starting point for an Iced runtime. 10 | 11 | ![iced_core](../docs/graphs/core.png) 12 | 13 | [documentation]: https://docs.rs/iced_core 14 | 15 | ## Installation 16 | Add `iced_core` as a dependency in your `Cargo.toml`: 17 | 18 | ```toml 19 | iced_core = "0.2" 20 | ``` 21 | 22 | __Iced moves fast and the `master` branch can contain breaking changes!__ If 23 | you want to learn about a specific release, check out [the release list]. 24 | 25 | [the release list]: https://github.com/hecrj/iced/releases 26 | -------------------------------------------------------------------------------- /examples/tour/README.md: -------------------------------------------------------------------------------- 1 | ## Tour 2 | 3 | A simple UI tour that can run both on native platforms and the web! It showcases different widgets that can be built using Iced. 4 | 5 | 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__. 6 | 7 |
8 | 9 | 10 | 11 |
12 | 13 | [`main`]: src/main.rs 14 | [`iced_winit`]: ../../winit 15 | [`iced_native`]: ../../native 16 | [`iced_wgpu`]: ../../wgpu 17 | [`iced_web`]: ../../web 18 | [`winit`]: https://github.com/rust-windowing/winit 19 | [`wgpu`]: https://github.com/gfx-rs/wgpu-rs 20 | 21 | You can run the native version with `cargo run`: 22 | ``` 23 | cargo run --package tour 24 | ``` 25 | 26 | The web version can be run by following [the usage instructions of `iced_web`] or by accessing [iced.rs](https://iced.rs/)! 27 | 28 | [the usage instructions of `iced_web`]: ../../web#usage 29 | -------------------------------------------------------------------------------- /futures/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iced_futures" 3 | version = "0.1.2" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | description = "Commands, subscriptions, and runtimes for Iced" 7 | license = "MIT" 8 | repository = "https://github.com/hecrj/iced" 9 | documentation = "https://docs.rs/iced_futures" 10 | keywords = ["gui", "ui", "graphics", "interface", "futures"] 11 | categories = ["gui"] 12 | 13 | [features] 14 | thread-pool = ["futures/thread-pool"] 15 | 16 | [dependencies] 17 | log = "0.4" 18 | 19 | [dependencies.futures] 20 | version = "0.3" 21 | 22 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio] 23 | version = "0.2" 24 | optional = true 25 | features = ["rt-core", "rt-threaded", "time", "stream"] 26 | 27 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies.async-std] 28 | version = "1.0" 29 | optional = true 30 | features = ["unstable"] 31 | 32 | [target.'cfg(target_arch = "wasm32")'.dependencies] 33 | wasm-bindgen-futures = "0.4" 34 | 35 | [package.metadata.docs.rs] 36 | rustdoc-args = ["--cfg", "docsrs"] 37 | all-features = true 38 | -------------------------------------------------------------------------------- /style/src/progress_bar.rs: -------------------------------------------------------------------------------- 1 | //! Provide progress feedback to your users. 2 | use iced_core::{Background, Color}; 3 | 4 | /// The appearance of a progress bar. 5 | #[derive(Debug)] 6 | pub struct Style { 7 | pub background: Background, 8 | pub bar: Background, 9 | pub border_radius: u16, 10 | } 11 | 12 | /// A set of rules that dictate the style of a progress bar. 13 | pub trait StyleSheet { 14 | fn style(&self) -> Style; 15 | } 16 | 17 | struct Default; 18 | 19 | impl StyleSheet for Default { 20 | fn style(&self) -> Style { 21 | Style { 22 | background: Background::Color(Color::from_rgb(0.6, 0.6, 0.6)), 23 | bar: Background::Color(Color::from_rgb(0.3, 0.9, 0.3)), 24 | border_radius: 5, 25 | } 26 | } 27 | } 28 | 29 | impl std::default::Default for Box { 30 | fn default() -> Self { 31 | Box::new(Default) 32 | } 33 | } 34 | 35 | impl From for Box 36 | where 37 | T: 'static + StyleSheet, 38 | { 39 | fn from(style: T) -> Self { 40 | Box::new(style) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core/src/keyboard/modifiers_state.rs: -------------------------------------------------------------------------------- 1 | /// The current state of the keyboard modifiers. 2 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 3 | pub struct ModifiersState { 4 | /// Whether a shift key is pressed 5 | pub shift: bool, 6 | 7 | /// Whether a control key is pressed 8 | pub control: bool, 9 | 10 | /// Whether an alt key is pressed 11 | pub alt: bool, 12 | 13 | /// Whether a logo key is pressed (e.g. windows key, command key...) 14 | pub logo: bool, 15 | } 16 | 17 | impl ModifiersState { 18 | /// Returns true if the current [`ModifiersState`] has at least the same 19 | /// modifiers enabled as the given value, and false otherwise. 20 | /// 21 | /// [`ModifiersState`]: struct.ModifiersState.html 22 | pub fn matches(&self, modifiers: ModifiersState) -> bool { 23 | let shift = !modifiers.shift || self.shift; 24 | let control = !modifiers.control || self.control; 25 | let alt = !modifiers.alt || self.alt; 26 | let logo = !modifiers.logo || self.logo; 27 | 28 | shift && control && alt && logo 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /web/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iced_web" 3 | version = "0.2.1" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | description = "A web backend for Iced" 7 | license = "MIT" 8 | repository = "https://github.com/hecrj/iced" 9 | documentation = "https://docs.rs/iced_web" 10 | readme = "README.md" 11 | keywords = ["gui", "ui", "web", "interface", "widgets"] 12 | categories = ["web-programming"] 13 | 14 | [badges] 15 | maintenance = { status = "actively-developed" } 16 | 17 | [dependencies] 18 | dodrio = "0.1.0" 19 | wasm-bindgen = "0.2.51" 20 | wasm-bindgen-futures = "0.4" 21 | url = "2.0" 22 | 23 | [dependencies.iced_core] 24 | version = "0.2" 25 | path = "../core" 26 | 27 | [dependencies.iced_futures] 28 | version = "0.1" 29 | path = "../futures" 30 | 31 | [dependencies.iced_style] 32 | version = "0.1" 33 | path = "../style" 34 | 35 | [dependencies.web-sys] 36 | version = "0.3.27" 37 | features = [ 38 | "console", 39 | "Document", 40 | "HtmlElement", 41 | "HtmlInputElement", 42 | "Event", 43 | "EventTarget", 44 | "InputEvent", 45 | "KeyboardEvent", 46 | ] 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Héctor Ramón, Iced contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: [push, pull_request] 3 | jobs: 4 | native: 5 | runs-on: ${{ matrix.os }} 6 | strategy: 7 | matrix: 8 | os: [ubuntu-latest, windows-latest, macOS-latest] 9 | rust: [stable, beta] 10 | steps: 11 | - uses: hecrj/setup-rust-action@v1 12 | with: 13 | rust-version: ${{ matrix.rust }} 14 | - uses: actions/checkout@master 15 | - name: Run tests 16 | run: | 17 | cargo test --verbose --all 18 | cargo test --verbose --all --all-features 19 | 20 | web: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: hecrj/setup-rust-action@v1 24 | with: 25 | rust-version: stable 26 | targets: wasm32-unknown-unknown 27 | - uses: actions/checkout@master 28 | - name: Run checks 29 | run: cargo check --package iced --target wasm32-unknown-unknown 30 | - name: Check compilation of `tour` example 31 | run: cargo build --package tour --target wasm32-unknown-unknown 32 | - name: Check compilation of `pokedex` example 33 | run: cargo build --package pokedex --target wasm32-unknown-unknown 34 | -------------------------------------------------------------------------------- /wgpu/src/text/font.rs: -------------------------------------------------------------------------------- 1 | pub use font_kit::{ 2 | error::SelectionError as LoadError, family_name::FamilyName as Family, 3 | }; 4 | 5 | pub struct Source { 6 | raw: font_kit::source::SystemSource, 7 | } 8 | 9 | impl Source { 10 | pub fn new() -> Self { 11 | Source { 12 | raw: font_kit::source::SystemSource::new(), 13 | } 14 | } 15 | 16 | pub fn load(&self, families: &[Family]) -> Result, LoadError> { 17 | let font = self.raw.select_best_match( 18 | families, 19 | &font_kit::properties::Properties::default(), 20 | )?; 21 | 22 | match font { 23 | font_kit::handle::Handle::Path { path, .. } => { 24 | use std::io::Read; 25 | 26 | let mut buf = Vec::new(); 27 | let mut reader = std::fs::File::open(path).expect("Read font"); 28 | let _ = reader.read_to_end(&mut buf); 29 | 30 | Ok(buf) 31 | } 32 | font_kit::handle::Handle::Memory { bytes, .. } => { 33 | Ok(bytes.as_ref().clone()) 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /wgpu/src/widget/pane_grid.rs: -------------------------------------------------------------------------------- 1 | //! Let your users split regions of your application and organize layout dynamically. 2 | //! 3 | //! [![Pane grid - Iced](https://thumbs.gfycat.com/MixedFlatJellyfish-small.gif)](https://gfycat.com/mixedflatjellyfish) 4 | //! 5 | //! # Example 6 | //! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing, 7 | //! drag and drop, and hotkey support. 8 | //! 9 | //! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.1/examples/pane_grid 10 | //! [`PaneGrid`]: type.PaneGrid.html 11 | use crate::Renderer; 12 | 13 | pub use iced_native::pane_grid::{ 14 | Axis, Direction, DragEvent, Focus, KeyPressEvent, Pane, ResizeEvent, Split, 15 | State, 16 | }; 17 | 18 | /// A collection of panes distributed using either vertical or horizontal splits 19 | /// to completely fill the space available. 20 | /// 21 | /// [![Pane grid - Iced](https://thumbs.gfycat.com/MixedFlatJellyfish-small.gif)](https://gfycat.com/mixedflatjellyfish) 22 | /// 23 | /// This is an alias of an `iced_native` pane grid with an `iced_wgpu::Renderer`. 24 | pub type PaneGrid<'a, Message> = iced_native::PaneGrid<'a, Message, Renderer>; 25 | -------------------------------------------------------------------------------- /wgpu/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iced_wgpu" 3 | version = "0.2.2" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | description = "A wgpu renderer for Iced" 7 | license = "MIT AND OFL-1.1" 8 | repository = "https://github.com/hecrj/iced" 9 | 10 | [features] 11 | svg = ["resvg"] 12 | canvas = ["lyon"] 13 | 14 | [dependencies] 15 | wgpu = "0.5" 16 | wgpu_glyph = "0.8" 17 | zerocopy = "0.3" 18 | glyph_brush = "0.6" 19 | raw-window-handle = "0.3" 20 | glam = "0.8" 21 | font-kit = "0.6" 22 | log = "0.4" 23 | guillotiere = "0.5" 24 | # Pin `gfx-memory` until https://github.com/gfx-rs/wgpu-rs/issues/261 is 25 | # resolved 26 | gfx-memory = "=0.1.1" 27 | 28 | [dependencies.iced_native] 29 | version = "0.2" 30 | path = "../native" 31 | 32 | [dependencies.iced_style] 33 | version = "0.1" 34 | path = "../style" 35 | 36 | [dependencies.image] 37 | version = "0.23" 38 | optional = true 39 | 40 | [dependencies.resvg] 41 | version = "0.9" 42 | features = ["raqote-backend"] 43 | optional = true 44 | 45 | [dependencies.lyon] 46 | version = "0.15" 47 | optional = true 48 | 49 | [package.metadata.docs.rs] 50 | rustdoc-args = ["--cfg", "docsrs"] 51 | all-features = true 52 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget/row.rs: -------------------------------------------------------------------------------- 1 | use crate::{Primitive, Renderer}; 2 | use iced_native::{mouse, row, Element, Layout, Point}; 3 | 4 | impl row::Renderer for Renderer { 5 | fn draw( 6 | &mut self, 7 | defaults: &Self::Defaults, 8 | children: &[Element<'_, Message, Self>], 9 | layout: Layout<'_>, 10 | cursor_position: Point, 11 | ) -> Self::Output { 12 | let mut mouse_interaction = mouse::Interaction::default(); 13 | 14 | ( 15 | Primitive::Group { 16 | primitives: children 17 | .iter() 18 | .zip(layout.children()) 19 | .map(|(child, layout)| { 20 | let (primitive, new_mouse_interaction) = 21 | child.draw(self, defaults, layout, cursor_position); 22 | 23 | if new_mouse_interaction > mouse_interaction { 24 | mouse_interaction = new_mouse_interaction; 25 | } 26 | 27 | primitive 28 | }) 29 | .collect(), 30 | }, 31 | mouse_interaction, 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget/column.rs: -------------------------------------------------------------------------------- 1 | use crate::{Primitive, Renderer}; 2 | use iced_native::{column, mouse, Element, Layout, Point}; 3 | 4 | impl column::Renderer for Renderer { 5 | fn draw( 6 | &mut self, 7 | defaults: &Self::Defaults, 8 | content: &[Element<'_, Message, Self>], 9 | layout: Layout<'_>, 10 | cursor_position: Point, 11 | ) -> Self::Output { 12 | let mut mouse_interaction = mouse::Interaction::default(); 13 | 14 | ( 15 | Primitive::Group { 16 | primitives: content 17 | .iter() 18 | .zip(layout.children()) 19 | .map(|(child, layout)| { 20 | let (primitive, new_mouse_interaction) = 21 | child.draw(self, defaults, layout, cursor_position); 22 | 23 | if new_mouse_interaction > mouse_interaction { 24 | mouse_interaction = new_mouse_interaction; 25 | } 26 | 27 | primitive 28 | }) 29 | .collect(), 30 | }, 31 | mouse_interaction, 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/progress_bar/src/main.rs: -------------------------------------------------------------------------------- 1 | use iced::{slider, Column, Element, ProgressBar, Sandbox, Settings, Slider}; 2 | 3 | pub fn main() { 4 | Progress::run(Settings::default()) 5 | } 6 | 7 | #[derive(Default)] 8 | struct Progress { 9 | value: f32, 10 | progress_bar_slider: slider::State, 11 | } 12 | 13 | #[derive(Debug, Clone, Copy)] 14 | enum Message { 15 | SliderChanged(f32), 16 | } 17 | 18 | impl Sandbox for Progress { 19 | type Message = Message; 20 | 21 | fn new() -> Self { 22 | Self::default() 23 | } 24 | 25 | fn title(&self) -> String { 26 | String::from("A simple Progressbar") 27 | } 28 | 29 | fn update(&mut self, message: Message) { 30 | match message { 31 | Message::SliderChanged(x) => self.value = x, 32 | } 33 | } 34 | 35 | fn view(&mut self) -> Element { 36 | Column::new() 37 | .padding(20) 38 | .push(ProgressBar::new(0.0..=100.0, self.value)) 39 | .push(Slider::new( 40 | &mut self.progress_bar_slider, 41 | 0.0..=100.0, 42 | self.value, 43 | Message::SliderChanged, 44 | )) 45 | .into() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /wgpu/src/widget.rs: -------------------------------------------------------------------------------- 1 | //! Use the widgets supported out-of-the-box. 2 | //! 3 | //! # Re-exports 4 | //! For convenience, the contents of this module are available at the root 5 | //! module. Therefore, you can directly type: 6 | //! 7 | //! ``` 8 | //! use iced_wgpu::{button, Button}; 9 | //! ``` 10 | pub mod button; 11 | pub mod checkbox; 12 | pub mod container; 13 | pub mod pane_grid; 14 | pub mod progress_bar; 15 | pub mod radio; 16 | pub mod scrollable; 17 | pub mod slider; 18 | pub mod text_input; 19 | 20 | mod text; 21 | 22 | #[doc(no_inline)] 23 | pub use button::Button; 24 | #[doc(no_inline)] 25 | pub use checkbox::Checkbox; 26 | #[doc(no_inline)] 27 | pub use container::Container; 28 | #[doc(no_inline)] 29 | pub use pane_grid::PaneGrid; 30 | #[doc(no_inline)] 31 | pub use progress_bar::ProgressBar; 32 | #[doc(no_inline)] 33 | pub use radio::Radio; 34 | #[doc(no_inline)] 35 | pub use scrollable::Scrollable; 36 | #[doc(no_inline)] 37 | pub use slider::Slider; 38 | #[doc(no_inline)] 39 | pub use text_input::TextInput; 40 | 41 | pub use text::Text; 42 | 43 | #[cfg(feature = "canvas")] 44 | #[cfg_attr(docsrs, doc(cfg(feature = "canvas")))] 45 | pub mod canvas; 46 | 47 | #[cfg(feature = "canvas")] 48 | #[doc(no_inline)] 49 | pub use canvas::Canvas; 50 | -------------------------------------------------------------------------------- /core/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The core library of [Iced]. 2 | //! 3 | //! ![`iced_core` crate graph](https://github.com/hecrj/iced/blob/cae26cb7bc627f4a5b3bcf1cd023a0c552e8c65e/docs/graphs/core.png?raw=true) 4 | //! 5 | //! This library holds basic types that can be reused and re-exported in 6 | //! different runtime implementations. For instance, both [`iced_native`] and 7 | //! [`iced_web`] are built on top of `iced_core`. 8 | //! 9 | //! [Iced]: https://github.com/hecrj/iced 10 | //! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native 11 | //! [`iced_web`]: https://github.com/hecrj/iced/tree/master/web 12 | #![deny(missing_docs)] 13 | #![deny(missing_debug_implementations)] 14 | #![deny(unused_results)] 15 | #![forbid(unsafe_code)] 16 | #![forbid(rust_2018_idioms)] 17 | pub mod keyboard; 18 | pub mod mouse; 19 | 20 | mod align; 21 | mod background; 22 | mod color; 23 | mod font; 24 | mod length; 25 | mod point; 26 | mod rectangle; 27 | mod size; 28 | mod vector; 29 | 30 | pub use align::{Align, HorizontalAlignment, VerticalAlignment}; 31 | pub use background::Background; 32 | pub use color::Color; 33 | pub use font::Font; 34 | pub use length::Length; 35 | pub use point::Point; 36 | pub use rectangle::Rectangle; 37 | pub use size::Size; 38 | pub use vector::Vector; 39 | -------------------------------------------------------------------------------- /winit/README.md: -------------------------------------------------------------------------------- 1 | # `iced_winit` 2 | [![Documentation](https://docs.rs/iced_winit/badge.svg)][documentation] 3 | [![Crates.io](https://img.shields.io/crates/v/iced_winit.svg)](https://crates.io/crates/iced_winit) 4 | [![License](https://img.shields.io/crates/l/iced_winit.svg)](https://github.com/hecrj/iced/blob/master/LICENSE) 5 | [![project chat](https://img.shields.io/badge/chat-on_zulip-brightgreen.svg)](https://iced.zulipchat.com) 6 | 7 | `iced_winit` offers some convenient abstractions on top of [`iced_native`] to quickstart development when using [`winit`]. 8 | 9 | It exposes a renderer-agnostic `Application` trait that can be implemented and then run with a simple call. The use of this trait is optional. A `conversion` module is provided for users that decide to implement a custom event loop. 10 | 11 | ![iced_winit](../docs/graphs/winit.png) 12 | 13 | [documentation]: https://docs.rs/iced_winit 14 | [`iced_native`]: ../native 15 | [`winit`]: https://github.com/rust-windowing/winit 16 | 17 | ## Installation 18 | Add `iced_winit` as a dependency in your `Cargo.toml`: 19 | 20 | ```toml 21 | iced_winit = "0.1" 22 | ``` 23 | 24 | __Iced moves fast and the `master` branch can contain breaking changes!__ If 25 | you want to learn about a specific release, check out [the release list]. 26 | 27 | [the release list]: https://github.com/hecrj/iced/releases 28 | -------------------------------------------------------------------------------- /wgpu/src/shader/quad.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 v_Pos; 4 | layout(location = 1) in vec2 i_Pos; 5 | layout(location = 2) in vec2 i_Scale; 6 | layout(location = 3) in vec4 i_Color; 7 | layout(location = 4) in vec4 i_BorderColor; 8 | layout(location = 5) in float i_BorderRadius; 9 | layout(location = 6) in float i_BorderWidth; 10 | 11 | layout (set = 0, binding = 0) uniform Globals { 12 | mat4 u_Transform; 13 | float u_Scale; 14 | }; 15 | 16 | layout(location = 0) out vec4 o_Color; 17 | layout(location = 1) out vec4 o_BorderColor; 18 | layout(location = 2) out vec2 o_Pos; 19 | layout(location = 3) out vec2 o_Scale; 20 | layout(location = 4) out float o_BorderRadius; 21 | layout(location = 5) out float o_BorderWidth; 22 | 23 | void main() { 24 | vec2 p_Pos = i_Pos * u_Scale; 25 | vec2 p_Scale = i_Scale * u_Scale; 26 | 27 | mat4 i_Transform = mat4( 28 | vec4(p_Scale.x + 1.0, 0.0, 0.0, 0.0), 29 | vec4(0.0, p_Scale.y + 1.0, 0.0, 0.0), 30 | vec4(0.0, 0.0, 1.0, 0.0), 31 | vec4(p_Pos - vec2(0.5, 0.5), 0.0, 1.0) 32 | ); 33 | 34 | o_Color = i_Color; 35 | o_BorderColor = i_BorderColor; 36 | o_Pos = p_Pos; 37 | o_Scale = p_Scale; 38 | o_BorderRadius = i_BorderRadius * u_Scale; 39 | o_BorderWidth = i_BorderWidth * u_Scale; 40 | 41 | gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0); 42 | } 43 | -------------------------------------------------------------------------------- /style/src/radio.rs: -------------------------------------------------------------------------------- 1 | //! Create choices using radio buttons. 2 | use iced_core::{Background, Color}; 3 | 4 | /// The appearance of a radio button. 5 | #[derive(Debug)] 6 | pub struct Style { 7 | pub background: Background, 8 | pub dot_color: Color, 9 | pub border_width: u16, 10 | pub border_color: Color, 11 | } 12 | 13 | /// A set of rules that dictate the style of a radio button. 14 | pub trait StyleSheet { 15 | fn active(&self) -> Style; 16 | 17 | fn hovered(&self) -> Style; 18 | } 19 | 20 | struct Default; 21 | 22 | impl StyleSheet for Default { 23 | fn active(&self) -> Style { 24 | Style { 25 | background: Background::Color(Color::from_rgb(0.95, 0.95, 0.95)), 26 | dot_color: Color::from_rgb(0.3, 0.3, 0.3), 27 | border_width: 1, 28 | border_color: Color::from_rgb(0.6, 0.6, 0.6), 29 | } 30 | } 31 | 32 | fn hovered(&self) -> Style { 33 | Style { 34 | background: Background::Color(Color::from_rgb(0.90, 0.90, 0.90)), 35 | ..self.active() 36 | } 37 | } 38 | } 39 | 40 | impl std::default::Default for Box { 41 | fn default() -> Self { 42 | Box::new(Default) 43 | } 44 | } 45 | 46 | impl From for Box 47 | where 48 | T: 'static + StyleSheet, 49 | { 50 | fn from(style: T) -> Self { 51 | Box::new(style) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /wgpu/src/widget/canvas/path/arc.rs: -------------------------------------------------------------------------------- 1 | //! Build and draw curves. 2 | use iced_native::{Point, Vector}; 3 | 4 | /// A segment of a differentiable curve. 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Arc { 7 | /// The center of the arc. 8 | pub center: Point, 9 | /// The radius of the arc. 10 | pub radius: f32, 11 | /// The start of the segment's angle, clockwise rotation. 12 | pub start_angle: f32, 13 | /// The end of the segment's angle, clockwise rotation. 14 | pub end_angle: f32, 15 | } 16 | 17 | /// An elliptical [`Arc`]. 18 | /// 19 | /// [`Arc`]: struct.Arc.html 20 | #[derive(Debug, Clone, Copy)] 21 | pub struct Elliptical { 22 | /// The center of the arc. 23 | pub center: Point, 24 | /// The radii of the arc's ellipse, defining its axes. 25 | pub radii: Vector, 26 | /// The rotation of the arc's ellipse. 27 | pub rotation: f32, 28 | /// The start of the segment's angle, clockwise rotation. 29 | pub start_angle: f32, 30 | /// The end of the segment's angle, clockwise rotation. 31 | pub end_angle: f32, 32 | } 33 | 34 | impl From for Elliptical { 35 | fn from(arc: Arc) -> Elliptical { 36 | Elliptical { 37 | center: arc.center, 38 | radii: Vector::new(arc.radius, arc.radius), 39 | rotation: 0.0, 40 | start_angle: arc.start_angle, 41 | end_angle: arc.end_angle, 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/graphs/ecosystem.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | fontname = "Roboto"; 3 | newrank=true; 4 | node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"]; 5 | edge[color="#333333"]; 6 | 7 | subgraph cluster_1 { 8 | label = "renderers "; 9 | labelloc = "b"; 10 | labeljust = "r"; 11 | fontcolor = "#0366d6"; 12 | color="#f6f8fa"; 13 | bgcolor="#f6f8fa"; 14 | style=rounded; 15 | 16 | etc_1 [label="...", style=solid, shape=none]; 17 | iced_wgpu; 18 | } 19 | 20 | subgraph cluster_2 { 21 | label = "shells "; 22 | labelloc = "b"; 23 | labeljust = "r"; 24 | fontcolor = "#0366d6"; 25 | color="#f6f8fa"; 26 | bgcolor="#f6f8fa"; 27 | style=rounded; 28 | 29 | etc_2 [label="...", style=solid, shape=none]; 30 | iced_winit; 31 | } 32 | 33 | subgraph cluster_3 { 34 | style=invis; 35 | margin=20; 36 | iced; 37 | } 38 | 39 | { rank = same; iced_native iced_web } 40 | { rank = same; iced_wgpu iced_winit etc_1 etc_2 } 41 | 42 | iced_core -> iced_native [style=dashed]; 43 | iced_core -> iced_web [style=dashed]; 44 | iced_native -> iced_wgpu; 45 | iced_native -> iced_winit; 46 | 47 | iced_winit -> iced; 48 | iced_wgpu -> iced; 49 | iced_web -> iced; 50 | 51 | iced -> "cross-platform application"; 52 | 53 | iced_core [style=dashed]; 54 | 55 | "cross-platform application" [shape=box, width=2.8, height=0.6]; 56 | } 57 | -------------------------------------------------------------------------------- /winit/src/settings.rs: -------------------------------------------------------------------------------- 1 | //! Configure your application. 2 | #[cfg(target_os = "windows")] 3 | #[path = "settings/windows.rs"] 4 | mod platform; 5 | #[cfg(not(target_os = "windows"))] 6 | #[path = "settings/not_windows.rs"] 7 | mod platform; 8 | 9 | pub use platform::PlatformSpecific; 10 | 11 | /// The settings of an application. 12 | #[derive(Debug, Clone, Copy, PartialEq, Default)] 13 | pub struct Settings { 14 | /// The [`Window`] settings 15 | /// 16 | /// [`Window`]: struct.Window.html 17 | pub window: Window, 18 | 19 | /// The data needed to initialize an [`Application`]. 20 | /// 21 | /// [`Application`]: trait.Application.html 22 | pub flags: Flags, 23 | } 24 | 25 | /// The window settings of an application. 26 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 27 | pub struct Window { 28 | /// The size of the window. 29 | pub size: (u32, u32), 30 | 31 | /// Whether the window should be resizable or not. 32 | pub resizable: bool, 33 | 34 | /// Whether the window should have a border, a title bar, etc. 35 | pub decorations: bool, 36 | 37 | /// Platform specific settings. 38 | pub platform_specific: platform::PlatformSpecific, 39 | } 40 | 41 | impl Default for Window { 42 | fn default() -> Window { 43 | Window { 44 | size: (1024, 768), 45 | resizable: true, 46 | decorations: true, 47 | platform_specific: Default::default(), 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /winit/src/proxy.rs: -------------------------------------------------------------------------------- 1 | use iced_native::futures::{ 2 | channel::mpsc, 3 | task::{Context, Poll}, 4 | Sink, 5 | }; 6 | use std::pin::Pin; 7 | 8 | pub struct Proxy { 9 | raw: winit::event_loop::EventLoopProxy, 10 | } 11 | 12 | impl Clone for Proxy { 13 | fn clone(&self) -> Self { 14 | Self { 15 | raw: self.raw.clone(), 16 | } 17 | } 18 | } 19 | 20 | impl Proxy { 21 | pub fn new(raw: winit::event_loop::EventLoopProxy) -> Self { 22 | Self { raw } 23 | } 24 | } 25 | 26 | impl Sink for Proxy { 27 | type Error = mpsc::SendError; 28 | 29 | fn poll_ready( 30 | self: Pin<&mut Self>, 31 | _cx: &mut Context<'_>, 32 | ) -> Poll> { 33 | Poll::Ready(Ok(())) 34 | } 35 | 36 | fn start_send( 37 | self: Pin<&mut Self>, 38 | message: Message, 39 | ) -> Result<(), Self::Error> { 40 | let _ = self.raw.send_event(message); 41 | 42 | Ok(()) 43 | } 44 | 45 | fn poll_flush( 46 | self: Pin<&mut Self>, 47 | _cx: &mut Context<'_>, 48 | ) -> Poll> { 49 | Poll::Ready(Ok(())) 50 | } 51 | 52 | fn poll_close( 53 | self: Pin<&mut Self>, 54 | _cx: &mut Context<'_>, 55 | ) -> Poll> { 56 | Poll::Ready(Ok(())) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/length.rs: -------------------------------------------------------------------------------- 1 | /// The strategy used to fill space in a specific dimension. 2 | #[derive(Debug, Clone, Copy, PartialEq, Hash)] 3 | pub enum Length { 4 | /// Fill all the remaining space 5 | Fill, 6 | 7 | /// Fill a portion of the remaining space relative to other elements. 8 | /// 9 | /// Let's say we have two elements: one with `FillPortion(2)` and one with 10 | /// `FillPortion(3)`. The first will get 2 portions of the available space, 11 | /// while the second one would get 3. 12 | /// 13 | /// `Length::Fill` is equivalent to `Length::FillPortion(1)`. 14 | FillPortion(u16), 15 | 16 | /// Fill the least amount of space 17 | Shrink, 18 | 19 | /// Fill a fixed amount of space 20 | Units(u16), 21 | } 22 | 23 | impl Length { 24 | /// Returns the _fill factor_ of the [`Length`]. 25 | /// 26 | /// The _fill factor_ is a relative unit describing how much of the 27 | /// remaining space should be filled when compared to other elements. It 28 | /// is only meant to be used by layout engines. 29 | /// 30 | /// [`Length`]: enum.Length.html 31 | pub fn fill_factor(&self) -> u16 { 32 | match self { 33 | Length::Fill => 1, 34 | Length::FillPortion(factor) => *factor, 35 | Length::Shrink => 0, 36 | Length::Units(_) => 0, 37 | } 38 | } 39 | } 40 | 41 | impl From for Length { 42 | fn from(units: u16) -> Self { 43 | Length::Units(units) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /wgpu/src/widget/canvas/text.rs: -------------------------------------------------------------------------------- 1 | use iced_native::{Color, Font, HorizontalAlignment, Point, VerticalAlignment}; 2 | 3 | /// A bunch of text that can be drawn to a canvas 4 | #[derive(Debug, Clone)] 5 | pub struct Text { 6 | /// The contents of the text 7 | pub content: String, 8 | /// The position where to begin drawing the text (top-left corner coordinates) 9 | pub position: Point, 10 | /// The color of the text 11 | pub color: Color, 12 | /// The size of the text 13 | pub size: f32, 14 | /// The font of the text 15 | pub font: Font, 16 | /// The horizontal alignment of the text 17 | pub horizontal_alignment: HorizontalAlignment, 18 | /// The vertical alignment of the text 19 | pub vertical_alignment: VerticalAlignment, 20 | } 21 | 22 | impl Default for Text { 23 | fn default() -> Text { 24 | Text { 25 | content: String::new(), 26 | position: Point::ORIGIN, 27 | color: Color::BLACK, 28 | size: 16.0, 29 | font: Font::Default, 30 | horizontal_alignment: HorizontalAlignment::Left, 31 | vertical_alignment: VerticalAlignment::Top, 32 | } 33 | } 34 | } 35 | 36 | impl From for Text { 37 | fn from(content: String) -> Text { 38 | Text { 39 | content, 40 | ..Default::default() 41 | } 42 | } 43 | } 44 | 45 | impl From<&str> for Text { 46 | fn from(content: &str) -> Text { 47 | String::from(content).into() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /style/src/container.rs: -------------------------------------------------------------------------------- 1 | //! Decorate content and apply alignment. 2 | use iced_core::{Background, Color}; 3 | 4 | /// The appearance of a container. 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Style { 7 | pub text_color: Option, 8 | pub background: Option, 9 | pub border_radius: u16, 10 | pub border_width: u16, 11 | pub border_color: Color, 12 | } 13 | 14 | impl std::default::Default for Style { 15 | fn default() -> Self { 16 | Self { 17 | text_color: None, 18 | background: None, 19 | border_radius: 0, 20 | border_width: 0, 21 | border_color: Color::TRANSPARENT, 22 | } 23 | } 24 | } 25 | 26 | /// A set of rules that dictate the style of a container. 27 | pub trait StyleSheet { 28 | /// Produces the style of a container. 29 | fn style(&self) -> Style; 30 | } 31 | 32 | struct Default; 33 | 34 | impl StyleSheet for Default { 35 | fn style(&self) -> Style { 36 | Style { 37 | text_color: None, 38 | background: None, 39 | border_radius: 0, 40 | border_width: 0, 41 | border_color: Color::TRANSPARENT, 42 | } 43 | } 44 | } 45 | 46 | impl std::default::Default for Box { 47 | fn default() -> Self { 48 | Box::new(Default) 49 | } 50 | } 51 | 52 | impl From for Box 53 | where 54 | T: 'static + StyleSheet, 55 | { 56 | fn from(style: T) -> Self { 57 | Box::new(style) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /core/src/vector.rs: -------------------------------------------------------------------------------- 1 | /// A 2D vector. 2 | #[derive(Debug, Clone, Copy, PartialEq)] 3 | pub struct Vector { 4 | /// The X component of the [`Vector`] 5 | /// 6 | /// [`Vector`]: struct.Vector.html 7 | pub x: T, 8 | 9 | /// The Y component of the [`Vector`] 10 | /// 11 | /// [`Vector`]: struct.Vector.html 12 | pub y: T, 13 | } 14 | 15 | impl Vector { 16 | /// Creates a new [`Vector`] with the given components. 17 | /// 18 | /// [`Vector`]: struct.Vector.html 19 | pub const fn new(x: T, y: T) -> Self { 20 | Self { x, y } 21 | } 22 | } 23 | 24 | impl std::ops::Add for Vector 25 | where 26 | T: std::ops::Add, 27 | { 28 | type Output = Self; 29 | 30 | fn add(self, b: Self) -> Self { 31 | Self::new(self.x + b.x, self.y + b.y) 32 | } 33 | } 34 | 35 | impl std::ops::Sub for Vector 36 | where 37 | T: std::ops::Sub, 38 | { 39 | type Output = Self; 40 | 41 | fn sub(self, b: Self) -> Self { 42 | Self::new(self.x - b.x, self.y - b.y) 43 | } 44 | } 45 | 46 | impl std::ops::Mul for Vector 47 | where 48 | T: std::ops::Mul + Copy, 49 | { 50 | type Output = Self; 51 | 52 | fn mul(self, scale: T) -> Self { 53 | Self::new(self.x * scale, self.y * scale) 54 | } 55 | } 56 | 57 | impl Default for Vector 58 | where 59 | T: Default, 60 | { 61 | fn default() -> Self { 62 | Self { 63 | x: T::default(), 64 | y: T::default(), 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /style/src/checkbox.rs: -------------------------------------------------------------------------------- 1 | //! Show toggle controls using checkboxes. 2 | use iced_core::{Background, Color}; 3 | 4 | /// The appearance of a checkbox. 5 | #[derive(Debug)] 6 | pub struct Style { 7 | pub background: Background, 8 | pub checkmark_color: Color, 9 | pub border_radius: u16, 10 | pub border_width: u16, 11 | pub border_color: Color, 12 | } 13 | 14 | /// A set of rules that dictate the style of a checkbox. 15 | pub trait StyleSheet { 16 | fn active(&self, is_checked: bool) -> Style; 17 | 18 | fn hovered(&self, is_checked: bool) -> Style; 19 | } 20 | 21 | struct Default; 22 | 23 | impl StyleSheet for Default { 24 | fn active(&self, _is_checked: bool) -> Style { 25 | Style { 26 | background: Background::Color(Color::from_rgb(0.95, 0.95, 0.95)), 27 | checkmark_color: Color::from_rgb(0.3, 0.3, 0.3), 28 | border_radius: 5, 29 | border_width: 1, 30 | border_color: Color::from_rgb(0.6, 0.6, 0.6), 31 | } 32 | } 33 | 34 | fn hovered(&self, is_checked: bool) -> Style { 35 | Style { 36 | background: Background::Color(Color::from_rgb(0.90, 0.90, 0.90)), 37 | ..self.active(is_checked) 38 | } 39 | } 40 | } 41 | 42 | impl std::default::Default for Box { 43 | fn default() -> Self { 44 | Box::new(Default) 45 | } 46 | } 47 | 48 | impl From for Box 49 | where 50 | T: 'static + StyleSheet, 51 | { 52 | fn from(style: T) -> Self { 53 | Box::new(style) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/mouse/event.rs: -------------------------------------------------------------------------------- 1 | use super::Button; 2 | 3 | /// A mouse event. 4 | /// 5 | /// _**Note:** This type is largely incomplete! If you need to track 6 | /// additional events, feel free to [open an issue] and share your use case!_ 7 | /// 8 | /// [open an issue]: https://github.com/hecrj/iced/issues 9 | #[derive(Debug, Clone, Copy, PartialEq)] 10 | pub enum Event { 11 | /// The mouse cursor entered the window. 12 | CursorEntered, 13 | 14 | /// The mouse cursor left the window. 15 | CursorLeft, 16 | 17 | /// The mouse cursor was moved 18 | CursorMoved { 19 | /// The X coordinate of the mouse position 20 | x: f32, 21 | 22 | /// The Y coordinate of the mouse position 23 | y: f32, 24 | }, 25 | 26 | /// A mouse button was pressed. 27 | ButtonPressed(Button), 28 | 29 | /// A mouse button was released. 30 | ButtonReleased(Button), 31 | 32 | /// The mouse wheel was scrolled. 33 | WheelScrolled { 34 | /// The scroll movement. 35 | delta: ScrollDelta, 36 | }, 37 | } 38 | 39 | /// A scroll movement. 40 | #[derive(Debug, Clone, Copy, PartialEq)] 41 | pub enum ScrollDelta { 42 | /// A line-based scroll movement 43 | Lines { 44 | /// The number of horizontal lines scrolled 45 | x: f32, 46 | 47 | /// The number of vertical lines scrolled 48 | y: f32, 49 | }, 50 | /// A pixel-based scroll movement 51 | Pixels { 52 | /// The number of horizontal pixels scrolled 53 | x: f32, 54 | /// The number of vertical pixels scrolled 55 | y: f32, 56 | }, 57 | } 58 | -------------------------------------------------------------------------------- /web/src/bus.rs: -------------------------------------------------------------------------------- 1 | use iced_futures::futures::channel::mpsc; 2 | use std::rc::Rc; 3 | 4 | /// A publisher of messages. 5 | /// 6 | /// It can be used to route messages back to the [`Application`]. 7 | /// 8 | /// [`Application`]: trait.Application.html 9 | #[allow(missing_debug_implementations)] 10 | pub struct Bus { 11 | publish: Rc ()>>, 12 | } 13 | 14 | impl Clone for Bus { 15 | fn clone(&self) -> Self { 16 | Bus { 17 | publish: self.publish.clone(), 18 | } 19 | } 20 | } 21 | 22 | impl Bus 23 | where 24 | Message: 'static, 25 | { 26 | pub(crate) fn new(publish: mpsc::UnboundedSender) -> Self { 27 | Self { 28 | publish: Rc::new(Box::new(move |message| { 29 | publish.unbounded_send(message).expect("Send message"); 30 | })), 31 | } 32 | } 33 | 34 | /// Publishes a new message for the [`Application`]. 35 | /// 36 | /// [`Application`]: trait.Application.html 37 | pub fn publish(&self, message: Message) { 38 | (self.publish)(message) 39 | } 40 | 41 | /// Creates a new [`Bus`] that applies the given function to the messages 42 | /// before publishing. 43 | /// 44 | /// [`Bus`]: struct.Bus.html 45 | pub fn map(&self, mapper: Rc Message>>) -> Bus 46 | where 47 | B: 'static, 48 | { 49 | let publish = self.publish.clone(); 50 | 51 | Bus { 52 | publish: Rc::new(Box::new(move |message| publish(mapper(message)))), 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/counter/src/main.rs: -------------------------------------------------------------------------------- 1 | use iced::{button, Align, Button, Column, Element, Sandbox, Settings, Text}; 2 | 3 | pub fn main() { 4 | Counter::run(Settings::default()) 5 | } 6 | 7 | #[derive(Default)] 8 | struct Counter { 9 | value: i32, 10 | increment_button: button::State, 11 | decrement_button: button::State, 12 | } 13 | 14 | #[derive(Debug, Clone, Copy)] 15 | enum Message { 16 | IncrementPressed, 17 | DecrementPressed, 18 | } 19 | 20 | impl Sandbox for Counter { 21 | type Message = Message; 22 | 23 | fn new() -> Self { 24 | Self::default() 25 | } 26 | 27 | fn title(&self) -> String { 28 | String::from("Counter - Iced") 29 | } 30 | 31 | fn update(&mut self, message: Message) { 32 | match message { 33 | Message::IncrementPressed => { 34 | self.value += 1; 35 | } 36 | Message::DecrementPressed => { 37 | self.value -= 1; 38 | } 39 | } 40 | } 41 | 42 | fn view(&mut self) -> Element { 43 | Column::new() 44 | .padding(20) 45 | .align_items(Align::Center) 46 | .push( 47 | Button::new(&mut self.increment_button, Text::new("Increment")) 48 | .on_press(Message::IncrementPressed), 49 | ) 50 | .push(Text::new(self.value.to_string()).size(50)) 51 | .push( 52 | Button::new(&mut self.decrement_button, Text::new("Decrement")) 53 | .on_press(Message::DecrementPressed), 54 | ) 55 | .into() 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /core/src/size.rs: -------------------------------------------------------------------------------- 1 | use std::f32; 2 | 3 | /// An amount of space in 2 dimensions. 4 | #[derive(Debug, Clone, Copy, PartialEq)] 5 | pub struct Size { 6 | /// The width. 7 | pub width: f32, 8 | /// The height. 9 | pub height: f32, 10 | } 11 | 12 | impl Size { 13 | /// A [`Size`] with zero width and height. 14 | /// 15 | /// [`Size`]: struct.Size.html 16 | pub const ZERO: Size = Size::new(0., 0.); 17 | 18 | /// A [`Size`] with a width and height of 1 unit. 19 | /// 20 | /// [`Size`]: struct.Size.html 21 | pub const UNIT: Size = Size::new(1., 1.); 22 | 23 | /// A [`Size`] with infinite width and height. 24 | /// 25 | /// [`Size`]: struct.Size.html 26 | pub const INFINITY: Size = Size::new(f32::INFINITY, f32::INFINITY); 27 | 28 | /// Creates a new [`Size`] with the given width and height. 29 | /// 30 | /// [`Size`]: struct.Size.html 31 | pub const fn new(width: f32, height: f32) -> Self { 32 | Size { width, height } 33 | } 34 | 35 | /// Increments the [`Size`] to account for the given padding. 36 | /// 37 | /// [`Size`]: struct.Size.html 38 | pub fn pad(&self, padding: f32) -> Self { 39 | Size { 40 | width: self.width + padding * 2.0, 41 | height: self.height + padding * 2.0, 42 | } 43 | } 44 | } 45 | 46 | impl From<[f32; 2]> for Size { 47 | fn from([width, height]: [f32; 2]) -> Self { 48 | Size { width, height } 49 | } 50 | } 51 | 52 | impl From<[u16; 2]> for Size { 53 | fn from([width, height]: [u16; 2]) -> Self { 54 | Size::new(width.into(), height.into()) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /wgpu/src/transformation.rs: -------------------------------------------------------------------------------- 1 | use glam::{Mat4, Vec3, Vec4}; 2 | use std::ops::Mul; 3 | 4 | /// A 2D transformation matrix. 5 | #[derive(Debug, Clone, Copy, PartialEq)] 6 | pub struct Transformation(Mat4); 7 | 8 | impl Transformation { 9 | /// Get the identity transformation. 10 | pub fn identity() -> Transformation { 11 | Transformation(Mat4::identity()) 12 | } 13 | 14 | /// Creates an orthographic projection. 15 | #[rustfmt::skip] 16 | pub fn orthographic(width: u32, height: u32) -> Transformation { 17 | Transformation(Mat4::from_cols( 18 | Vec4::new(2.0 / width as f32, 0.0, 0.0, 0.0), 19 | Vec4::new(0.0, -2.0 / height as f32, 0.0, 0.0), 20 | Vec4::new(0.0, 0.0, -1.0, 0.0), 21 | Vec4::new(-1.0, 1.0, 0.0, 1.0) 22 | )) 23 | } 24 | 25 | /// Creates a translate transformation. 26 | pub fn translate(x: f32, y: f32) -> Transformation { 27 | Transformation(Mat4::from_translation(Vec3::new(x, y, 0.0))) 28 | } 29 | 30 | /// Creates a scale transformation. 31 | pub fn scale(x: f32, y: f32) -> Transformation { 32 | Transformation(Mat4::from_scale(Vec3::new(x, y, 1.0))) 33 | } 34 | } 35 | 36 | impl Mul for Transformation { 37 | type Output = Self; 38 | 39 | fn mul(self, rhs: Self) -> Self { 40 | Transformation(self.0 * rhs.0) 41 | } 42 | } 43 | 44 | impl AsRef<[f32; 16]> for Transformation { 45 | fn as_ref(&self) -> &[f32; 16] { 46 | self.0.as_ref() 47 | } 48 | } 49 | 50 | impl From for [f32; 16] { 51 | fn from(t: Transformation) -> [f32; 16] { 52 | *t.as_ref() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /wgpu/src/settings.rs: -------------------------------------------------------------------------------- 1 | //! Configure a [`Renderer`]. 2 | //! 3 | //! [`Renderer`]: struct.Renderer.html 4 | 5 | /// The settings of a [`Renderer`]. 6 | /// 7 | /// [`Renderer`]: ../struct.Renderer.html 8 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 9 | pub struct Settings { 10 | /// The output format of the [`Renderer`]. 11 | /// 12 | /// [`Renderer`]: ../struct.Renderer.html 13 | pub format: wgpu::TextureFormat, 14 | 15 | /// The bytes of the font that will be used by default. 16 | /// 17 | /// If `None` is provided, a default system font will be chosen. 18 | pub default_font: Option<&'static [u8]>, 19 | 20 | /// The antialiasing strategy that will be used for triangle primitives. 21 | pub antialiasing: Option, 22 | } 23 | 24 | impl Default for Settings { 25 | fn default() -> Settings { 26 | Settings { 27 | format: wgpu::TextureFormat::Bgra8UnormSrgb, 28 | default_font: None, 29 | antialiasing: None, 30 | } 31 | } 32 | } 33 | 34 | /// An antialiasing strategy. 35 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 36 | pub enum Antialiasing { 37 | /// Multisample AA with 2 samples 38 | MSAAx2, 39 | /// Multisample AA with 4 samples 40 | MSAAx4, 41 | /// Multisample AA with 8 samples 42 | MSAAx8, 43 | /// Multisample AA with 16 samples 44 | MSAAx16, 45 | } 46 | 47 | impl Antialiasing { 48 | pub(crate) fn sample_count(self) -> u32 { 49 | match self { 50 | Antialiasing::MSAAx2 => 2, 51 | Antialiasing::MSAAx4 => 4, 52 | Antialiasing::MSAAx8 => 8, 53 | Antialiasing::MSAAx16 => 16, 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /winit/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A windowing shell for Iced, on top of [`winit`]. 2 | //! 3 | //! ![`iced_winit` crate graph](https://github.com/hecrj/iced/blob/cae26cb7bc627f4a5b3bcf1cd023a0c552e8c65e/docs/graphs/winit.png?raw=true) 4 | //! 5 | //! `iced_winit` offers some convenient abstractions on top of [`iced_native`] 6 | //! to quickstart development when using [`winit`]. 7 | //! 8 | //! It exposes a renderer-agnostic [`Application`] trait that can be implemented 9 | //! and then run with a simple call. The use of this trait is optional. 10 | //! 11 | //! Additionally, a [`conversion`] module is available for users that decide to 12 | //! implement a custom event loop. 13 | //! 14 | //! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native 15 | //! [`winit`]: https://github.com/rust-windowing/winit 16 | //! [`Application`]: trait.Application.html 17 | //! [`conversion`]: conversion 18 | #![deny(missing_docs)] 19 | #![deny(missing_debug_implementations)] 20 | #![deny(unused_results)] 21 | #![forbid(unsafe_code)] 22 | #![forbid(rust_2018_idioms)] 23 | 24 | #[doc(no_inline)] 25 | pub use iced_native::*; 26 | pub use winit; 27 | 28 | pub mod conversion; 29 | pub mod settings; 30 | 31 | mod application; 32 | mod clipboard; 33 | mod mode; 34 | mod proxy; 35 | mod size; 36 | 37 | // We disable debug capabilities on release builds unless the `debug` feature 38 | // is explicitly enabled. 39 | #[cfg(feature = "debug")] 40 | #[path = "debug/basic.rs"] 41 | mod debug; 42 | #[cfg(not(feature = "debug"))] 43 | #[path = "debug/null.rs"] 44 | mod debug; 45 | 46 | pub use application::Application; 47 | pub use clipboard::Clipboard; 48 | pub use mode::Mode; 49 | pub use settings::Settings; 50 | 51 | use debug::Debug; 52 | use proxy::Proxy; 53 | -------------------------------------------------------------------------------- /native/src/subscription.rs: -------------------------------------------------------------------------------- 1 | //! Listen to external events in your application. 2 | use crate::{Event, Hasher}; 3 | use iced_futures::futures::stream::BoxStream; 4 | 5 | /// A request to listen to external events. 6 | /// 7 | /// Besides performing async actions on demand with [`Command`], most 8 | /// applications also need to listen to external events passively. 9 | /// 10 | /// A [`Subscription`] is normally provided to some runtime, like a [`Command`], 11 | /// and it will generate events as long as the user keeps requesting it. 12 | /// 13 | /// For instance, you can use a [`Subscription`] to listen to a WebSocket 14 | /// connection, keyboard presses, mouse events, time ticks, etc. 15 | /// 16 | /// [`Command`]: ../struct.Command.html 17 | /// [`Subscription`]: struct.Subscription.html 18 | pub type Subscription = iced_futures::Subscription; 19 | 20 | /// A stream of runtime events. 21 | /// 22 | /// It is the input of a [`Subscription`] in the native runtime. 23 | /// 24 | /// [`Subscription`]: type.Subscription.html 25 | pub type EventStream = BoxStream<'static, Event>; 26 | 27 | /// A native [`Subscription`] tracker. 28 | /// 29 | /// [`Subscription`]: type.Subscription.html 30 | pub type Tracker = iced_futures::subscription::Tracker; 31 | 32 | pub use iced_futures::subscription::Recipe; 33 | 34 | mod events; 35 | 36 | use events::Events; 37 | 38 | /// Returns a [`Subscription`] to all the runtime events. 39 | /// 40 | /// This subscription will notify your application of any [`Event`] handled by 41 | /// the runtime. 42 | /// 43 | /// [`Subscription`]: type.Subscription.html 44 | /// [`Event`]: ../enum.Event.html 45 | pub fn events() -> Subscription { 46 | Subscription::from_recipe(Events) 47 | } 48 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget/container.rs: -------------------------------------------------------------------------------- 1 | use crate::{container, defaults, Defaults, Primitive, Renderer}; 2 | use iced_native::{Background, Color, Element, Layout, Point, Rectangle}; 3 | 4 | impl iced_native::container::Renderer for Renderer { 5 | type Style = Box; 6 | 7 | fn draw( 8 | &mut self, 9 | defaults: &Defaults, 10 | bounds: Rectangle, 11 | cursor_position: Point, 12 | style_sheet: &Self::Style, 13 | content: &Element<'_, Message, Self>, 14 | content_layout: Layout<'_>, 15 | ) -> Self::Output { 16 | let style = style_sheet.style(); 17 | 18 | let defaults = Defaults { 19 | text: defaults::Text { 20 | color: style.text_color.unwrap_or(defaults.text.color), 21 | }, 22 | }; 23 | 24 | let (content, mouse_interaction) = 25 | content.draw(self, &defaults, content_layout, cursor_position); 26 | 27 | if style.background.is_some() || style.border_width > 0 { 28 | let quad = Primitive::Quad { 29 | bounds, 30 | background: style 31 | .background 32 | .unwrap_or(Background::Color(Color::TRANSPARENT)), 33 | border_radius: style.border_radius, 34 | border_width: style.border_width, 35 | border_color: style.border_color, 36 | }; 37 | 38 | ( 39 | Primitive::Group { 40 | primitives: vec![quad, content], 41 | }, 42 | mouse_interaction, 43 | ) 44 | } else { 45 | (content, mouse_interaction) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /native/README.md: -------------------------------------------------------------------------------- 1 | # `iced_native` 2 | [![Documentation](https://docs.rs/iced_native/badge.svg)][documentation] 3 | [![Crates.io](https://img.shields.io/crates/v/iced_native.svg)](https://crates.io/crates/iced_native) 4 | [![License](https://img.shields.io/crates/l/iced_native.svg)](https://github.com/hecrj/iced/blob/master/LICENSE) 5 | [![project chat](https://img.shields.io/badge/chat-on_zulip-brightgreen.svg)](https://iced.zulipchat.com) 6 | 7 | `iced_native` takes [`iced_core`] and builds a native runtime on top of it, featuring: 8 | - A custom layout engine, greatly inspired by [`druid`] 9 | - Event handling for all the built-in widgets 10 | - A renderer-agnostic API 11 | 12 | To achieve this, it introduces a bunch of reusable interfaces: 13 | - A `Widget` trait, which is used to implement new widgets: from layout requirements to event and drawing logic. 14 | - A bunch of `Renderer` traits, meant to keep the crate renderer-agnostic. 15 | - A `Windowed` trait, leveraging [`raw-window-handle`], which can be implemented by graphical renderers that target _windows_. Window-based shells (like [`iced_winit`]) can use this trait to stay renderer-agnostic. 16 | 17 | ![iced_native](../docs/graphs/native.png) 18 | 19 | [documentation]: https://docs.rs/iced_native 20 | [`iced_core`]: ../core 21 | [`iced_winit`]: ../winit 22 | [`druid`]: https://github.com/xi-editor/druid 23 | [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle 24 | 25 | ## Installation 26 | Add `iced_native` as a dependency in your `Cargo.toml`: 27 | 28 | ```toml 29 | iced_native = "0.2" 30 | ``` 31 | 32 | __Iced moves fast and the `master` branch can contain breaking changes!__ If 33 | you want to learn about a specific release, check out [the release list]. 34 | 35 | [the release list]: https://github.com/hecrj/iced/releases 36 | -------------------------------------------------------------------------------- /native/src/window/backend.rs: -------------------------------------------------------------------------------- 1 | use crate::mouse; 2 | 3 | use raw_window_handle::HasRawWindowHandle; 4 | 5 | /// A graphics backend that can render to windows. 6 | pub trait Backend: Sized { 7 | /// The settings of the backend. 8 | type Settings: Default; 9 | 10 | /// The iced renderer of the backend. 11 | type Renderer: crate::Renderer; 12 | 13 | /// The surface of the backend. 14 | type Surface; 15 | 16 | /// The swap chain of the backend. 17 | type SwapChain; 18 | 19 | /// Creates a new [`Backend`] and an associated iced renderer. 20 | /// 21 | /// [`Backend`]: trait.Backend.html 22 | fn new(settings: Self::Settings) -> (Self, Self::Renderer); 23 | 24 | /// Crates a new [`Surface`] for the given window. 25 | /// 26 | /// [`Surface`]: #associatedtype.Surface 27 | fn create_surface( 28 | &mut self, 29 | window: &W, 30 | ) -> Self::Surface; 31 | 32 | /// Crates a new [`SwapChain`] for the given [`Surface`]. 33 | /// 34 | /// [`SwapChain`]: #associatedtype.SwapChain 35 | /// [`Surface`]: #associatedtype.Surface 36 | fn create_swap_chain( 37 | &mut self, 38 | surface: &Self::Surface, 39 | width: u32, 40 | height: u32, 41 | ) -> Self::SwapChain; 42 | 43 | /// Draws the output primitives to the next frame of the given [`SwapChain`]. 44 | /// 45 | /// [`SwapChain`]: #associatedtype.SwapChain 46 | /// [`Surface`]: #associatedtype.Surface 47 | fn draw>( 48 | &mut self, 49 | renderer: &mut Self::Renderer, 50 | swap_chain: &mut Self::SwapChain, 51 | output: &::Output, 52 | scale_factor: f64, 53 | overlay: &[T], 54 | ) -> mouse::Interaction; 55 | } 56 | -------------------------------------------------------------------------------- /wgpu/src/window/swap_chain.rs: -------------------------------------------------------------------------------- 1 | use crate::Viewport; 2 | 3 | /// The rendering target of a window. 4 | /// 5 | /// It represents a series of virtual framebuffers with a scale factor. 6 | #[derive(Debug)] 7 | pub struct SwapChain { 8 | raw: wgpu::SwapChain, 9 | viewport: Viewport, 10 | } 11 | 12 | impl SwapChain {} 13 | 14 | impl SwapChain { 15 | /// Creates a new [`SwapChain`] for the given surface. 16 | /// 17 | /// [`SwapChain`]: struct.SwapChain.html 18 | pub fn new( 19 | device: &wgpu::Device, 20 | surface: &wgpu::Surface, 21 | format: wgpu::TextureFormat, 22 | width: u32, 23 | height: u32, 24 | ) -> SwapChain { 25 | SwapChain { 26 | raw: new_swap_chain(surface, format, width, height, device), 27 | viewport: Viewport::new(width, height), 28 | } 29 | } 30 | 31 | /// Returns the next frame of the [`SwapChain`] alongside its [`Viewport`]. 32 | /// 33 | /// [`SwapChain`]: struct.SwapChain.html 34 | /// [`Viewport`]: ../struct.Viewport.html 35 | pub fn next_frame( 36 | &mut self, 37 | ) -> Result<(wgpu::SwapChainOutput, &Viewport), wgpu::TimeOut> { 38 | let viewport = &self.viewport; 39 | 40 | self.raw.get_next_texture().map(|output| (output, viewport)) 41 | } 42 | } 43 | 44 | fn new_swap_chain( 45 | surface: &wgpu::Surface, 46 | format: wgpu::TextureFormat, 47 | width: u32, 48 | height: u32, 49 | device: &wgpu::Device, 50 | ) -> wgpu::SwapChain { 51 | device.create_swap_chain( 52 | &surface, 53 | &wgpu::SwapChainDescriptor { 54 | usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, 55 | format, 56 | width, 57 | height, 58 | present_mode: wgpu::PresentMode::Mailbox, 59 | }, 60 | ) 61 | } 62 | -------------------------------------------------------------------------------- /native/src/widget/pane_grid/axis.rs: -------------------------------------------------------------------------------- 1 | use crate::Rectangle; 2 | 3 | /// A fixed reference line for the measurement of coordinates. 4 | #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] 5 | pub enum Axis { 6 | /// The horizontal axis: — 7 | Horizontal, 8 | /// The vertical axis: | 9 | Vertical, 10 | } 11 | 12 | impl Axis { 13 | pub(super) fn split( 14 | &self, 15 | rectangle: &Rectangle, 16 | ratio: f32, 17 | halved_spacing: f32, 18 | ) -> (Rectangle, Rectangle) { 19 | match self { 20 | Axis::Horizontal => { 21 | let height_top = (rectangle.height * ratio).round(); 22 | let height_bottom = rectangle.height - height_top; 23 | 24 | ( 25 | Rectangle { 26 | height: height_top - halved_spacing, 27 | ..*rectangle 28 | }, 29 | Rectangle { 30 | y: rectangle.y + height_top + halved_spacing, 31 | height: height_bottom - halved_spacing, 32 | ..*rectangle 33 | }, 34 | ) 35 | } 36 | Axis::Vertical => { 37 | let width_left = (rectangle.width * ratio).round(); 38 | let width_right = rectangle.width - width_left; 39 | 40 | ( 41 | Rectangle { 42 | width: width_left - halved_spacing, 43 | ..*rectangle 44 | }, 45 | Rectangle { 46 | x: rectangle.x + width_left + halved_spacing, 47 | width: width_right - halved_spacing, 48 | ..*rectangle 49 | }, 50 | ) 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /futures/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Asynchronous tasks for GUI programming, inspired by Elm. 2 | #![deny(missing_docs)] 3 | #![deny(missing_debug_implementations)] 4 | #![deny(unused_results)] 5 | #![forbid(unsafe_code)] 6 | #![forbid(rust_2018_idioms)] 7 | #![cfg_attr(docsrs, feature(doc_cfg))] 8 | 9 | pub use futures; 10 | 11 | mod command; 12 | mod runtime; 13 | 14 | pub mod executor; 15 | pub mod subscription; 16 | 17 | #[cfg(all( 18 | any(feature = "tokio", feature = "async-std"), 19 | not(target_arch = "wasm32") 20 | ))] 21 | #[cfg_attr(docsrs, doc(cfg(any(feature = "tokio", feature = "async-std"))))] 22 | pub mod time; 23 | 24 | pub use command::Command; 25 | pub use executor::Executor; 26 | pub use runtime::Runtime; 27 | pub use subscription::Subscription; 28 | 29 | /// A boxed static future. 30 | /// 31 | /// - On native platforms, it needs a `Send` requirement. 32 | /// - On the Web platform, it does not need a `Send` requirement. 33 | #[cfg(not(target_arch = "wasm32"))] 34 | pub type BoxFuture = futures::future::BoxFuture<'static, T>; 35 | 36 | /// A boxed static future. 37 | /// 38 | /// - On native platforms, it needs a `Send` requirement. 39 | /// - On the Web platform, it does not need a `Send` requirement. 40 | #[cfg(target_arch = "wasm32")] 41 | pub type BoxFuture = futures::future::LocalBoxFuture<'static, T>; 42 | 43 | /// A boxed static stream. 44 | /// 45 | /// - On native platforms, it needs a `Send` requirement. 46 | /// - On the Web platform, it does not need a `Send` requirement. 47 | #[cfg(not(target_arch = "wasm32"))] 48 | pub type BoxStream = futures::stream::BoxStream<'static, T>; 49 | 50 | /// A boxed static stream. 51 | /// 52 | /// - On native platforms, it needs a `Send` requirement. 53 | /// - On the Web platform, it does not need a `Send` requirement. 54 | #[cfg(target_arch = "wasm32")] 55 | pub type BoxStream = futures::stream::LocalBoxStream<'static, T>; 56 | -------------------------------------------------------------------------------- /core/src/point.rs: -------------------------------------------------------------------------------- 1 | use crate::Vector; 2 | 3 | /// A 2D point. 4 | #[derive(Debug, Clone, Copy, PartialEq, Default)] 5 | pub struct Point { 6 | /// The X coordinate. 7 | pub x: f32, 8 | 9 | /// The Y coordinate. 10 | pub y: f32, 11 | } 12 | 13 | impl Point { 14 | /// The origin (i.e. a [`Point`] at (0, 0)). 15 | /// 16 | /// [`Point`]: struct.Point.html 17 | pub const ORIGIN: Point = Point::new(0.0, 0.0); 18 | 19 | /// Creates a new [`Point`] with the given coordinates. 20 | /// 21 | /// [`Point`]: struct.Point.html 22 | pub const fn new(x: f32, y: f32) -> Self { 23 | Self { x, y } 24 | } 25 | 26 | /// Computes the distance to another [`Point`]. 27 | /// 28 | /// [`Point`]: struct.Point.html 29 | pub fn distance(&self, to: Point) -> f32 { 30 | let a = self.x - to.x; 31 | let b = self.y - to.y; 32 | 33 | a.hypot(b) 34 | } 35 | } 36 | 37 | impl From<[f32; 2]> for Point { 38 | fn from([x, y]: [f32; 2]) -> Self { 39 | Point { x, y } 40 | } 41 | } 42 | 43 | impl From<[u16; 2]> for Point { 44 | fn from([x, y]: [u16; 2]) -> Self { 45 | Point::new(x.into(), y.into()) 46 | } 47 | } 48 | 49 | impl std::ops::Add for Point { 50 | type Output = Self; 51 | 52 | fn add(self, vector: Vector) -> Self { 53 | Self { 54 | x: self.x + vector.x, 55 | y: self.y + vector.y, 56 | } 57 | } 58 | } 59 | 60 | impl std::ops::Sub for Point { 61 | type Output = Self; 62 | 63 | fn sub(self, vector: Vector) -> Self { 64 | Self { 65 | x: self.x - vector.x, 66 | y: self.y - vector.y, 67 | } 68 | } 69 | } 70 | 71 | impl std::ops::Sub for Point { 72 | type Output = Vector; 73 | 74 | fn sub(self, point: Point) -> Vector { 75 | Vector::new(self.x - point.x, self.y - point.y) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget/progress_bar.rs: -------------------------------------------------------------------------------- 1 | use crate::{progress_bar::StyleSheet, Primitive, Renderer}; 2 | use iced_native::{mouse, progress_bar, Color, Rectangle}; 3 | 4 | impl progress_bar::Renderer for Renderer { 5 | type Style = Box; 6 | 7 | const DEFAULT_HEIGHT: u16 = 30; 8 | 9 | fn draw( 10 | &self, 11 | bounds: Rectangle, 12 | range: std::ops::RangeInclusive, 13 | value: f32, 14 | style_sheet: &Self::Style, 15 | ) -> Self::Output { 16 | let style = style_sheet.style(); 17 | 18 | let (range_start, range_end) = range.into_inner(); 19 | let active_progress_width = bounds.width 20 | * ((value - range_start) / (range_end - range_start).max(1.0)); 21 | 22 | let background = Primitive::Group { 23 | primitives: vec![Primitive::Quad { 24 | bounds: Rectangle { ..bounds }, 25 | background: style.background, 26 | border_radius: style.border_radius, 27 | border_width: 0, 28 | border_color: Color::TRANSPARENT, 29 | }], 30 | }; 31 | 32 | ( 33 | if active_progress_width > 0.0 { 34 | let bar = Primitive::Quad { 35 | bounds: Rectangle { 36 | width: active_progress_width, 37 | ..bounds 38 | }, 39 | background: style.bar, 40 | border_radius: style.border_radius, 41 | border_width: 0, 42 | border_color: Color::TRANSPARENT, 43 | }; 44 | 45 | Primitive::Group { 46 | primitives: vec![background, bar], 47 | } 48 | } else { 49 | background 50 | }, 51 | mouse::Interaction::default(), 52 | ) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /web/src/widget/space.rs: -------------------------------------------------------------------------------- 1 | use crate::{css, Bus, Css, Element, Length, Widget}; 2 | use dodrio::bumpalo; 3 | 4 | /// An amount of empty space. 5 | /// 6 | /// It can be useful if you want to fill some space with nothing. 7 | #[derive(Debug)] 8 | pub struct Space { 9 | width: Length, 10 | height: Length, 11 | } 12 | 13 | impl Space { 14 | /// Creates an amount of empty [`Space`] with the given width and height. 15 | /// 16 | /// [`Space`]: struct.Space.html 17 | pub fn new(width: Length, height: Length) -> Self { 18 | Space { width, height } 19 | } 20 | 21 | /// Creates an amount of horizontal [`Space`]. 22 | /// 23 | /// [`Space`]: struct.Space.html 24 | pub fn with_width(width: Length) -> Self { 25 | Space { 26 | width, 27 | height: Length::Shrink, 28 | } 29 | } 30 | 31 | /// Creates an amount of vertical [`Space`]. 32 | /// 33 | /// [`Space`]: struct.Space.html 34 | pub fn with_height(height: Length) -> Self { 35 | Space { 36 | width: Length::Shrink, 37 | height, 38 | } 39 | } 40 | } 41 | 42 | impl<'a, Message> Widget for Space { 43 | fn node<'b>( 44 | &self, 45 | bump: &'b bumpalo::Bump, 46 | _publish: &Bus, 47 | _css: &mut Css<'b>, 48 | ) -> dodrio::Node<'b> { 49 | use dodrio::builder::*; 50 | 51 | let width = css::length(self.width); 52 | let height = css::length(self.height); 53 | 54 | let style = bumpalo::format!( 55 | in bump, 56 | "width: {}; height: {};", 57 | width, 58 | height 59 | ); 60 | 61 | div(bump).attr("style", style.into_bump_str()).finish() 62 | } 63 | } 64 | 65 | impl<'a, Message> From for Element<'a, Message> { 66 | fn from(space: Space) -> Element<'a, Message> { 67 | Element::new(space) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /web/src/widget.rs: -------------------------------------------------------------------------------- 1 | //! Use the built-in widgets or create your own. 2 | //! 3 | //! # Custom widgets 4 | //! If you want to implement a custom widget, you simply need to implement the 5 | //! [`Widget`] trait. You can use the API of the built-in widgets as a guide or 6 | //! source of inspiration. 7 | //! 8 | //! # Re-exports 9 | //! For convenience, the contents of this module are available at the root 10 | //! module. Therefore, you can directly type: 11 | //! 12 | //! ``` 13 | //! use iced_web::{button, Button, Widget}; 14 | //! ``` 15 | //! 16 | //! [`Widget`]: trait.Widget.html 17 | use crate::{Bus, Css}; 18 | use dodrio::bumpalo; 19 | 20 | pub mod button; 21 | pub mod checkbox; 22 | pub mod container; 23 | pub mod image; 24 | pub mod progress_bar; 25 | pub mod radio; 26 | pub mod scrollable; 27 | pub mod slider; 28 | pub mod text_input; 29 | 30 | mod column; 31 | mod row; 32 | mod space; 33 | mod text; 34 | 35 | #[doc(no_inline)] 36 | pub use button::Button; 37 | #[doc(no_inline)] 38 | pub use scrollable::Scrollable; 39 | #[doc(no_inline)] 40 | pub use slider::Slider; 41 | #[doc(no_inline)] 42 | pub use text::Text; 43 | #[doc(no_inline)] 44 | pub use text_input::TextInput; 45 | 46 | pub use checkbox::Checkbox; 47 | pub use column::Column; 48 | pub use container::Container; 49 | pub use image::Image; 50 | pub use progress_bar::ProgressBar; 51 | pub use radio::Radio; 52 | pub use row::Row; 53 | pub use space::Space; 54 | 55 | /// A component that displays information and allows interaction. 56 | /// 57 | /// If you want to build your own widgets, you will need to implement this 58 | /// trait. 59 | /// 60 | /// [`Widget`]: trait.Widget.html 61 | pub trait Widget { 62 | /// Produces a VDOM node for the [`Widget`]. 63 | /// 64 | /// [`Widget`]: trait.Widget.html 65 | fn node<'b>( 66 | &self, 67 | bump: &'b bumpalo::Bump, 68 | _bus: &Bus, 69 | style_sheet: &mut Css<'b>, 70 | ) -> dodrio::Node<'b>; 71 | } 72 | -------------------------------------------------------------------------------- /wgpu/src/image/atlas/allocator.rs: -------------------------------------------------------------------------------- 1 | use guillotiere::{AtlasAllocator, Size}; 2 | 3 | pub struct Allocator { 4 | raw: AtlasAllocator, 5 | allocations: usize, 6 | } 7 | 8 | impl Allocator { 9 | pub fn new(size: u32) -> Allocator { 10 | let raw = AtlasAllocator::new(Size::new(size as i32, size as i32)); 11 | 12 | Allocator { 13 | raw, 14 | allocations: 0, 15 | } 16 | } 17 | 18 | pub fn allocate(&mut self, width: u32, height: u32) -> Option { 19 | let allocation = 20 | self.raw.allocate(Size::new(width as i32, height as i32))?; 21 | 22 | self.allocations += 1; 23 | 24 | Some(Region { allocation }) 25 | } 26 | 27 | pub fn deallocate(&mut self, region: &Region) { 28 | self.raw.deallocate(region.allocation.id); 29 | 30 | self.allocations = self.allocations.saturating_sub(1); 31 | } 32 | 33 | pub fn is_empty(&self) -> bool { 34 | self.allocations == 0 35 | } 36 | } 37 | 38 | pub struct Region { 39 | allocation: guillotiere::Allocation, 40 | } 41 | 42 | impl Region { 43 | pub fn position(&self) -> (u32, u32) { 44 | let rectangle = &self.allocation.rectangle; 45 | 46 | (rectangle.min.x as u32, rectangle.min.y as u32) 47 | } 48 | 49 | pub fn size(&self) -> (u32, u32) { 50 | let size = self.allocation.rectangle.size(); 51 | 52 | (size.width as u32, size.height as u32) 53 | } 54 | } 55 | 56 | impl std::fmt::Debug for Allocator { 57 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 58 | write!(f, "Allocator") 59 | } 60 | } 61 | 62 | impl std::fmt::Debug for Region { 63 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 64 | f.debug_struct("Region") 65 | .field("id", &self.allocation.id) 66 | .field("rectangle", &self.allocation.rectangle) 67 | .finish() 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /native/src/mouse/click.rs: -------------------------------------------------------------------------------- 1 | //! Track mouse clicks. 2 | use crate::Point; 3 | use std::time::Instant; 4 | 5 | /// A mouse click. 6 | #[derive(Debug, Clone, Copy)] 7 | pub struct Click { 8 | kind: Kind, 9 | position: Point, 10 | time: Instant, 11 | } 12 | 13 | /// The kind of mouse click. 14 | #[derive(Debug, Clone, Copy)] 15 | pub enum Kind { 16 | /// A single click 17 | Single, 18 | 19 | /// A double click 20 | Double, 21 | 22 | /// A triple click 23 | Triple, 24 | } 25 | 26 | impl Kind { 27 | fn next(&self) -> Kind { 28 | match self { 29 | Kind::Single => Kind::Double, 30 | Kind::Double => Kind::Triple, 31 | Kind::Triple => Kind::Double, 32 | } 33 | } 34 | } 35 | 36 | impl Click { 37 | /// Creates a new [`Click`] with the given position and previous last 38 | /// [`Click`]. 39 | /// 40 | /// [`Click`]: struct.Click.html 41 | pub fn new(position: Point, previous: Option) -> Click { 42 | let time = Instant::now(); 43 | 44 | let kind = if let Some(previous) = previous { 45 | if previous.is_consecutive(position, time) { 46 | previous.kind.next() 47 | } else { 48 | Kind::Single 49 | } 50 | } else { 51 | Kind::Single 52 | }; 53 | 54 | Click { 55 | kind, 56 | position, 57 | time, 58 | } 59 | } 60 | 61 | /// Returns the [`Kind`] of [`Click`]. 62 | /// 63 | /// [`Kind`]: enum.Kind.html 64 | /// [`Click`]: struct.Click.html 65 | pub fn kind(&self) -> Kind { 66 | self.kind 67 | } 68 | 69 | fn is_consecutive(&self, new_position: Point, time: Instant) -> bool { 70 | self.position == new_position 71 | && time 72 | .checked_duration_since(self.time) 73 | .map(|duration| duration.as_millis() <= 300) 74 | .unwrap_or(false) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /native/src/layout.rs: -------------------------------------------------------------------------------- 1 | //! Position your widgets properly. 2 | mod debugger; 3 | mod limits; 4 | mod node; 5 | 6 | pub mod flex; 7 | 8 | pub use debugger::Debugger; 9 | pub use limits::Limits; 10 | pub use node::Node; 11 | 12 | use crate::{Point, Rectangle, Vector}; 13 | 14 | /// The bounds of a [`Node`] and its children, using absolute coordinates. 15 | /// 16 | /// [`Node`]: struct.Node.html 17 | #[derive(Debug, Clone, Copy)] 18 | pub struct Layout<'a> { 19 | position: Point, 20 | node: &'a Node, 21 | } 22 | 23 | impl<'a> Layout<'a> { 24 | pub(crate) fn new(node: &'a Node) -> Self { 25 | Self::with_offset(Vector::new(0.0, 0.0), node) 26 | } 27 | 28 | pub(crate) fn with_offset(offset: Vector, node: &'a Node) -> Self { 29 | let bounds = node.bounds(); 30 | 31 | Self { 32 | position: Point::new(bounds.x, bounds.y) + offset, 33 | node, 34 | } 35 | } 36 | 37 | /// Gets the bounds of the [`Layout`]. 38 | /// 39 | /// The returned [`Rectangle`] describes the position and size of a 40 | /// [`Node`]. 41 | /// 42 | /// [`Layout`]: struct.Layout.html 43 | /// [`Rectangle`]: struct.Rectangle.html 44 | /// [`Node`]: struct.Node.html 45 | pub fn bounds(&self) -> Rectangle { 46 | let bounds = self.node.bounds(); 47 | 48 | Rectangle { 49 | x: self.position.x, 50 | y: self.position.y, 51 | width: bounds.width, 52 | height: bounds.height, 53 | } 54 | } 55 | 56 | /// Returns an iterator over the [`Layout`] of the children of a [`Node`]. 57 | /// 58 | /// [`Layout`]: struct.Layout.html 59 | /// [`Node`]: struct.Node.html 60 | pub fn children(&'a self) -> impl Iterator> { 61 | self.node.children().iter().map(move |node| { 62 | Layout::with_offset( 63 | Vector::new(self.position.x, self.position.y), 64 | node, 65 | ) 66 | }) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget/text.rs: -------------------------------------------------------------------------------- 1 | use crate::{Primitive, Renderer}; 2 | use iced_native::{ 3 | mouse, text, Color, Font, HorizontalAlignment, Rectangle, Size, 4 | VerticalAlignment, 5 | }; 6 | 7 | use std::f32; 8 | 9 | impl text::Renderer for Renderer { 10 | type Font = Font; 11 | 12 | const DEFAULT_SIZE: u16 = 20; 13 | 14 | fn measure( 15 | &self, 16 | content: &str, 17 | size: u16, 18 | font: Font, 19 | bounds: Size, 20 | ) -> (f32, f32) { 21 | self.text_pipeline 22 | .measure(content, f32::from(size), font, bounds) 23 | } 24 | 25 | fn draw( 26 | &mut self, 27 | defaults: &Self::Defaults, 28 | bounds: Rectangle, 29 | content: &str, 30 | size: u16, 31 | font: Font, 32 | color: Option, 33 | horizontal_alignment: HorizontalAlignment, 34 | vertical_alignment: VerticalAlignment, 35 | ) -> Self::Output { 36 | let x = match horizontal_alignment { 37 | iced_native::HorizontalAlignment::Left => bounds.x, 38 | iced_native::HorizontalAlignment::Center => bounds.center_x(), 39 | iced_native::HorizontalAlignment::Right => bounds.x + bounds.width, 40 | }; 41 | 42 | let y = match vertical_alignment { 43 | iced_native::VerticalAlignment::Top => bounds.y, 44 | iced_native::VerticalAlignment::Center => bounds.center_y(), 45 | iced_native::VerticalAlignment::Bottom => bounds.y + bounds.height, 46 | }; 47 | 48 | ( 49 | Primitive::Text { 50 | content: content.to_string(), 51 | size: f32::from(size), 52 | bounds: Rectangle { x, y, ..bounds }, 53 | color: color.unwrap_or(defaults.text.color), 54 | font, 55 | horizontal_alignment, 56 | vertical_alignment, 57 | }, 58 | mouse::Interaction::default(), 59 | ) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for considering contributing to Iced! Feel free to read [the ecosystem overview] and [the roadmap] to get an idea of the current state of the library. 4 | 5 | The main advice for new contributors is to share your ideas with the community. Introduce yourself over our [Zulip server] or [start a discussion in an issue](https://github.com/hecrj/iced/issues) explaining what you have in mind (do not be afraid of duplicated issues!). If you want to talk directly to me (@hecrj), you can also find me on Discord (`lone_scientist#9554`). 6 | 7 | This is a very important step. It helps to coordinate work, get on the same page, and start building trust. Please, do not skip it! Remember that [Code is the Easy Part] and also [The Hard Parts of Open Source]! 8 | 9 | Provided you get in touch first, all kinds of contributions are welcome! Here are a few interesting ideas: 10 | 11 | - New widgets: toggle, table, grid, color picker, video... 12 | - New renderers: `iced_piet` (already in the works!), `iced_skia`, `iced_raqote`, `iced_pathfinder`... 13 | - New shells: `iced_sdl` could be useful for gamedev! 14 | - Better style generation for `iced_web` 15 | - Optimizations for `iced_wgpu`: tiling, incremental rendering... 16 | - Alternative to [`wgpu_glyph`] for proper (shaped), efficient text rendering 17 | - Time travelling debugger built on top of Iced itself 18 | - Testing library 19 | - Cool website to serve on https://iced.rs 20 | 21 | Besides directly writing code, there are many other different ways you can contribute. To name a few: 22 | 23 | - Writing tutorials or blog posts 24 | - Improving the documentation 25 | - Submitting bug reports and use cases 26 | - Sharing, discussing, researching and exploring new ideas 27 | 28 | [the ecosystem overview]: ECOSYSTEM.md 29 | [the roadmap]: ROADMAP.md 30 | [Zulip server]: https://iced.zulipchat.com/ 31 | [Code is the Easy Part]: https://youtu.be/DSjbTC-hvqQ?t=1138 32 | [The Hard Parts of Open Source]: https://www.youtube.com/watch?v=o_4EX4dPppA 33 | [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph 34 | -------------------------------------------------------------------------------- /wgpu/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A [`wgpu`] renderer for [`iced_native`]. 2 | //! 3 | //! ![`iced_wgpu` crate graph](https://github.com/hecrj/iced/blob/cae26cb7bc627f4a5b3bcf1cd023a0c552e8c65e/docs/graphs/wgpu.png?raw=true) 4 | //! 5 | //! For now, it is the default renderer of [Iced] in native platforms. 6 | //! 7 | //! [`wgpu`] supports most modern graphics backends: Vulkan, Metal, DX11, and 8 | //! DX12 (OpenGL and WebGL are still WIP). Additionally, it will support the 9 | //! incoming [WebGPU API]. 10 | //! 11 | //! Currently, `iced_wgpu` supports the following primitives: 12 | //! - Text, which is rendered using [`wgpu_glyph`]. No shaping at all. 13 | //! - Quads or rectangles, with rounded borders and a solid background color. 14 | //! - Clip areas, useful to implement scrollables or hide overflowing content. 15 | //! - Images and SVG, loaded from memory or the file system. 16 | //! - Meshes of triangles, useful to draw geometry freely. 17 | //! 18 | //! [Iced]: https://github.com/hecrj/iced 19 | //! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native 20 | //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs 21 | //! [WebGPU API]: https://gpuweb.github.io/gpuweb/ 22 | //! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph 23 | #![deny(missing_docs)] 24 | #![deny(missing_debug_implementations)] 25 | #![deny(unused_results)] 26 | #![forbid(unsafe_code)] 27 | #![forbid(rust_2018_idioms)] 28 | #![cfg_attr(docsrs, feature(doc_cfg))] 29 | 30 | pub mod defaults; 31 | pub mod settings; 32 | pub mod triangle; 33 | pub mod widget; 34 | pub mod window; 35 | 36 | mod primitive; 37 | mod quad; 38 | mod renderer; 39 | mod target; 40 | mod text; 41 | mod transformation; 42 | mod viewport; 43 | 44 | pub use wgpu; 45 | 46 | pub use defaults::Defaults; 47 | pub use primitive::Primitive; 48 | pub use renderer::Renderer; 49 | pub use settings::Settings; 50 | pub use target::Target; 51 | pub use viewport::Viewport; 52 | 53 | #[doc(no_inline)] 54 | pub use widget::*; 55 | 56 | pub(crate) use quad::Quad; 57 | pub(crate) use transformation::Transformation; 58 | 59 | #[cfg(any(feature = "image", feature = "svg"))] 60 | mod image; 61 | -------------------------------------------------------------------------------- /futures/src/executor.rs: -------------------------------------------------------------------------------- 1 | //! Choose your preferred executor to power a runtime. 2 | mod null; 3 | 4 | #[cfg(all(not(target_arch = "wasm32"), feature = "thread-pool"))] 5 | mod thread_pool; 6 | 7 | #[cfg(all(not(target_arch = "wasm32"), feature = "tokio"))] 8 | mod tokio; 9 | 10 | #[cfg(all(not(target_arch = "wasm32"), feature = "async-std"))] 11 | mod async_std; 12 | 13 | #[cfg(target_arch = "wasm32")] 14 | mod wasm_bindgen; 15 | 16 | pub use null::Null; 17 | 18 | #[cfg(all(not(target_arch = "wasm32"), feature = "thread-pool"))] 19 | pub use thread_pool::ThreadPool; 20 | 21 | #[cfg(all(not(target_arch = "wasm32"), feature = "tokio"))] 22 | pub use self::tokio::Tokio; 23 | 24 | #[cfg(all(not(target_arch = "wasm32"), feature = "async-std"))] 25 | pub use self::async_std::AsyncStd; 26 | 27 | #[cfg(target_arch = "wasm32")] 28 | pub use wasm_bindgen::WasmBindgen; 29 | 30 | use futures::Future; 31 | 32 | /// A type that can run futures. 33 | pub trait Executor: Sized { 34 | /// Creates a new [`Executor`]. 35 | /// 36 | /// [`Executor`]: trait.Executor.html 37 | fn new() -> Result 38 | where 39 | Self: Sized; 40 | 41 | /// Spawns a future in the [`Executor`]. 42 | /// 43 | /// [`Executor`]: trait.Executor.html 44 | #[cfg(not(target_arch = "wasm32"))] 45 | fn spawn(&self, future: impl Future + Send + 'static); 46 | 47 | /// Spawns a local future in the [`Executor`]. 48 | /// 49 | /// [`Executor`]: trait.Executor.html 50 | #[cfg(target_arch = "wasm32")] 51 | fn spawn(&self, future: impl Future + 'static); 52 | 53 | /// Runs the given closure inside the [`Executor`]. 54 | /// 55 | /// Some executors, like `tokio`, require some global state to be in place 56 | /// before creating futures. This method can be leveraged to set up this 57 | /// global state, call a function, restore the state, and obtain the result 58 | /// of the call. 59 | /// 60 | /// [`Executor`]: trait.Executor.html 61 | fn enter(&self, f: impl FnOnce() -> R) -> R { 62 | f() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /wgpu/src/shader/quad.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec4 v_Color; 4 | layout(location = 1) in vec4 v_BorderColor; 5 | layout(location = 2) in vec2 v_Pos; 6 | layout(location = 3) in vec2 v_Scale; 7 | layout(location = 4) in float v_BorderRadius; 8 | layout(location = 5) in float v_BorderWidth; 9 | 10 | layout(location = 0) out vec4 o_Color; 11 | 12 | float distance(in vec2 frag_coord, in vec2 position, in vec2 size, float radius) 13 | { 14 | // TODO: Try SDF approach: https://www.shadertoy.com/view/wd3XRN 15 | vec2 inner_size = size - vec2(radius, radius) * 2.0; 16 | vec2 top_left = position + vec2(radius, radius); 17 | vec2 bottom_right = top_left + inner_size; 18 | 19 | vec2 top_left_distance = top_left - frag_coord; 20 | vec2 bottom_right_distance = frag_coord - bottom_right; 21 | 22 | vec2 distance = vec2( 23 | max(max(top_left_distance.x, bottom_right_distance.x), 0), 24 | max(max(top_left_distance.y, bottom_right_distance.y), 0) 25 | ); 26 | 27 | return sqrt(distance.x * distance.x + distance.y * distance.y); 28 | } 29 | 30 | void main() { 31 | vec4 mixed_color; 32 | 33 | // TODO: Remove branching (?) 34 | if(v_BorderWidth > 0) { 35 | float internal_border = max(v_BorderRadius - v_BorderWidth, 0); 36 | 37 | float internal_distance = distance( 38 | gl_FragCoord.xy, 39 | v_Pos + vec2(v_BorderWidth), 40 | v_Scale - vec2(v_BorderWidth * 2.0), 41 | internal_border 42 | ); 43 | 44 | float border_mix = smoothstep( 45 | max(internal_border - 0.5, 0.0), 46 | internal_border + 0.5, 47 | internal_distance 48 | ); 49 | 50 | mixed_color = mix(v_Color, v_BorderColor, border_mix); 51 | } else { 52 | mixed_color = v_Color; 53 | } 54 | 55 | float d = distance( 56 | gl_FragCoord.xy, 57 | v_Pos, 58 | v_Scale, 59 | v_BorderRadius 60 | ); 61 | 62 | float radius_alpha = 63 | 1.0 - smoothstep(max(v_BorderRadius - 0.5, 0), v_BorderRadius + 0.5, d); 64 | 65 | o_Color = vec4(mixed_color.xyz, mixed_color.w * radius_alpha); 66 | } 67 | -------------------------------------------------------------------------------- /style/src/scrollable.rs: -------------------------------------------------------------------------------- 1 | //! Navigate an endless amount of content with a scrollbar. 2 | use iced_core::{Background, Color}; 3 | 4 | /// The appearance of a scrollable. 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Scrollbar { 7 | pub background: Option, 8 | pub border_radius: u16, 9 | pub border_width: u16, 10 | pub border_color: Color, 11 | pub scroller: Scroller, 12 | } 13 | 14 | /// The appearance of the scroller of a scrollable. 15 | #[derive(Debug, Clone, Copy)] 16 | pub struct Scroller { 17 | pub color: Color, 18 | pub border_radius: u16, 19 | pub border_width: u16, 20 | pub border_color: Color, 21 | } 22 | 23 | /// A set of rules that dictate the style of a scrollable. 24 | pub trait StyleSheet { 25 | /// Produces the style of an active scrollbar. 26 | fn active(&self) -> Scrollbar; 27 | 28 | /// Produces the style of an hovered scrollbar. 29 | fn hovered(&self) -> Scrollbar; 30 | 31 | /// Produces the style of a scrollbar that is being dragged. 32 | fn dragging(&self) -> Scrollbar { 33 | self.hovered() 34 | } 35 | } 36 | 37 | struct Default; 38 | 39 | impl StyleSheet for Default { 40 | fn active(&self) -> Scrollbar { 41 | Scrollbar { 42 | background: None, 43 | border_radius: 5, 44 | border_width: 0, 45 | border_color: Color::TRANSPARENT, 46 | scroller: Scroller { 47 | color: [0.0, 0.0, 0.0, 0.7].into(), 48 | border_radius: 5, 49 | border_width: 0, 50 | border_color: Color::TRANSPARENT, 51 | }, 52 | } 53 | } 54 | 55 | fn hovered(&self) -> Scrollbar { 56 | Scrollbar { 57 | background: Some(Background::Color([0.0, 0.0, 0.0, 0.3].into())), 58 | ..self.active() 59 | } 60 | } 61 | } 62 | 63 | impl std::default::Default for Box { 64 | fn default() -> Self { 65 | Box::new(Default) 66 | } 67 | } 68 | 69 | impl From for Box 70 | where 71 | T: 'static + StyleSheet, 72 | { 73 | fn from(style: T) -> Self { 74 | Box::new(style) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /futures/src/time.rs: -------------------------------------------------------------------------------- 1 | //! Listen and react to time. 2 | use crate::subscription::{self, Subscription}; 3 | 4 | /// Returns a [`Subscription`] that produces messages at a set interval. 5 | /// 6 | /// The first message is produced after a `duration`, and then continues to 7 | /// produce more messages every `duration` after that. 8 | /// 9 | /// [`Subscription`]: ../subscription/struct.Subscription.html 10 | pub fn every( 11 | duration: std::time::Duration, 12 | ) -> Subscription { 13 | Subscription::from_recipe(Every(duration)) 14 | } 15 | 16 | struct Every(std::time::Duration); 17 | 18 | #[cfg(feature = "async-std")] 19 | impl subscription::Recipe for Every 20 | where 21 | H: std::hash::Hasher, 22 | { 23 | type Output = std::time::Instant; 24 | 25 | fn hash(&self, state: &mut H) { 26 | use std::hash::Hash; 27 | 28 | std::any::TypeId::of::().hash(state); 29 | self.0.hash(state); 30 | } 31 | 32 | fn stream( 33 | self: Box, 34 | _input: futures::stream::BoxStream<'static, E>, 35 | ) -> futures::stream::BoxStream<'static, Self::Output> { 36 | use futures::stream::StreamExt; 37 | 38 | async_std::stream::interval(self.0) 39 | .map(|_| std::time::Instant::now()) 40 | .boxed() 41 | } 42 | } 43 | 44 | #[cfg(all(feature = "tokio", not(feature = "async-std")))] 45 | impl subscription::Recipe for Every 46 | where 47 | H: std::hash::Hasher, 48 | { 49 | type Output = std::time::Instant; 50 | 51 | fn hash(&self, state: &mut H) { 52 | use std::hash::Hash; 53 | 54 | std::any::TypeId::of::().hash(state); 55 | self.0.hash(state); 56 | } 57 | 58 | fn stream( 59 | self: Box, 60 | _input: futures::stream::BoxStream<'static, E>, 61 | ) -> futures::stream::BoxStream<'static, Self::Output> { 62 | use futures::stream::StreamExt; 63 | 64 | let start = tokio::time::Instant::now() + self.0; 65 | 66 | tokio::time::interval_at(start, self.0) 67 | .map(|_| std::time::Instant::now()) 68 | .boxed() 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget/radio.rs: -------------------------------------------------------------------------------- 1 | use crate::{radio::StyleSheet, Primitive, Renderer}; 2 | use iced_native::{mouse, radio, Background, Color, Rectangle}; 3 | 4 | const SIZE: f32 = 28.0; 5 | const DOT_SIZE: f32 = SIZE / 2.0; 6 | 7 | impl radio::Renderer for Renderer { 8 | type Style = Box; 9 | 10 | fn default_size(&self) -> u32 { 11 | SIZE as u32 12 | } 13 | 14 | fn draw( 15 | &mut self, 16 | bounds: Rectangle, 17 | is_selected: bool, 18 | is_mouse_over: bool, 19 | (label, _): Self::Output, 20 | style_sheet: &Self::Style, 21 | ) -> Self::Output { 22 | let style = if is_mouse_over { 23 | style_sheet.hovered() 24 | } else { 25 | style_sheet.active() 26 | }; 27 | 28 | let radio = Primitive::Quad { 29 | bounds, 30 | background: style.background, 31 | border_radius: (SIZE / 2.0) as u16, 32 | border_width: style.border_width, 33 | border_color: style.border_color, 34 | }; 35 | 36 | ( 37 | Primitive::Group { 38 | primitives: if is_selected { 39 | let radio_circle = Primitive::Quad { 40 | bounds: Rectangle { 41 | x: bounds.x + DOT_SIZE / 2.0, 42 | y: bounds.y + DOT_SIZE / 2.0, 43 | width: bounds.width - DOT_SIZE, 44 | height: bounds.height - DOT_SIZE, 45 | }, 46 | background: Background::Color(style.dot_color), 47 | border_radius: (DOT_SIZE / 2.0) as u16, 48 | border_width: 0, 49 | border_color: Color::TRANSPARENT, 50 | }; 51 | 52 | vec![radio, radio_circle, label] 53 | } else { 54 | vec![radio, label] 55 | }, 56 | }, 57 | if is_mouse_over { 58 | mouse::Interaction::Pointer 59 | } else { 60 | mouse::Interaction::default() 61 | }, 62 | ) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /wgpu/src/renderer/widget/checkbox.rs: -------------------------------------------------------------------------------- 1 | use crate::{checkbox::StyleSheet, Primitive, Renderer}; 2 | use iced_native::{ 3 | checkbox, mouse, HorizontalAlignment, Rectangle, VerticalAlignment, 4 | }; 5 | 6 | impl checkbox::Renderer for Renderer { 7 | type Style = Box; 8 | 9 | const DEFAULT_SIZE: u16 = 20; 10 | const DEFAULT_SPACING: u16 = 15; 11 | 12 | fn draw( 13 | &mut self, 14 | bounds: Rectangle, 15 | is_checked: bool, 16 | is_mouse_over: bool, 17 | (label, _): Self::Output, 18 | style_sheet: &Self::Style, 19 | ) -> Self::Output { 20 | let style = if is_mouse_over { 21 | style_sheet.hovered(is_checked) 22 | } else { 23 | style_sheet.active(is_checked) 24 | }; 25 | 26 | let checkbox = Primitive::Quad { 27 | bounds, 28 | background: style.background, 29 | border_radius: style.border_radius, 30 | border_width: style.border_width, 31 | border_color: style.border_color, 32 | }; 33 | 34 | ( 35 | Primitive::Group { 36 | primitives: if is_checked { 37 | let check = Primitive::Text { 38 | content: crate::text::CHECKMARK_ICON.to_string(), 39 | font: crate::text::BUILTIN_ICONS, 40 | size: bounds.height * 0.7, 41 | bounds: Rectangle { 42 | x: bounds.center_x(), 43 | y: bounds.center_y(), 44 | ..bounds 45 | }, 46 | color: style.checkmark_color, 47 | horizontal_alignment: HorizontalAlignment::Center, 48 | vertical_alignment: VerticalAlignment::Center, 49 | }; 50 | 51 | vec![checkbox, check, label] 52 | } else { 53 | vec![checkbox, label] 54 | }, 55 | }, 56 | if is_mouse_over { 57 | mouse::Interaction::Pointer 58 | } else { 59 | mouse::Interaction::default() 60 | }, 61 | ) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /native/src/renderer.rs: -------------------------------------------------------------------------------- 1 | //! Write your own renderer. 2 | //! 3 | //! You will need to implement the `Renderer` trait first. It simply contains 4 | //! an `Output` associated type. 5 | //! 6 | //! There is no common trait to draw all the widgets. Instead, every [`Widget`] 7 | //! constrains its generic `Renderer` type as necessary. 8 | //! 9 | //! This approach is flexible and composable. For instance, the 10 | //! [`Text`] widget only needs a [`text::Renderer`] while a [`Checkbox`] widget 11 | //! needs both a [`text::Renderer`] and a [`checkbox::Renderer`], reusing logic. 12 | //! 13 | //! In the end, a __renderer__ satisfying all the constraints is 14 | //! needed to build a [`UserInterface`]. 15 | //! 16 | //! [`Widget`]: ../widget/trait.Widget.html 17 | //! [`UserInterface`]: ../struct.UserInterface.html 18 | //! [`Text`]: ../widget/text/struct.Text.html 19 | //! [`text::Renderer`]: ../widget/text/trait.Renderer.html 20 | //! [`Checkbox`]: ../widget/checkbox/struct.Checkbox.html 21 | //! [`checkbox::Renderer`]: ../widget/checkbox/trait.Renderer.html 22 | 23 | #[cfg(debug_assertions)] 24 | mod null; 25 | #[cfg(debug_assertions)] 26 | pub use null::Null; 27 | 28 | use crate::{layout, Element}; 29 | 30 | /// A component that can take the state of a user interface and produce an 31 | /// output for its users. 32 | pub trait Renderer: Sized { 33 | /// The type of output of the [`Renderer`]. 34 | /// 35 | /// If you are implementing a graphical renderer, your output will most 36 | /// likely be a tree of visual primitives. 37 | /// 38 | /// [`Renderer`]: trait.Renderer.html 39 | type Output; 40 | 41 | /// The default styling attributes of the [`Renderer`]. 42 | /// 43 | /// This type can be leveraged to implement style inheritance. 44 | /// 45 | /// [`Renderer`]: trait.Renderer.html 46 | type Defaults: Default; 47 | 48 | /// Lays out the elements of a user interface. 49 | /// 50 | /// You should override this if you need to perform any operations before or 51 | /// after layouting. For instance, trimming the measurements cache. 52 | fn layout<'a, Message>( 53 | &mut self, 54 | element: &Element<'a, Message, Self>, 55 | limits: &layout::Limits, 56 | ) -> layout::Node { 57 | element.layout(self, limits) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /wgpu/src/widget/canvas/path.rs: -------------------------------------------------------------------------------- 1 | //! Build different kinds of 2D shapes. 2 | pub mod arc; 3 | 4 | mod builder; 5 | 6 | #[doc(no_inline)] 7 | pub use arc::Arc; 8 | pub use builder::Builder; 9 | 10 | use iced_native::{Point, Size}; 11 | 12 | /// An immutable set of points that may or may not be connected. 13 | /// 14 | /// A single [`Path`] can represent different kinds of 2D shapes! 15 | /// 16 | /// [`Path`]: struct.Path.html 17 | #[derive(Debug, Clone)] 18 | pub struct Path { 19 | raw: lyon::path::Path, 20 | } 21 | 22 | impl Path { 23 | /// Creates a new [`Path`] with the provided closure. 24 | /// 25 | /// Use the [`Builder`] to configure your [`Path`]. 26 | /// 27 | /// [`Path`]: struct.Path.html 28 | /// [`Builder`]: struct.Builder.html 29 | pub fn new(f: impl FnOnce(&mut Builder)) -> Self { 30 | let mut builder = Builder::new(); 31 | 32 | // TODO: Make it pure instead of side-effect-based (?) 33 | f(&mut builder); 34 | 35 | builder.build() 36 | } 37 | 38 | /// Creates a new [`Path`] representing a line segment given its starting 39 | /// and end points. 40 | /// 41 | /// [`Path`]: struct.Path.html 42 | pub fn line(from: Point, to: Point) -> Self { 43 | Self::new(|p| { 44 | p.move_to(from); 45 | p.line_to(to); 46 | }) 47 | } 48 | 49 | /// Creates a new [`Path`] representing a rectangle given its top-left 50 | /// corner coordinate and its `Size`. 51 | /// 52 | /// [`Path`]: struct.Path.html 53 | pub fn rectangle(top_left: Point, size: Size) -> Self { 54 | Self::new(|p| p.rectangle(top_left, size)) 55 | } 56 | 57 | /// Creates a new [`Path`] representing a circle given its center 58 | /// coordinate and its radius. 59 | /// 60 | /// [`Path`]: struct.Path.html 61 | pub fn circle(center: Point, radius: f32) -> Self { 62 | Self::new(|p| p.circle(center, radius)) 63 | } 64 | 65 | #[inline] 66 | pub(crate) fn raw(&self) -> &lyon::path::Path { 67 | &self.raw 68 | } 69 | 70 | #[inline] 71 | pub(crate) fn transformed( 72 | &self, 73 | transform: &lyon::math::Transform, 74 | ) -> Path { 75 | Path { 76 | raw: self.raw.transformed(transform), 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iced" 3 | version = "0.1.1" 4 | authors = ["Héctor Ramón Jiménez "] 5 | edition = "2018" 6 | description = "A cross-platform GUI library inspired by Elm" 7 | license = "MIT" 8 | repository = "https://github.com/hecrj/iced" 9 | documentation = "https://docs.rs/iced" 10 | readme = "README.md" 11 | keywords = ["gui", "ui", "graphics", "interface", "widgets"] 12 | categories = ["gui"] 13 | 14 | [features] 15 | # Enables the `Image` widget 16 | image = ["iced_wgpu/image"] 17 | # Enables the `Svg` widget 18 | svg = ["iced_wgpu/svg"] 19 | # Enables the `Canvas` widget 20 | canvas = ["iced_wgpu/canvas"] 21 | # Enables a debug view in native platforms (press F12) 22 | debug = ["iced_winit/debug"] 23 | # Enables `tokio` as the `executor::Default` on native platforms 24 | tokio = ["iced_futures/tokio"] 25 | # Enables `async-std` as the `executor::Default` on native platforms 26 | async-std = ["iced_futures/async-std"] 27 | # Enables advanced color conversion via `palette` 28 | palette = ["iced_core/palette"] 29 | 30 | [badges] 31 | maintenance = { status = "actively-developed" } 32 | 33 | [workspace] 34 | members = [ 35 | "core", 36 | "futures", 37 | "native", 38 | "style", 39 | "web", 40 | "wgpu", 41 | "winit", 42 | "examples/bezier_tool", 43 | "examples/clock", 44 | "examples/color_palette", 45 | "examples/counter", 46 | "examples/custom_widget", 47 | "examples/download_progress", 48 | "examples/events", 49 | "examples/game_of_life", 50 | "examples/geometry", 51 | "examples/integration", 52 | "examples/pane_grid", 53 | "examples/pokedex", 54 | "examples/progress_bar", 55 | "examples/solar_system", 56 | "examples/stopwatch", 57 | "examples/styling", 58 | "examples/svg", 59 | "examples/todos", 60 | "examples/tour", 61 | ] 62 | 63 | [dependencies] 64 | iced_core = { version = "0.2", path = "core" } 65 | iced_futures = { version = "0.1", path = "futures" } 66 | 67 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 68 | iced_winit = { version = "0.1", path = "winit" } 69 | iced_wgpu = { version = "0.2", path = "wgpu" } 70 | 71 | [target.'cfg(target_arch = "wasm32")'.dependencies] 72 | iced_web = { version = "0.2", path = "web" } 73 | 74 | [package.metadata.docs.rs] 75 | rustdoc-args = ["--cfg", "docsrs"] 76 | features = ["image", "svg", "canvas"] 77 | -------------------------------------------------------------------------------- /native/src/widget/text_input/editor.rs: -------------------------------------------------------------------------------- 1 | use crate::text_input::{Cursor, Value}; 2 | 3 | pub struct Editor<'a> { 4 | value: &'a mut Value, 5 | cursor: &'a mut Cursor, 6 | } 7 | 8 | impl<'a> Editor<'a> { 9 | pub fn new(value: &'a mut Value, cursor: &'a mut Cursor) -> Editor<'a> { 10 | Editor { value, cursor } 11 | } 12 | 13 | pub fn contents(&self) -> String { 14 | self.value.to_string() 15 | } 16 | 17 | pub fn insert(&mut self, character: char) { 18 | match self.cursor.selection() { 19 | Some((left, right)) => { 20 | self.cursor.move_left(self.value); 21 | self.value.remove_many(left, right); 22 | } 23 | _ => (), 24 | } 25 | 26 | self.value.insert(self.cursor.end(self.value), character); 27 | self.cursor.move_right(self.value); 28 | } 29 | 30 | pub fn paste(&mut self, content: Value) { 31 | let length = content.len(); 32 | 33 | match self.cursor.selection() { 34 | Some((left, right)) => { 35 | self.cursor.move_left(self.value); 36 | self.value.remove_many(left, right); 37 | } 38 | _ => (), 39 | } 40 | 41 | self.value.insert_many(self.cursor.end(self.value), content); 42 | 43 | self.cursor.move_right_by_amount(self.value, length); 44 | } 45 | 46 | pub fn backspace(&mut self) { 47 | match self.cursor.selection() { 48 | Some((start, end)) => { 49 | self.cursor.move_left(self.value); 50 | self.value.remove_many(start, end); 51 | } 52 | None => { 53 | let start = self.cursor.start(self.value); 54 | 55 | if start > 0 { 56 | self.cursor.move_left(self.value); 57 | self.value.remove(start - 1); 58 | } 59 | } 60 | } 61 | } 62 | 63 | pub fn delete(&mut self) { 64 | match self.cursor.selection() { 65 | Some(_) => { 66 | self.backspace(); 67 | } 68 | None => { 69 | let end = self.cursor.end(self.value); 70 | 71 | if end < self.value.len() { 72 | self.value.remove(end); 73 | } 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /style/src/text_input.rs: -------------------------------------------------------------------------------- 1 | //! Display fields that can be filled with text. 2 | use iced_core::{Background, Color}; 3 | 4 | /// The appearance of a text input. 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Style { 7 | pub background: Background, 8 | pub border_radius: u16, 9 | pub border_width: u16, 10 | pub border_color: Color, 11 | } 12 | 13 | impl std::default::Default for Style { 14 | fn default() -> Self { 15 | Self { 16 | background: Background::Color(Color::WHITE), 17 | border_radius: 0, 18 | border_width: 0, 19 | border_color: Color::TRANSPARENT, 20 | } 21 | } 22 | } 23 | 24 | /// A set of rules that dictate the style of a text input. 25 | pub trait StyleSheet { 26 | /// Produces the style of an active text input. 27 | fn active(&self) -> Style; 28 | 29 | /// Produces the style of a focused text input. 30 | fn focused(&self) -> Style; 31 | 32 | fn placeholder_color(&self) -> Color; 33 | 34 | fn value_color(&self) -> Color; 35 | 36 | fn selection_color(&self) -> Color; 37 | 38 | /// Produces the style of an hovered text input. 39 | fn hovered(&self) -> Style { 40 | self.focused() 41 | } 42 | } 43 | 44 | struct Default; 45 | 46 | impl StyleSheet for Default { 47 | fn active(&self) -> Style { 48 | Style { 49 | background: Background::Color(Color::WHITE), 50 | border_radius: 5, 51 | border_width: 1, 52 | border_color: Color::from_rgb(0.7, 0.7, 0.7), 53 | } 54 | } 55 | 56 | fn focused(&self) -> Style { 57 | Style { 58 | border_color: Color::from_rgb(0.5, 0.5, 0.5), 59 | ..self.active() 60 | } 61 | } 62 | 63 | fn placeholder_color(&self) -> Color { 64 | Color::from_rgb(0.7, 0.7, 0.7) 65 | } 66 | 67 | fn value_color(&self) -> Color { 68 | Color::from_rgb(0.3, 0.3, 0.3) 69 | } 70 | 71 | fn selection_color(&self) -> Color { 72 | Color::from_rgb(0.8, 0.8, 1.0) 73 | } 74 | } 75 | 76 | impl std::default::Default for Box { 77 | fn default() -> Self { 78 | Box::new(Default) 79 | } 80 | } 81 | 82 | impl From for Box 83 | where 84 | T: 'static + StyleSheet, 85 | { 86 | fn from(style: T) -> Self { 87 | Box::new(style) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /wgpu/README.md: -------------------------------------------------------------------------------- 1 | # `iced_wgpu` 2 | [![Documentation](https://docs.rs/iced_wgpu/badge.svg)][documentation] 3 | [![Crates.io](https://img.shields.io/crates/v/iced_wgpu.svg)](https://crates.io/crates/iced_wgpu) 4 | [![License](https://img.shields.io/crates/l/iced_wgpu.svg)](https://github.com/hecrj/iced/blob/master/LICENSE) 5 | [![project chat](https://img.shields.io/badge/chat-on_zulip-brightgreen.svg)](https://iced.zulipchat.com) 6 | 7 | `iced_wgpu` is a [`wgpu`] renderer for [`iced_native`]. For now, it is the default renderer of Iced in native platforms. 8 | 9 | [`wgpu`] supports most modern graphics backends: Vulkan, Metal, DX11, and DX12 (OpenGL and WebGL are still WIP). Additionally, it will support the incoming [WebGPU API]. 10 | 11 | Currently, `iced_wgpu` supports the following primitives: 12 | - Text, which is rendered using [`wgpu_glyph`]. No shaping at all. 13 | - Quads or rectangles, with rounded borders and a solid background color. 14 | - Clip areas, useful to implement scrollables or hide overflowing content. 15 | - Images and SVG, loaded from memory or the file system. 16 | - Meshes of triangles, useful to draw geometry freely. 17 | 18 | ![iced_wgpu](../docs/graphs/wgpu.png) 19 | 20 | [documentation]: https://docs.rs/iced_wgpu 21 | [`iced_native`]: ../native 22 | [`wgpu`]: https://github.com/gfx-rs/wgpu-rs 23 | [WebGPU API]: https://gpuweb.github.io/gpuweb/ 24 | [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph 25 | 26 | ## Installation 27 | Add `iced_wgpu` as a dependency in your `Cargo.toml`: 28 | 29 | ```toml 30 | iced_wgpu = "0.2" 31 | ``` 32 | 33 | __Iced moves fast and the `master` branch can contain breaking changes!__ If 34 | you want to learn about a specific release, check out [the release list]. 35 | 36 | [the release list]: https://github.com/hecrj/iced/releases 37 | 38 | ## Current limitations 39 | 40 | The current implementation is quite naive, it uses: 41 | 42 | - A different pipeline/shader for each primitive 43 | - A very simplistic layer model: every `Clip` primitive will generate new layers 44 | - _Many_ render passes instead of preparing everything upfront 45 | - A glyph cache that is trimmed incorrectly when there are multiple layers (a [`glyph_brush`] limitation) 46 | 47 | Some of these issues are already being worked on! If you want to help, [get in touch!] 48 | 49 | [get in touch!]: ../CONTRIBUTING.md 50 | [`glyph_brush`]: https://github.com/alexheretic/glyph-brush 51 | -------------------------------------------------------------------------------- /src/settings.rs: -------------------------------------------------------------------------------- 1 | //! Configure your application. 2 | use crate::window; 3 | 4 | /// The settings of an application. 5 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 6 | pub struct Settings { 7 | /// The window settings. 8 | /// 9 | /// They will be ignored on the Web. 10 | /// 11 | /// [`Window`]: struct.Window.html 12 | pub window: window::Settings, 13 | 14 | /// The data needed to initialize an [`Application`]. 15 | /// 16 | /// [`Application`]: ../trait.Application.html 17 | pub flags: Flags, 18 | 19 | /// The bytes of the font that will be used by default. 20 | /// 21 | /// If `None` is provided, a default system font will be chosen. 22 | // TODO: Add `name` for web compatibility 23 | pub default_font: Option<&'static [u8]>, 24 | 25 | /// If set to true, the renderer will try to perform antialiasing for some 26 | /// primitives. 27 | /// 28 | /// Enabling it can produce a smoother result in some widgets, like the 29 | /// [`Canvas`], at a performance cost. 30 | /// 31 | /// By default, it is disabled. 32 | /// 33 | /// [`Canvas`]: ../widget/canvas/struct.Canvas.html 34 | pub antialiasing: bool, 35 | } 36 | 37 | impl Settings { 38 | /// Initialize application settings using the given data. 39 | /// 40 | /// [`Application`]: ../trait.Application.html 41 | pub fn with_flags(flags: Flags) -> Self { 42 | Self { 43 | flags, 44 | // not using ..Default::default() struct update syntax since it is more permissive to 45 | // allow initializing with flags without trait bound on Default 46 | antialiasing: Default::default(), 47 | default_font: Default::default(), 48 | window: Default::default(), 49 | } 50 | } 51 | } 52 | 53 | #[cfg(not(target_arch = "wasm32"))] 54 | impl From> for iced_winit::Settings { 55 | fn from(settings: Settings) -> iced_winit::Settings { 56 | iced_winit::Settings { 57 | window: iced_winit::settings::Window { 58 | size: settings.window.size, 59 | resizable: settings.window.resizable, 60 | decorations: settings.window.decorations, 61 | platform_specific: Default::default(), 62 | }, 63 | flags: settings.flags, 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /examples/events/src/main.rs: -------------------------------------------------------------------------------- 1 | use iced::{ 2 | executor, Align, Application, Checkbox, Column, Command, Container, 3 | Element, Length, Settings, Subscription, Text, 4 | }; 5 | 6 | pub fn main() { 7 | Events::run(Settings::default()) 8 | } 9 | 10 | #[derive(Debug, Default)] 11 | struct Events { 12 | last: Vec, 13 | enabled: bool, 14 | } 15 | 16 | #[derive(Debug, Clone)] 17 | enum Message { 18 | EventOccurred(iced_native::Event), 19 | Toggled(bool), 20 | } 21 | 22 | impl Application for Events { 23 | type Executor = executor::Default; 24 | type Message = Message; 25 | type Flags = (); 26 | 27 | fn new(_flags: ()) -> (Events, Command) { 28 | (Events::default(), Command::none()) 29 | } 30 | 31 | fn title(&self) -> String { 32 | String::from("Events - Iced") 33 | } 34 | 35 | fn update(&mut self, message: Message) -> Command { 36 | match message { 37 | Message::EventOccurred(event) => { 38 | self.last.push(event); 39 | 40 | if self.last.len() > 5 { 41 | let _ = self.last.remove(0); 42 | } 43 | } 44 | Message::Toggled(enabled) => { 45 | self.enabled = enabled; 46 | } 47 | }; 48 | 49 | Command::none() 50 | } 51 | 52 | fn subscription(&self) -> Subscription { 53 | if self.enabled { 54 | iced_native::subscription::events().map(Message::EventOccurred) 55 | } else { 56 | Subscription::none() 57 | } 58 | } 59 | 60 | fn view(&mut self) -> Element { 61 | let events = self.last.iter().fold( 62 | Column::new().spacing(10), 63 | |column, event| { 64 | column.push(Text::new(format!("{:?}", event)).size(40)) 65 | }, 66 | ); 67 | 68 | let toggle = Checkbox::new( 69 | self.enabled, 70 | "Listen to runtime events", 71 | Message::Toggled, 72 | ); 73 | 74 | let content = Column::new() 75 | .align_items(Align::Center) 76 | .spacing(20) 77 | .push(events) 78 | .push(toggle); 79 | 80 | Container::new(content) 81 | .width(Length::Fill) 82 | .height(Length::Fill) 83 | .center_x() 84 | .center_y() 85 | .into() 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /wgpu/src/widget/canvas/cursor.rs: -------------------------------------------------------------------------------- 1 | use iced_native::{Point, Rectangle}; 2 | 3 | /// The mouse cursor state. 4 | #[derive(Debug, Clone, Copy, PartialEq)] 5 | pub enum Cursor { 6 | /// The cursor has a defined position. 7 | Available(Point), 8 | 9 | /// The cursor is currently unavailable (i.e. out of bounds or busy). 10 | Unavailable, 11 | } 12 | 13 | impl Cursor { 14 | // TODO: Remove this once this type is used in `iced_native` to encode 15 | // proper cursor availability 16 | pub(crate) fn from_window_position(position: Point) -> Self { 17 | if position.x < 0.0 || position.y < 0.0 { 18 | Cursor::Unavailable 19 | } else { 20 | Cursor::Available(position) 21 | } 22 | } 23 | 24 | /// Returns the absolute position of the [`Cursor`], if available. 25 | /// 26 | /// [`Cursor`]: enum.Cursor.html 27 | pub fn position(&self) -> Option { 28 | match self { 29 | Cursor::Available(position) => Some(*position), 30 | Cursor::Unavailable => None, 31 | } 32 | } 33 | 34 | /// Returns the relative position of the [`Cursor`] inside the given bounds, 35 | /// if available. 36 | /// 37 | /// If the [`Cursor`] is not over the provided bounds, this method will 38 | /// return `None`. 39 | /// 40 | /// [`Cursor`]: enum.Cursor.html 41 | pub fn position_in(&self, bounds: &Rectangle) -> Option { 42 | if self.is_over(bounds) { 43 | self.position_from(bounds.position()) 44 | } else { 45 | None 46 | } 47 | } 48 | 49 | /// Returns the relative position of the [`Cursor`] from the given origin, 50 | /// if available. 51 | /// 52 | /// [`Cursor`]: enum.Cursor.html 53 | pub fn position_from(&self, origin: Point) -> Option { 54 | match self { 55 | Cursor::Available(position) => { 56 | Some(Point::new(position.x - origin.x, position.y - origin.y)) 57 | } 58 | Cursor::Unavailable => None, 59 | } 60 | } 61 | 62 | /// Returns whether the [`Cursor`] is currently over the provided bounds 63 | /// or not. 64 | /// 65 | /// [`Cursor`]: enum.Cursor.html 66 | pub fn is_over(&self, bounds: &Rectangle) -> bool { 67 | match self { 68 | Cursor::Available(position) => bounds.contains(*position), 69 | Cursor::Unavailable => false, 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/widget.rs: -------------------------------------------------------------------------------- 1 | //! Display information and interactive controls in your application. 2 | //! 3 | //! # Re-exports 4 | //! For convenience, the contents of this module are available at the root 5 | //! module. Therefore, you can directly type: 6 | //! 7 | //! ``` 8 | //! use iced::{button, Button}; 9 | //! ``` 10 | //! 11 | //! # Stateful widgets 12 | //! Some widgets need to keep track of __local state__. 13 | //! 14 | //! These widgets have their own module with a `State` type. For instance, a 15 | //! [`TextInput`] has some [`text_input::State`]. 16 | //! 17 | //! [`TextInput`]: text_input/struct.TextInput.html 18 | //! [`text_input::State`]: text_input/struct.State.html 19 | #[cfg(not(target_arch = "wasm32"))] 20 | mod platform { 21 | pub use iced_wgpu::widget::{ 22 | button, checkbox, container, pane_grid, progress_bar, radio, 23 | scrollable, slider, text_input, Text, 24 | }; 25 | 26 | #[cfg(feature = "canvas")] 27 | #[cfg_attr(docsrs, doc(cfg(feature = "canvas")))] 28 | pub use iced_wgpu::widget::canvas; 29 | 30 | #[cfg_attr(docsrs, doc(cfg(feature = "image")))] 31 | pub mod image { 32 | //! Display images in your user interface. 33 | pub use iced_winit::image::{Handle, Image}; 34 | } 35 | 36 | #[cfg_attr(docsrs, doc(cfg(feature = "svg")))] 37 | pub mod svg { 38 | //! Display vector graphics in your user interface. 39 | pub use iced_winit::svg::{Handle, Svg}; 40 | } 41 | 42 | pub use iced_winit::Space; 43 | 44 | #[doc(no_inline)] 45 | pub use { 46 | button::Button, checkbox::Checkbox, container::Container, image::Image, 47 | pane_grid::PaneGrid, progress_bar::ProgressBar, radio::Radio, 48 | scrollable::Scrollable, slider::Slider, svg::Svg, 49 | text_input::TextInput, 50 | }; 51 | 52 | #[cfg(feature = "canvas")] 53 | #[doc(no_inline)] 54 | pub use canvas::Canvas; 55 | 56 | /// A container that distributes its contents vertically. 57 | /// 58 | /// This is an alias of an `iced_native` column with a default `Renderer`. 59 | pub type Column<'a, Message> = 60 | iced_winit::Column<'a, Message, iced_wgpu::Renderer>; 61 | 62 | /// A container that distributes its contents horizontally. 63 | /// 64 | /// This is an alias of an `iced_native` row with a default `Renderer`. 65 | pub type Row<'a, Message> = 66 | iced_winit::Row<'a, Message, iced_wgpu::Renderer>; 67 | } 68 | 69 | #[cfg(target_arch = "wasm32")] 70 | mod platform { 71 | pub use iced_web::widget::*; 72 | } 73 | 74 | pub use platform::*; 75 | -------------------------------------------------------------------------------- /style/src/slider.rs: -------------------------------------------------------------------------------- 1 | //! Display an interactive selector of a single value from a range of values. 2 | use iced_core::Color; 3 | 4 | /// The appearance of a slider. 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Style { 7 | pub rail_colors: (Color, Color), 8 | pub handle: Handle, 9 | } 10 | 11 | /// The appearance of the handle of a slider. 12 | #[derive(Debug, Clone, Copy)] 13 | pub struct Handle { 14 | pub shape: HandleShape, 15 | pub color: Color, 16 | pub border_width: u16, 17 | pub border_color: Color, 18 | } 19 | 20 | /// The shape of the handle of a slider. 21 | #[derive(Debug, Clone, Copy)] 22 | pub enum HandleShape { 23 | Circle { radius: u16 }, 24 | Rectangle { width: u16, border_radius: u16 }, 25 | } 26 | 27 | /// A set of rules that dictate the style of a slider. 28 | pub trait StyleSheet { 29 | /// Produces the style of an active slider. 30 | fn active(&self) -> Style; 31 | 32 | /// Produces the style of an hovered slider. 33 | fn hovered(&self) -> Style; 34 | 35 | /// Produces the style of a slider that is being dragged. 36 | fn dragging(&self) -> Style; 37 | } 38 | 39 | struct Default; 40 | 41 | impl StyleSheet for Default { 42 | fn active(&self) -> Style { 43 | Style { 44 | rail_colors: ([0.6, 0.6, 0.6, 0.5].into(), Color::WHITE), 45 | handle: Handle { 46 | shape: HandleShape::Rectangle { 47 | width: 8, 48 | border_radius: 4, 49 | }, 50 | color: Color::from_rgb(0.95, 0.95, 0.95), 51 | border_color: Color::from_rgb(0.6, 0.6, 0.6), 52 | border_width: 1, 53 | }, 54 | } 55 | } 56 | 57 | fn hovered(&self) -> Style { 58 | let active = self.active(); 59 | 60 | Style { 61 | handle: Handle { 62 | color: Color::from_rgb(0.90, 0.90, 0.90), 63 | ..active.handle 64 | }, 65 | ..active 66 | } 67 | } 68 | 69 | fn dragging(&self) -> Style { 70 | let active = self.active(); 71 | 72 | Style { 73 | handle: Handle { 74 | color: Color::from_rgb(0.85, 0.85, 0.85), 75 | ..active.handle 76 | }, 77 | ..active 78 | } 79 | } 80 | } 81 | 82 | impl std::default::Default for Box { 83 | fn default() -> Self { 84 | Box::new(Default) 85 | } 86 | } 87 | 88 | impl From for Box 89 | where 90 | T: 'static + StyleSheet, 91 | { 92 | fn from(style: T) -> Self { 93 | Box::new(style) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/executor.rs: -------------------------------------------------------------------------------- 1 | //! Choose your preferred executor to power your application. 2 | pub use crate::runtime::{executor::Null, Executor}; 3 | 4 | pub use platform::Default; 5 | 6 | #[cfg(not(target_arch = "wasm32"))] 7 | mod platform { 8 | use iced_futures::{executor, futures}; 9 | 10 | #[cfg(feature = "tokio")] 11 | type Executor = executor::Tokio; 12 | 13 | #[cfg(all(not(feature = "tokio"), feature = "async-std"))] 14 | type Executor = executor::AsyncStd; 15 | 16 | #[cfg(not(any(feature = "tokio", feature = "async-std")))] 17 | type Executor = executor::ThreadPool; 18 | 19 | /// A default cross-platform executor. 20 | /// 21 | /// - On native platforms, it will use: 22 | /// - `iced_futures::executor::Tokio` when the `tokio` feature is enabled. 23 | /// - `iced_futures::executor::AsyncStd` when the `async-std` feature is 24 | /// enabled. 25 | /// - `iced_futures::executor::ThreadPool` otherwise. 26 | /// - On the Web, it will use `iced_futures::executor::WasmBindgen`. 27 | #[derive(Debug)] 28 | pub struct Default(Executor); 29 | 30 | impl super::Executor for Default { 31 | fn new() -> Result { 32 | Ok(Default(Executor::new()?)) 33 | } 34 | 35 | fn spawn( 36 | &self, 37 | future: impl futures::Future + Send + 'static, 38 | ) { 39 | let _ = self.0.spawn(future); 40 | } 41 | 42 | fn enter(&self, f: impl FnOnce() -> R) -> R { 43 | self.0.enter(f) 44 | } 45 | } 46 | } 47 | 48 | #[cfg(target_arch = "wasm32")] 49 | mod platform { 50 | use iced_futures::{executor::WasmBindgen, futures, Executor}; 51 | 52 | /// A default cross-platform executor. 53 | /// 54 | /// - On native platforms, it will use: 55 | /// - `iced_futures::executor::Tokio` when the `tokio` feature is enabled. 56 | /// - `iced_futures::executor::AsyncStd` when the `async-std` feature is 57 | /// enabled. 58 | /// - `iced_futures::executor::ThreadPool` otherwise. 59 | /// - On the Web, it will use `iced_futures::executor::WasmBindgen`. 60 | #[derive(Debug)] 61 | pub struct Default(WasmBindgen); 62 | 63 | impl Executor for Default { 64 | fn new() -> Result { 65 | Ok(Default(WasmBindgen::new()?)) 66 | } 67 | 68 | fn spawn(&self, future: impl futures::Future + 'static) { 69 | self.0.spawn(future); 70 | } 71 | 72 | fn enter(&self, f: impl FnOnce() -> R) -> R { 73 | self.0.enter(f) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | todos_linux: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: hecrj/setup-rust-action@v1 11 | - name: Install cargo-deb 12 | run: cargo install cargo-deb 13 | - uses: actions/checkout@master 14 | - name: Enable Link Time Optimizations 15 | run: | 16 | echo "[profile.release]" >> Cargo.toml 17 | echo "lto = true" >> Cargo.toml 18 | - name: Build todos binary 19 | run: cargo build --verbose --release --package todos 20 | - name: Archive todos binary 21 | uses: actions/upload-artifact@v1 22 | with: 23 | name: todos-x86_64-unknown-linux-gnu 24 | path: target/release/todos 25 | - name: Pack todos .deb package 26 | run: cargo deb --no-build --package todos 27 | - name: Rename todos .deb package 28 | run: mv target/debian/*.deb target/debian/iced_todos-x86_64-debian-linux-gnu.deb 29 | - name: Archive todos .deb package 30 | uses: actions/upload-artifact@v1 31 | with: 32 | name: todos-x86_64-debian-linux-gnu 33 | path: target/debian/iced_todos-x86_64-debian-linux-gnu.deb 34 | 35 | todos_windows: 36 | runs-on: windows-latest 37 | steps: 38 | - uses: hecrj/setup-rust-action@v1 39 | - uses: actions/checkout@master 40 | - name: Enable Link Time Optimizations 41 | run: | 42 | echo "[profile.release]" >> Cargo.toml 43 | echo "lto = true" >> Cargo.toml 44 | - name: Enable static CRT linkage 45 | run: | 46 | mkdir .cargo 47 | echo '[target.x86_64-pc-windows-msvc]' >> .cargo/config 48 | echo 'rustflags = ["-Ctarget-feature=+crt-static"]' >> .cargo/config 49 | - name: Build todos binary 50 | run: cargo build --verbose --release --package todos 51 | - name: Archive todos binary 52 | uses: actions/upload-artifact@v1 53 | with: 54 | name: todos-x86_64-pc-windows-msvc 55 | path: target/release/todos.exe 56 | 57 | todos_macos: 58 | runs-on: macOS-latest 59 | steps: 60 | - uses: hecrj/setup-rust-action@v1 61 | - uses: actions/checkout@master 62 | - name: Enable Link Time Optimizations 63 | run: | 64 | echo "[profile.release]" >> Cargo.toml 65 | echo "lto = true" >> Cargo.toml 66 | - name: Build todos binary 67 | env: 68 | MACOSX_DEPLOYMENT_TARGET: 10.14 69 | run: cargo build --verbose --release --package todos 70 | - name: Archive todos binary 71 | uses: actions/upload-artifact@v1 72 | with: 73 | name: todos-x86_64-apple-darwin 74 | path: target/release/todos 75 | -------------------------------------------------------------------------------- /style/src/button.rs: -------------------------------------------------------------------------------- 1 | //! Allow your users to perform actions by pressing a button. 2 | use iced_core::{Background, Color, Vector}; 3 | 4 | /// The appearance of a button. 5 | #[derive(Debug)] 6 | pub struct Style { 7 | pub shadow_offset: Vector, 8 | pub background: Option, 9 | pub border_radius: u16, 10 | pub border_width: u16, 11 | pub border_color: Color, 12 | pub text_color: Color, 13 | } 14 | 15 | impl std::default::Default for Style { 16 | fn default() -> Self { 17 | Self { 18 | shadow_offset: Vector::default(), 19 | background: None, 20 | border_radius: 0, 21 | border_width: 0, 22 | border_color: Color::TRANSPARENT, 23 | text_color: Color::BLACK, 24 | } 25 | } 26 | } 27 | 28 | /// A set of rules that dictate the style of a button. 29 | pub trait StyleSheet { 30 | fn active(&self) -> Style; 31 | 32 | fn hovered(&self) -> Style { 33 | let active = self.active(); 34 | 35 | Style { 36 | shadow_offset: active.shadow_offset + Vector::new(0.0, 1.0), 37 | ..active 38 | } 39 | } 40 | 41 | fn pressed(&self) -> Style { 42 | Style { 43 | shadow_offset: Vector::default(), 44 | ..self.active() 45 | } 46 | } 47 | 48 | fn disabled(&self) -> Style { 49 | let active = self.active(); 50 | 51 | Style { 52 | shadow_offset: Vector::default(), 53 | background: active.background.map(|background| match background { 54 | Background::Color(color) => Background::Color(Color { 55 | a: color.a * 0.5, 56 | ..color 57 | }), 58 | }), 59 | text_color: Color { 60 | a: active.text_color.a * 0.5, 61 | ..active.text_color 62 | }, 63 | ..active 64 | } 65 | } 66 | } 67 | 68 | struct Default; 69 | 70 | impl StyleSheet for Default { 71 | fn active(&self) -> Style { 72 | Style { 73 | shadow_offset: Vector::new(0.0, 0.0), 74 | background: Some(Background::Color([0.87, 0.87, 0.87].into())), 75 | border_radius: 2, 76 | border_width: 1, 77 | border_color: [0.7, 0.7, 0.7].into(), 78 | text_color: Color::BLACK, 79 | } 80 | } 81 | } 82 | 83 | impl std::default::Default for Box { 84 | fn default() -> Self { 85 | Box::new(Default) 86 | } 87 | } 88 | 89 | impl From for Box 90 | where 91 | T: 'static + StyleSheet, 92 | { 93 | fn from(style: T) -> Self { 94 | Box::new(style) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /wgpu/src/widget/canvas/program.rs: -------------------------------------------------------------------------------- 1 | use crate::canvas::{Cursor, Event, Geometry}; 2 | use iced_native::{mouse, Rectangle}; 3 | 4 | /// The state and logic of a [`Canvas`]. 5 | /// 6 | /// A [`Program`] can mutate internal state and produce messages for an 7 | /// application. 8 | /// 9 | /// [`Canvas`]: struct.Canvas.html 10 | /// [`Program`]: trait.Program.html 11 | pub trait Program { 12 | /// Updates the state of the [`Program`]. 13 | /// 14 | /// When a [`Program`] is used in a [`Canvas`], the runtime will call this 15 | /// method for each [`Event`]. 16 | /// 17 | /// This method can optionally return a `Message` to notify an application 18 | /// of any meaningful interactions. 19 | /// 20 | /// By default, this method does and returns nothing. 21 | /// 22 | /// [`Program`]: trait.Program.html 23 | /// [`Canvas`]: struct.Canvas.html 24 | /// [`Event`]: enum.Event.html 25 | fn update( 26 | &mut self, 27 | _event: Event, 28 | _bounds: Rectangle, 29 | _cursor: Cursor, 30 | ) -> Option { 31 | None 32 | } 33 | 34 | /// Draws the state of the [`Program`], producing a bunch of [`Geometry`]. 35 | /// 36 | /// [`Geometry`] can be easily generated with a [`Frame`] or stored in a 37 | /// [`Cache`]. 38 | /// 39 | /// [`Program`]: trait.Program.html 40 | /// [`Geometry`]: struct.Geometry.html 41 | /// [`Frame`]: struct.Frame.html 42 | /// [`Cache`]: struct.Cache.html 43 | fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec; 44 | 45 | /// Returns the current mouse interaction of the [`Program`]. 46 | /// 47 | /// The interaction returned will be in effect even if the cursor position 48 | /// is out of bounds of the program's [`Canvas`]. 49 | /// 50 | /// [`Program`]: trait.Program.html 51 | /// [`Canvas`]: struct.Canvas.html 52 | fn mouse_interaction( 53 | &self, 54 | _bounds: Rectangle, 55 | _cursor: Cursor, 56 | ) -> mouse::Interaction { 57 | mouse::Interaction::default() 58 | } 59 | } 60 | 61 | impl Program for &mut T 62 | where 63 | T: Program, 64 | { 65 | fn update( 66 | &mut self, 67 | event: Event, 68 | bounds: Rectangle, 69 | cursor: Cursor, 70 | ) -> Option { 71 | T::update(self, event, bounds, cursor) 72 | } 73 | 74 | fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec { 75 | T::draw(self, bounds, cursor) 76 | } 77 | 78 | fn mouse_interaction( 79 | &self, 80 | bounds: Rectangle, 81 | cursor: Cursor, 82 | ) -> mouse::Interaction { 83 | T::mouse_interaction(self, bounds, cursor) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /native/src/layout/node.rs: -------------------------------------------------------------------------------- 1 | use crate::{Align, Point, Rectangle, Size}; 2 | 3 | /// The bounds of an element and its children. 4 | #[derive(Debug, Clone, Default)] 5 | pub struct Node { 6 | bounds: Rectangle, 7 | children: Vec, 8 | } 9 | 10 | impl Node { 11 | /// Creates a new [`Node`] with the given [`Size`]. 12 | /// 13 | /// [`Node`]: struct.Node.html 14 | /// [`Size`]: ../struct.Size.html 15 | pub const fn new(size: Size) -> Self { 16 | Self::with_children(size, Vec::new()) 17 | } 18 | 19 | /// Creates a new [`Node`] with the given [`Size`] and children. 20 | /// 21 | /// [`Node`]: struct.Node.html 22 | /// [`Size`]: ../struct.Size.html 23 | pub const fn with_children(size: Size, children: Vec) -> Self { 24 | Node { 25 | bounds: Rectangle { 26 | x: 0.0, 27 | y: 0.0, 28 | width: size.width, 29 | height: size.height, 30 | }, 31 | children, 32 | } 33 | } 34 | 35 | /// Returns the [`Size`] of the [`Node`]. 36 | /// 37 | /// [`Node`]: struct.Node.html 38 | /// [`Size`]: ../struct.Size.html 39 | pub fn size(&self) -> Size { 40 | Size::new(self.bounds.width, self.bounds.height) 41 | } 42 | 43 | /// Returns the bounds of the [`Node`]. 44 | /// 45 | /// [`Node`]: struct.Node.html 46 | pub fn bounds(&self) -> Rectangle { 47 | self.bounds 48 | } 49 | 50 | /// Returns the children of the [`Node`]. 51 | /// 52 | /// [`Node`]: struct.Node.html 53 | pub fn children(&self) -> &[Node] { 54 | &self.children 55 | } 56 | 57 | /// Aligns the [`Node`] in the given space. 58 | /// 59 | /// [`Node`]: struct.Node.html 60 | pub fn align( 61 | &mut self, 62 | horizontal_alignment: Align, 63 | vertical_alignment: Align, 64 | space: Size, 65 | ) { 66 | match horizontal_alignment { 67 | Align::Start => {} 68 | Align::Center => { 69 | self.bounds.x += (space.width - self.bounds.width) / 2.0; 70 | } 71 | Align::End => { 72 | self.bounds.x += space.width - self.bounds.width; 73 | } 74 | } 75 | 76 | match vertical_alignment { 77 | Align::Start => {} 78 | Align::Center => { 79 | self.bounds.y += (space.height - self.bounds.height) / 2.0; 80 | } 81 | Align::End => { 82 | self.bounds.y += space.height - self.bounds.height; 83 | } 84 | } 85 | } 86 | 87 | /// Moves the [`Node`] to the given position. 88 | /// 89 | /// [`Node`]: struct.Node.html 90 | pub fn move_to(&mut self, position: Point) { 91 | self.bounds.x = position.x; 92 | self.bounds.y = position.y; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /native/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A renderer-agnostic native GUI runtime. 2 | //! 3 | //! ![`iced_native` crate graph](https://github.com/hecrj/iced/blob/cae26cb7bc627f4a5b3bcf1cd023a0c552e8c65e/docs/graphs/native.png?raw=true) 4 | //! 5 | //! `iced_native` takes [`iced_core`] and builds a native runtime on top of it, 6 | //! featuring: 7 | //! 8 | //! - A custom layout engine, greatly inspired by [`druid`] 9 | //! - Event handling for all the built-in widgets 10 | //! - A renderer-agnostic API 11 | //! 12 | //! To achieve this, it introduces a bunch of reusable interfaces: 13 | //! 14 | //! - A [`Widget`] trait, which is used to implement new widgets: from layout 15 | //! requirements to event and drawing logic. 16 | //! - A bunch of `Renderer` traits, meant to keep the crate renderer-agnostic. 17 | //! - A [`window::Backend`] trait, leveraging [`raw-window-handle`], which can be 18 | //! implemented by graphical renderers that target _windows_. Window-based 19 | //! shells (like [`iced_winit`]) can use this trait to stay renderer-agnostic. 20 | //! 21 | //! # Usage 22 | //! The strategy to use this crate depends on your particular use case. If you 23 | //! want to: 24 | //! - Implement a custom shell or integrate it in your own system, check out the 25 | //! [`UserInterface`] type. 26 | //! - Build a new renderer, see the [renderer] module. 27 | //! - Build a custom widget, start at the [`Widget`] trait. 28 | //! 29 | //! [`iced_core`]: https://github.com/hecrj/iced/tree/master/core 30 | //! [`iced_winit`]: https://github.com/hecrj/iced/tree/master/winit 31 | //! [`druid`]: https://github.com/xi-editor/druid 32 | //! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle 33 | //! [`Widget`]: widget/trait.Widget.html 34 | //! [`window::Backend`]: window/trait.Backend.html 35 | //! [`UserInterface`]: struct.UserInterface.html 36 | //! [renderer]: renderer/index.html 37 | #![deny(missing_docs)] 38 | #![deny(missing_debug_implementations)] 39 | #![deny(unused_results)] 40 | #![forbid(unsafe_code)] 41 | #![forbid(rust_2018_idioms)] 42 | pub mod keyboard; 43 | pub mod layout; 44 | pub mod mouse; 45 | pub mod renderer; 46 | pub mod subscription; 47 | pub mod widget; 48 | pub mod window; 49 | 50 | mod clipboard; 51 | mod element; 52 | mod event; 53 | mod hasher; 54 | mod runtime; 55 | mod user_interface; 56 | 57 | pub use iced_core::{ 58 | Align, Background, Color, Font, HorizontalAlignment, Length, Point, 59 | Rectangle, Size, Vector, VerticalAlignment, 60 | }; 61 | pub use iced_futures::{executor, futures, Command}; 62 | 63 | #[doc(no_inline)] 64 | pub use executor::Executor; 65 | 66 | pub use clipboard::Clipboard; 67 | pub use element::Element; 68 | pub use event::Event; 69 | pub use hasher::Hasher; 70 | pub use layout::Layout; 71 | pub use renderer::Renderer; 72 | pub use runtime::Runtime; 73 | pub use subscription::Subscription; 74 | pub use user_interface::{Cache, UserInterface}; 75 | pub use widget::*; 76 | -------------------------------------------------------------------------------- /web/src/element.rs: -------------------------------------------------------------------------------- 1 | use crate::{Bus, Color, Css, Widget}; 2 | 3 | use dodrio::bumpalo; 4 | use std::rc::Rc; 5 | 6 | /// A generic [`Widget`]. 7 | /// 8 | /// It is useful to build composable user interfaces that do not leak 9 | /// implementation details in their __view logic__. 10 | /// 11 | /// If you have a [built-in widget], you should be able to use `Into` 12 | /// to turn it into an [`Element`]. 13 | /// 14 | /// [built-in widget]: widget/index.html 15 | /// [`Widget`]: widget/trait.Widget.html 16 | /// [`Element`]: struct.Element.html 17 | #[allow(missing_debug_implementations)] 18 | pub struct Element<'a, Message> { 19 | pub(crate) widget: Box + 'a>, 20 | } 21 | 22 | impl<'a, Message> Element<'a, Message> { 23 | /// Create a new [`Element`] containing the given [`Widget`]. 24 | /// 25 | /// [`Element`]: struct.Element.html 26 | /// [`Widget`]: widget/trait.Widget.html 27 | pub fn new(widget: impl Widget + 'a) -> Self { 28 | Self { 29 | widget: Box::new(widget), 30 | } 31 | } 32 | 33 | /// Applies a transformation to the produced message of the [`Element`]. 34 | /// 35 | /// This method is useful when you want to decouple different parts of your 36 | /// UI and make them __composable__. 37 | /// 38 | /// [`Element`]: struct.Element.html 39 | pub fn map(self, f: F) -> Element<'a, B> 40 | where 41 | Message: 'static, 42 | B: 'static, 43 | F: 'static + Fn(Message) -> B, 44 | { 45 | Element { 46 | widget: Box::new(Map::new(self.widget, f)), 47 | } 48 | } 49 | 50 | /// Marks the [`Element`] as _to-be-explained_. 51 | pub fn explain(self, _color: Color) -> Element<'a, Message> { 52 | self 53 | } 54 | 55 | /// Produces a VDOM node for the [`Element`]. 56 | pub fn node<'b>( 57 | &self, 58 | bump: &'b bumpalo::Bump, 59 | bus: &Bus, 60 | style_sheet: &mut Css<'b>, 61 | ) -> dodrio::Node<'b> { 62 | self.widget.node(bump, bus, style_sheet) 63 | } 64 | } 65 | 66 | struct Map<'a, A, B> { 67 | widget: Box + 'a>, 68 | mapper: Rc B>>, 69 | } 70 | 71 | impl<'a, A, B> Map<'a, A, B> { 72 | pub fn new(widget: Box + 'a>, mapper: F) -> Map<'a, A, B> 73 | where 74 | F: 'static + Fn(A) -> B, 75 | { 76 | Map { 77 | widget, 78 | mapper: Rc::new(Box::new(mapper)), 79 | } 80 | } 81 | } 82 | 83 | impl<'a, A, B> Widget for Map<'a, A, B> 84 | where 85 | A: 'static, 86 | B: 'static, 87 | { 88 | fn node<'b>( 89 | &self, 90 | bump: &'b bumpalo::Bump, 91 | bus: &Bus, 92 | style_sheet: &mut Css<'b>, 93 | ) -> dodrio::Node<'b> { 94 | self.widget 95 | .node(bump, &bus.map(self.mapper.clone()), style_sheet) 96 | } 97 | } 98 | --------------------------------------------------------------------------------