Implement `iced_glutin` 🎉
This commit is contained in:
parent
a1a5fcfd46
commit
e0e4ee73fe
13
Cargo.toml
13
Cargo.toml
|
@ -13,13 +13,13 @@ categories = ["gui"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Enables the `Image` widget
|
# Enables the `Image` widget
|
||||||
image = ["iced_wgpu/image"]
|
image = ["iced_glow/image"]
|
||||||
# Enables the `Svg` widget
|
# Enables the `Svg` widget
|
||||||
svg = ["iced_wgpu/svg"]
|
svg = ["iced_glow/svg"]
|
||||||
# Enables the `Canvas` widget
|
# Enables the `Canvas` widget
|
||||||
canvas = ["iced_wgpu/canvas"]
|
canvas = ["iced_glow/canvas"]
|
||||||
# Enables a debug view in native platforms (press F12)
|
# Enables a debug view in native platforms (press F12)
|
||||||
debug = ["iced_winit/debug"]
|
debug = ["iced_glutin/debug"]
|
||||||
# Enables `tokio` as the `executor::Default` on native platforms
|
# Enables `tokio` as the `executor::Default` on native platforms
|
||||||
tokio = ["iced_futures/tokio"]
|
tokio = ["iced_futures/tokio"]
|
||||||
# Enables `async-std` as the `executor::Default` on native platforms
|
# Enables `async-std` as the `executor::Default` on native platforms
|
||||||
|
@ -36,6 +36,7 @@ members = [
|
||||||
"futures",
|
"futures",
|
||||||
"graphics",
|
"graphics",
|
||||||
"glow",
|
"glow",
|
||||||
|
"glutin",
|
||||||
"native",
|
"native",
|
||||||
"style",
|
"style",
|
||||||
"web",
|
"web",
|
||||||
|
@ -67,8 +68,8 @@ iced_core = { version = "0.2", path = "core" }
|
||||||
iced_futures = { version = "0.1", path = "futures" }
|
iced_futures = { version = "0.1", path = "futures" }
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
iced_winit = { version = "0.1", path = "winit" }
|
iced_glutin = { version = "0.1", path = "glutin" }
|
||||||
iced_wgpu = { version = "0.2", path = "wgpu" }
|
iced_glow = { version = "0.1", path = "glow" }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
iced_web = { version = "0.2", path = "web" }
|
iced_web = { version = "0.2", path = "web" }
|
||||||
|
|
|
@ -8,4 +8,4 @@ publish = false
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced = { path = "../.." }
|
iced = { path = "../.." }
|
||||||
iced_native = { path = "../../native" }
|
iced_native = { path = "../../native" }
|
||||||
iced_wgpu = { path = "../../wgpu" }
|
iced_graphics = { path = "../../graphics" }
|
||||||
|
|
|
@ -9,11 +9,11 @@ mod circle {
|
||||||
// Of course, you can choose to make the implementation renderer-agnostic,
|
// Of course, you can choose to make the implementation renderer-agnostic,
|
||||||
// if you wish to, by creating your own `Renderer` trait, which could be
|
// if you wish to, by creating your own `Renderer` trait, which could be
|
||||||
// implemented by `iced_wgpu` and other renderers.
|
// implemented by `iced_wgpu` and other renderers.
|
||||||
|
use iced_graphics::{Backend, Defaults, Primitive, Renderer};
|
||||||
use iced_native::{
|
use iced_native::{
|
||||||
layout, mouse, Background, Color, Element, Hasher, Layout, Length,
|
layout, mouse, Background, Color, Element, Hasher, Layout, Length,
|
||||||
Point, Size, Widget,
|
Point, Size, Widget,
|
||||||
};
|
};
|
||||||
use iced_wgpu::{Defaults, Primitive, Renderer};
|
|
||||||
|
|
||||||
pub struct Circle {
|
pub struct Circle {
|
||||||
radius: u16,
|
radius: u16,
|
||||||
|
@ -25,7 +25,10 @@ mod circle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message> Widget<Message, Renderer> for Circle {
|
impl<Message, B> Widget<Message, Renderer<B>> for Circle
|
||||||
|
where
|
||||||
|
B: Backend,
|
||||||
|
{
|
||||||
fn width(&self) -> Length {
|
fn width(&self) -> Length {
|
||||||
Length::Shrink
|
Length::Shrink
|
||||||
}
|
}
|
||||||
|
@ -36,7 +39,7 @@ mod circle {
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer<B>,
|
||||||
_limits: &layout::Limits,
|
_limits: &layout::Limits,
|
||||||
) -> layout::Node {
|
) -> layout::Node {
|
||||||
layout::Node::new(Size::new(
|
layout::Node::new(Size::new(
|
||||||
|
@ -53,7 +56,7 @@ mod circle {
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
_renderer: &mut Renderer,
|
_renderer: &mut Renderer<B>,
|
||||||
_defaults: &Defaults,
|
_defaults: &Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_cursor_position: Point,
|
_cursor_position: Point,
|
||||||
|
@ -71,8 +74,11 @@ mod circle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message> Into<Element<'a, Message, Renderer>> for Circle {
|
impl<'a, Message, B> Into<Element<'a, Message, Renderer<B>>> for Circle
|
||||||
fn into(self) -> Element<'a, Message, Renderer> {
|
where
|
||||||
|
B: Backend,
|
||||||
|
{
|
||||||
|
fn into(self) -> Element<'a, Message, Renderer<B>> {
|
||||||
Element::new(self)
|
Element::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,4 +8,4 @@ publish = false
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced = { path = "../.." }
|
iced = { path = "../.." }
|
||||||
iced_native = { path = "../../native" }
|
iced_native = { path = "../../native" }
|
||||||
iced_wgpu = { path = "../../wgpu" }
|
iced_graphics = { path = "../../graphics" }
|
||||||
|
|
|
@ -10,14 +10,14 @@ mod rainbow {
|
||||||
// Of course, you can choose to make the implementation renderer-agnostic,
|
// Of course, you can choose to make the implementation renderer-agnostic,
|
||||||
// if you wish to, by creating your own `Renderer` trait, which could be
|
// if you wish to, by creating your own `Renderer` trait, which could be
|
||||||
// implemented by `iced_wgpu` and other renderers.
|
// implemented by `iced_wgpu` and other renderers.
|
||||||
|
use iced_graphics::{
|
||||||
|
triangle::{Mesh2D, Vertex2D},
|
||||||
|
Backend, Defaults, Primitive, Renderer,
|
||||||
|
};
|
||||||
use iced_native::{
|
use iced_native::{
|
||||||
layout, mouse, Element, Hasher, Layout, Length, Point, Size, Vector,
|
layout, mouse, Element, Hasher, Layout, Length, Point, Size, Vector,
|
||||||
Widget,
|
Widget,
|
||||||
};
|
};
|
||||||
use iced_wgpu::{
|
|
||||||
triangle::{Mesh2D, Vertex2D},
|
|
||||||
Defaults, Primitive, Renderer,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Rainbow;
|
pub struct Rainbow;
|
||||||
|
|
||||||
|
@ -27,7 +27,10 @@ mod rainbow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message> Widget<Message, Renderer> for Rainbow {
|
impl<Message, B> Widget<Message, Renderer<B>> for Rainbow
|
||||||
|
where
|
||||||
|
B: Backend,
|
||||||
|
{
|
||||||
fn width(&self) -> Length {
|
fn width(&self) -> Length {
|
||||||
Length::Fill
|
Length::Fill
|
||||||
}
|
}
|
||||||
|
@ -38,7 +41,7 @@ mod rainbow {
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer<B>,
|
||||||
limits: &layout::Limits,
|
limits: &layout::Limits,
|
||||||
) -> layout::Node {
|
) -> layout::Node {
|
||||||
let size = limits.width(Length::Fill).resolve(Size::ZERO);
|
let size = limits.width(Length::Fill).resolve(Size::ZERO);
|
||||||
|
@ -50,7 +53,7 @@ mod rainbow {
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
_renderer: &mut Renderer,
|
_renderer: &mut Renderer<B>,
|
||||||
_defaults: &Defaults,
|
_defaults: &Defaults,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor_position: Point,
|
cursor_position: Point,
|
||||||
|
@ -146,8 +149,11 @@ mod rainbow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message> Into<Element<'a, Message, Renderer>> for Rainbow {
|
impl<'a, Message, B> Into<Element<'a, Message, Renderer<B>>> for Rainbow
|
||||||
fn into(self) -> Element<'a, Message, Renderer> {
|
where
|
||||||
|
B: Backend,
|
||||||
|
{
|
||||||
|
fn into(self) -> Element<'a, Message, Renderer<B>> {
|
||||||
Element::new(self)
|
Element::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced = { path = "../..", features = ["async-std"] }
|
iced = { path = "../..", features = ["async-std", "debug"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,5 @@ edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced_winit = { path = "../../winit", features = ["debug"] }
|
iced = { path = "../..", features = ["image", "debug"] }
|
||||||
iced_glow = { path = "../../glow" }
|
|
||||||
env_logger = "0.7"
|
env_logger = "0.7"
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
use iced_glow::{
|
use iced::{
|
||||||
button, scrollable, slider, text_input, window, Button, Checkbox, Color,
|
button, executor, scrollable, slider, text_input, Application, Button,
|
||||||
Column, Command, Container, Element, HorizontalAlignment, Image, Length,
|
Checkbox, Color, Column, Command, Container, Element, HorizontalAlignment,
|
||||||
Radio, Row, Scrollable, Slider, Space, Text, TextInput,
|
Image, Length, Radio, Row, Scrollable, Settings, Slider, Space, Text,
|
||||||
|
TextInput,
|
||||||
};
|
};
|
||||||
use iced_winit::{executor, Application, Settings};
|
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
Tour::run(
|
Tour::run(Settings::default())
|
||||||
Settings::default(),
|
|
||||||
iced_glow::Settings {
|
|
||||||
default_font: None,
|
|
||||||
antialiasing: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Tour {
|
pub struct Tour {
|
||||||
|
@ -26,7 +20,6 @@ pub struct Tour {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application for Tour {
|
impl Application for Tour {
|
||||||
type Compositor = window::Compositor;
|
|
||||||
type Executor = executor::Null;
|
type Executor = executor::Null;
|
||||||
type Message = Message;
|
type Message = Message;
|
||||||
type Flags = ();
|
type Flags = ();
|
||||||
|
@ -693,18 +686,17 @@ impl<'a> Step {
|
||||||
|
|
||||||
fn ferris<'a>(width: u16) -> Container<'a, StepMessage> {
|
fn ferris<'a>(width: u16) -> Container<'a, StepMessage> {
|
||||||
Container::new(
|
Container::new(
|
||||||
Text::new("Not supported yet!")
|
|
||||||
// This should go away once we unify resource loading on native
|
// This should go away once we unify resource loading on native
|
||||||
// platforms
|
// platforms
|
||||||
//if cfg!(target_arch = "wasm32") {
|
if cfg!(target_arch = "wasm32") {
|
||||||
// Image::new("images/ferris.png")
|
Image::new("images/ferris.png")
|
||||||
//} else {
|
} else {
|
||||||
// Image::new(format!(
|
Image::new(format!(
|
||||||
// "{}/images/ferris.png",
|
"{}/images/ferris.png",
|
||||||
// env!("CARGO_MANIFEST_DIR")
|
env!("CARGO_MANIFEST_DIR")
|
||||||
// ))
|
))
|
||||||
//}
|
}
|
||||||
//.width(Length::Units(width)),
|
.width(Length::Units(width)),
|
||||||
)
|
)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.center_x()
|
.center_x()
|
||||||
|
@ -765,7 +757,7 @@ pub enum Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod style {
|
mod style {
|
||||||
use iced_glow::{button, Background, Color, Vector};
|
use iced::{button, Background, Color, Vector};
|
||||||
|
|
||||||
pub enum Button {
|
pub enum Button {
|
||||||
Primary,
|
Primary,
|
||||||
|
|
|
@ -7,8 +7,12 @@ description = "A glow renderer for iced"
|
||||||
license = "MIT AND OFL-1.1"
|
license = "MIT AND OFL-1.1"
|
||||||
repository = "https://github.com/hecrj/iced"
|
repository = "https://github.com/hecrj/iced"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
canvas = ["iced_graphics/canvas"]
|
||||||
|
image = []
|
||||||
|
svg = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
raw-window-handle = "0.3"
|
|
||||||
euclid = "0.20"
|
euclid = "0.20"
|
||||||
glow = "0.4"
|
glow = "0.4"
|
||||||
bytemuck = "1.2"
|
bytemuck = "1.2"
|
||||||
|
@ -23,12 +27,7 @@ path = "../native"
|
||||||
[dependencies.iced_graphics]
|
[dependencies.iced_graphics]
|
||||||
version = "0.1"
|
version = "0.1"
|
||||||
path = "../graphics"
|
path = "../graphics"
|
||||||
features = ["font-source", "font-fallback", "font-icons"]
|
features = ["font-source", "font-fallback", "font-icons", "opengl"]
|
||||||
|
|
||||||
[dependencies.surfman]
|
|
||||||
path = "../../surfman/surfman"
|
|
||||||
default-features = false
|
|
||||||
features = ["sm-raw-window-handle", "sm-x11"]
|
|
||||||
|
|
||||||
[dependencies.glow_glyph]
|
[dependencies.glow_glyph]
|
||||||
path = "../../glow_glyph"
|
path = "../../glow_glyph"
|
||||||
|
|
|
@ -36,12 +36,6 @@ impl Backend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the provided primitives in the given [`Target`].
|
|
||||||
///
|
|
||||||
/// The text provided as overlay will be renderer on top of the primitives.
|
|
||||||
/// This is useful for rendering debug information.
|
|
||||||
///
|
|
||||||
/// [`Target`]: struct.Target.html
|
|
||||||
pub fn draw<T: AsRef<str>>(
|
pub fn draw<T: AsRef<str>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
gl: &glow::Context,
|
gl: &glow::Context,
|
||||||
|
@ -50,6 +44,7 @@ impl Backend {
|
||||||
overlay_text: &[T],
|
overlay_text: &[T],
|
||||||
) -> mouse::Interaction {
|
) -> mouse::Interaction {
|
||||||
let viewport_size = viewport.physical_size();
|
let viewport_size = viewport.physical_size();
|
||||||
|
let scale_factor = viewport.scale_factor() as f32;
|
||||||
let projection = viewport.projection();
|
let projection = viewport.projection();
|
||||||
|
|
||||||
let mut layers = Layer::generate(primitive, viewport);
|
let mut layers = Layer::generate(primitive, viewport);
|
||||||
|
@ -58,7 +53,7 @@ impl Backend {
|
||||||
for layer in layers {
|
for layer in layers {
|
||||||
self.flush(
|
self.flush(
|
||||||
gl,
|
gl,
|
||||||
viewport.scale_factor() as f32,
|
scale_factor,
|
||||||
projection,
|
projection,
|
||||||
&layer,
|
&layer,
|
||||||
viewport_size.width,
|
viewport_size.width,
|
||||||
|
@ -78,7 +73,8 @@ impl Backend {
|
||||||
target_width: u32,
|
target_width: u32,
|
||||||
target_height: u32,
|
target_height: u32,
|
||||||
) {
|
) {
|
||||||
let bounds = (layer.bounds * scale_factor).round();
|
let mut bounds = (layer.bounds * scale_factor).round();
|
||||||
|
bounds.height = bounds.height.min(target_height);
|
||||||
|
|
||||||
if !layer.quads.is_empty() {
|
if !layer.quads.is_empty() {
|
||||||
self.quad_pipeline.draw(
|
self.quad_pipeline.draw(
|
||||||
|
@ -204,3 +200,20 @@ impl backend::Text for Backend {
|
||||||
self.text_pipeline.space_width(size)
|
self.text_pipeline.space_width(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "image")]
|
||||||
|
impl backend::Image for Backend {
|
||||||
|
fn dimensions(&self, _handle: &iced_native::image::Handle) -> (u32, u32) {
|
||||||
|
(50, 50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "svg")]
|
||||||
|
impl backend::Svg for Backend {
|
||||||
|
fn viewport_dimensions(
|
||||||
|
&self,
|
||||||
|
_handle: &iced_native::svg::Handle,
|
||||||
|
) -> (u32, u32) {
|
||||||
|
(50, 50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -38,7 +38,16 @@ pub use slider::Slider;
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use text_input::TextInput;
|
pub use text_input::TextInput;
|
||||||
|
|
||||||
pub use iced_native::{Image, Space, Text};
|
#[cfg(feature = "canvas")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))]
|
||||||
|
pub mod canvas;
|
||||||
|
|
||||||
|
#[cfg(feature = "canvas")]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use canvas::Canvas;
|
||||||
|
|
||||||
|
pub use iced_native::{Image, Space};
|
||||||
|
|
||||||
pub type Column<'a, Message> = iced_native::Column<'a, Message, Renderer>;
|
pub type Column<'a, Message> = iced_native::Column<'a, Message, Renderer>;
|
||||||
pub type Row<'a, Message> = iced_native::Row<'a, Message, Renderer>;
|
pub type Row<'a, Message> = iced_native::Row<'a, Message, Renderer>;
|
||||||
|
pub type Text = iced_native::Text<Renderer>;
|
||||||
|
|
|
@ -6,196 +6,4 @@
|
||||||
//!
|
//!
|
||||||
//! [`Canvas`]: struct.Canvas.html
|
//! [`Canvas`]: struct.Canvas.html
|
||||||
//! [`Frame`]: struct.Frame.html
|
//! [`Frame`]: struct.Frame.html
|
||||||
use crate::{Defaults, Primitive, Renderer};
|
pub use iced_graphics::canvas::*;
|
||||||
|
|
||||||
use iced_native::{
|
|
||||||
layout, Element, Hasher, Layout, Length, MouseCursor, Point, Size, Widget,
|
|
||||||
};
|
|
||||||
use std::hash::Hash;
|
|
||||||
|
|
||||||
pub mod layer;
|
|
||||||
pub mod path;
|
|
||||||
|
|
||||||
mod drawable;
|
|
||||||
mod fill;
|
|
||||||
mod frame;
|
|
||||||
mod stroke;
|
|
||||||
mod text;
|
|
||||||
|
|
||||||
pub use drawable::Drawable;
|
|
||||||
pub use fill::Fill;
|
|
||||||
pub use frame::Frame;
|
|
||||||
pub use layer::Layer;
|
|
||||||
pub use path::Path;
|
|
||||||
pub use stroke::{LineCap, LineJoin, Stroke};
|
|
||||||
pub use text::Text;
|
|
||||||
|
|
||||||
/// A widget capable of drawing 2D graphics.
|
|
||||||
///
|
|
||||||
/// A [`Canvas`] may contain multiple layers. A [`Layer`] is drawn using the
|
|
||||||
/// painter's algorithm. In other words, layers will be drawn on top of each
|
|
||||||
/// other in the same order they are pushed into the [`Canvas`].
|
|
||||||
///
|
|
||||||
/// [`Canvas`]: struct.Canvas.html
|
|
||||||
/// [`Layer`]: layer/trait.Layer.html
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// The repository has a couple of [examples] showcasing how to use a
|
|
||||||
/// [`Canvas`]:
|
|
||||||
///
|
|
||||||
/// - [`clock`], an application that uses the [`Canvas`] widget to draw a clock
|
|
||||||
/// and its hands to display the current time.
|
|
||||||
/// - [`solar_system`], an animated solar system drawn using the [`Canvas`] widget
|
|
||||||
/// and showcasing how to compose different transforms.
|
|
||||||
///
|
|
||||||
/// [examples]: https://github.com/hecrj/iced/tree/0.1/examples
|
|
||||||
/// [`clock`]: https://github.com/hecrj/iced/tree/0.1/examples/clock
|
|
||||||
/// [`solar_system`]: https://github.com/hecrj/iced/tree/0.1/examples/solar_system
|
|
||||||
///
|
|
||||||
/// ## Drawing a simple circle
|
|
||||||
/// If you want to get a quick overview, here's how we can draw a simple circle:
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// # mod iced {
|
|
||||||
/// # pub use iced_wgpu::canvas;
|
|
||||||
/// # pub use iced_native::Color;
|
|
||||||
/// # }
|
|
||||||
/// use iced::canvas::{self, layer, Canvas, Drawable, Fill, Frame, Path};
|
|
||||||
/// use iced::Color;
|
|
||||||
///
|
|
||||||
/// // First, we define the data we need for drawing
|
|
||||||
/// #[derive(Debug)]
|
|
||||||
/// struct Circle {
|
|
||||||
/// radius: f32,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// // Then, we implement the `Drawable` trait
|
|
||||||
/// impl Drawable for Circle {
|
|
||||||
/// fn draw(&self, frame: &mut Frame) {
|
|
||||||
/// // We create a `Path` representing a simple circle
|
|
||||||
/// let circle = Path::new(|p| p.circle(frame.center(), self.radius));
|
|
||||||
///
|
|
||||||
/// // And fill it with some color
|
|
||||||
/// frame.fill(&circle, Fill::Color(Color::BLACK));
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// // We can use a `Cache` to avoid unnecessary re-tessellation
|
|
||||||
/// let cache: layer::Cache<Circle> = layer::Cache::new();
|
|
||||||
///
|
|
||||||
/// // Finally, we simply provide the data to our `Cache` and push the resulting
|
|
||||||
/// // layer into a `Canvas`
|
|
||||||
/// let canvas = Canvas::new()
|
|
||||||
/// .push(cache.with(&Circle { radius: 50.0 }));
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Canvas<'a> {
|
|
||||||
width: Length,
|
|
||||||
height: Length,
|
|
||||||
layers: Vec<Box<dyn Layer + 'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Canvas<'a> {
|
|
||||||
const DEFAULT_SIZE: u16 = 100;
|
|
||||||
|
|
||||||
/// Creates a new [`Canvas`] with no layers.
|
|
||||||
///
|
|
||||||
/// [`Canvas`]: struct.Canvas.html
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Canvas {
|
|
||||||
width: Length::Units(Self::DEFAULT_SIZE),
|
|
||||||
height: Length::Units(Self::DEFAULT_SIZE),
|
|
||||||
layers: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the width of the [`Canvas`].
|
|
||||||
///
|
|
||||||
/// [`Canvas`]: struct.Canvas.html
|
|
||||||
pub fn width(mut self, width: Length) -> Self {
|
|
||||||
self.width = width;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the height of the [`Canvas`].
|
|
||||||
///
|
|
||||||
/// [`Canvas`]: struct.Canvas.html
|
|
||||||
pub fn height(mut self, height: Length) -> Self {
|
|
||||||
self.height = height;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a [`Layer`] to the [`Canvas`].
|
|
||||||
///
|
|
||||||
/// It will be drawn on top of previous layers.
|
|
||||||
///
|
|
||||||
/// [`Layer`]: layer/trait.Layer.html
|
|
||||||
/// [`Canvas`]: struct.Canvas.html
|
|
||||||
pub fn push(mut self, layer: impl Layer + 'a) -> Self {
|
|
||||||
self.layers.push(Box::new(layer));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message> Widget<Message, Renderer> for Canvas<'a> {
|
|
||||||
fn width(&self) -> Length {
|
|
||||||
self.width
|
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self) -> Length {
|
|
||||||
self.height
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layout(
|
|
||||||
&self,
|
|
||||||
_renderer: &Renderer,
|
|
||||||
limits: &layout::Limits,
|
|
||||||
) -> layout::Node {
|
|
||||||
let limits = limits.width(self.width).height(self.height);
|
|
||||||
let size = limits.resolve(Size::ZERO);
|
|
||||||
|
|
||||||
layout::Node::new(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(
|
|
||||||
&self,
|
|
||||||
_renderer: &mut Renderer,
|
|
||||||
_defaults: &Defaults,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
_cursor_position: Point,
|
|
||||||
) -> (Primitive, MouseCursor) {
|
|
||||||
let bounds = layout.bounds();
|
|
||||||
let origin = Point::new(bounds.x, bounds.y);
|
|
||||||
let size = Size::new(bounds.width, bounds.height);
|
|
||||||
|
|
||||||
(
|
|
||||||
Primitive::Group {
|
|
||||||
primitives: self
|
|
||||||
.layers
|
|
||||||
.iter()
|
|
||||||
.map(|layer| Primitive::Cached {
|
|
||||||
origin,
|
|
||||||
cache: layer.draw(size),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
},
|
|
||||||
MouseCursor::Idle,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hash_layout(&self, state: &mut Hasher) {
|
|
||||||
std::any::TypeId::of::<Canvas<'static>>().hash(state);
|
|
||||||
|
|
||||||
self.width.hash(state);
|
|
||||||
self.height.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message> From<Canvas<'a>> for Element<'a, Message, Renderer>
|
|
||||||
where
|
|
||||||
Message: 'static,
|
|
||||||
{
|
|
||||||
fn from(canvas: Canvas<'a>) -> Element<'a, Message, Renderer> {
|
|
||||||
Element::new(canvas)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,180 +1,64 @@
|
||||||
use crate::{Renderer, Settings, Viewport};
|
use crate::{Backend, Renderer, Settings, Viewport};
|
||||||
|
|
||||||
|
use core::ffi::c_void;
|
||||||
use glow::HasContext;
|
use glow::HasContext;
|
||||||
|
use iced_graphics::Size;
|
||||||
use iced_native::mouse;
|
use iced_native::mouse;
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
|
||||||
|
|
||||||
/// A window graphics backend for iced powered by `glow`.
|
/// A window graphics backend for iced powered by `glow`.
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Compositor {
|
pub struct Compositor {
|
||||||
connection: surfman::Connection,
|
gl: glow::Context,
|
||||||
device: surfman::Device,
|
|
||||||
gl_context: surfman::Context,
|
|
||||||
gl: Option<glow::Context>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl iced_graphics::window::Compositor for Compositor {
|
impl iced_graphics::window::GLCompositor for Compositor {
|
||||||
type Settings = Settings;
|
type Settings = Settings;
|
||||||
type Renderer = Renderer;
|
type Renderer = Renderer;
|
||||||
type Surface = ();
|
|
||||||
type SwapChain = ();
|
|
||||||
|
|
||||||
fn new(_settings: Self::Settings) -> Self {
|
unsafe fn new(
|
||||||
let connection = surfman::Connection::new().expect("Create connection");
|
settings: Self::Settings,
|
||||||
|
loader_function: impl FnMut(&str) -> *const c_void,
|
||||||
|
) -> (Self, Self::Renderer) {
|
||||||
|
let gl = glow::Context::from_loader_function(loader_function);
|
||||||
|
|
||||||
let adapter = connection
|
gl.clear_color(1.0, 1.0, 1.0, 1.0);
|
||||||
.create_hardware_adapter()
|
|
||||||
.expect("Create adapter");
|
|
||||||
|
|
||||||
let mut device =
|
// Enable auto-conversion from/to sRGB
|
||||||
connection.create_device(&adapter).expect("Create device");
|
gl.enable(glow::FRAMEBUFFER_SRGB);
|
||||||
|
|
||||||
let context_descriptor = device
|
// Enable alpha blending
|
||||||
.create_context_descriptor(&surfman::ContextAttributes {
|
gl.enable(glow::BLEND);
|
||||||
version: surfman::GLVersion::new(3, 0),
|
gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
|
||||||
flags: surfman::ContextAttributeFlags::empty(),
|
|
||||||
})
|
|
||||||
.expect("Create context descriptor");
|
|
||||||
|
|
||||||
let gl_context = device
|
let renderer = Renderer::new(Backend::new(&gl, settings));
|
||||||
.create_context(&context_descriptor)
|
|
||||||
.expect("Create context");
|
|
||||||
|
|
||||||
Self {
|
(Self { gl }, renderer)
|
||||||
connection,
|
|
||||||
device,
|
|
||||||
gl_context,
|
|
||||||
gl: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_renderer(&mut self, settings: Settings) -> Renderer {
|
fn resize_viewport(&mut self, physical_size: Size<u32>) {
|
||||||
self.device
|
|
||||||
.make_context_current(&self.gl_context)
|
|
||||||
.expect("Make context current");
|
|
||||||
|
|
||||||
Renderer::new(crate::Backend::new(self.gl.as_ref().unwrap(), settings))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_surface<W: HasRawWindowHandle>(
|
|
||||||
&mut self,
|
|
||||||
window: &W,
|
|
||||||
) -> Self::Surface {
|
|
||||||
let native_widget = self
|
|
||||||
.connection
|
|
||||||
.create_native_widget_from_rwh(window.raw_window_handle())
|
|
||||||
.expect("Create widget");
|
|
||||||
|
|
||||||
let surface = self
|
|
||||||
.device
|
|
||||||
.create_surface(
|
|
||||||
&self.gl_context,
|
|
||||||
surfman::SurfaceAccess::GPUOnly,
|
|
||||||
surfman::SurfaceType::Widget { native_widget },
|
|
||||||
)
|
|
||||||
.expect("Create surface");
|
|
||||||
|
|
||||||
let surfman::SurfaceInfo { .. } = self.device.surface_info(&surface);
|
|
||||||
|
|
||||||
self.device
|
|
||||||
.bind_surface_to_context(&mut self.gl_context, surface)
|
|
||||||
.expect("Bind surface to context");
|
|
||||||
|
|
||||||
self.device
|
|
||||||
.make_context_current(&self.gl_context)
|
|
||||||
.expect("Make context current");
|
|
||||||
|
|
||||||
self.gl = Some(glow::Context::from_loader_function(|s| {
|
|
||||||
self.device.get_proc_address(&self.gl_context, s)
|
|
||||||
}));
|
|
||||||
|
|
||||||
//let mut framebuffer =
|
|
||||||
// skia_safe::gpu::gl::FramebufferInfo::from_fboid(framebuffer_object);
|
|
||||||
|
|
||||||
//framebuffer.format = gl::RGBA8;
|
|
||||||
|
|
||||||
//framebuffer
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_swap_chain(
|
|
||||||
&mut self,
|
|
||||||
_surface: &Self::Surface,
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
) -> Self::SwapChain {
|
|
||||||
let mut surface = self
|
|
||||||
.device
|
|
||||||
.unbind_surface_from_context(&mut self.gl_context)
|
|
||||||
.expect("Unbind surface")
|
|
||||||
.expect("Active surface");
|
|
||||||
|
|
||||||
self.device
|
|
||||||
.resize_surface(
|
|
||||||
&self.gl_context,
|
|
||||||
&mut surface,
|
|
||||||
euclid::Size2D::new(width as i32, height as i32),
|
|
||||||
)
|
|
||||||
.expect("Resize surface");
|
|
||||||
|
|
||||||
self.device
|
|
||||||
.bind_surface_to_context(&mut self.gl_context, surface)
|
|
||||||
.expect("Bind surface to context");
|
|
||||||
|
|
||||||
let gl = self.gl.as_ref().unwrap();
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl.viewport(0, 0, width as i32, height as i32);
|
self.gl.viewport(
|
||||||
gl.clear_color(1.0, 1.0, 1.0, 1.0);
|
0,
|
||||||
|
0,
|
||||||
// Enable auto-conversion from/to sRGB
|
physical_size.width as i32,
|
||||||
gl.enable(glow::FRAMEBUFFER_SRGB);
|
physical_size.height as i32,
|
||||||
|
);
|
||||||
// Enable alpha blending
|
|
||||||
gl.enable(glow::BLEND);
|
|
||||||
gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw<T: AsRef<str>>(
|
fn draw<T: AsRef<str>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut Self::Renderer,
|
renderer: &mut Self::Renderer,
|
||||||
swap_chain: &mut Self::SwapChain,
|
|
||||||
viewport: &Viewport,
|
viewport: &Viewport,
|
||||||
output: &<Self::Renderer as iced_native::Renderer>::Output,
|
output: &<Self::Renderer as iced_native::Renderer>::Output,
|
||||||
overlay: &[T],
|
overlay: &[T],
|
||||||
) -> mouse::Interaction {
|
) -> mouse::Interaction {
|
||||||
let gl = self.gl.as_ref().unwrap();
|
let gl = &self.gl;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl.clear(glow::COLOR_BUFFER_BIT);
|
gl.clear(glow::COLOR_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mouse = renderer.backend_mut().draw(gl, viewport, output, overlay);
|
renderer.backend_mut().draw(gl, viewport, output, overlay)
|
||||||
|
|
||||||
{
|
|
||||||
let mut surface = self
|
|
||||||
.device
|
|
||||||
.unbind_surface_from_context(&mut self.gl_context)
|
|
||||||
.expect("Unbind surface")
|
|
||||||
.expect("Active surface");
|
|
||||||
|
|
||||||
self.device
|
|
||||||
.present_surface(&self.gl_context, &mut surface)
|
|
||||||
.expect("Present surface");
|
|
||||||
|
|
||||||
self.device
|
|
||||||
.bind_surface_to_context(&mut self.gl_context, surface)
|
|
||||||
.expect("Bind surface to context");
|
|
||||||
}
|
|
||||||
|
|
||||||
mouse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Compositor {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.device
|
|
||||||
.destroy_context(&mut self.gl_context)
|
|
||||||
.expect("Destroy context");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
[package]
|
||||||
|
name = "iced_glutin"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
description = "A glutin runtime for Iced"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/hecrj/iced"
|
||||||
|
documentation = "https://docs.rs/iced_glutin"
|
||||||
|
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
||||||
|
categories = ["gui"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
debug = ["iced_winit/debug"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
glutin = "0.24"
|
||||||
|
|
||||||
|
[dependencies.iced_native]
|
||||||
|
version = "0.2"
|
||||||
|
path = "../native"
|
||||||
|
|
||||||
|
[dependencies.iced_winit]
|
||||||
|
version = "0.1"
|
||||||
|
path = "../winit"
|
||||||
|
|
||||||
|
[dependencies.iced_graphics]
|
||||||
|
version = "0.1"
|
||||||
|
path = "../graphics"
|
||||||
|
features = ["opengl"]
|
|
@ -0,0 +1,27 @@
|
||||||
|
# `iced_winit`
|
||||||
|
[![Documentation](https://docs.rs/iced_winit/badge.svg)][documentation]
|
||||||
|
[![Crates.io](https://img.shields.io/crates/v/iced_winit.svg)](https://crates.io/crates/iced_winit)
|
||||||
|
[![License](https://img.shields.io/crates/l/iced_winit.svg)](https://github.com/hecrj/iced/blob/master/LICENSE)
|
||||||
|
[![project chat](https://img.shields.io/badge/chat-on_zulip-brightgreen.svg)](https://iced.zulipchat.com)
|
||||||
|
|
||||||
|
`iced_winit` offers some convenient abstractions on top of [`iced_native`] to quickstart development when using [`winit`].
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
![iced_winit](../docs/graphs/winit.png)
|
||||||
|
|
||||||
|
[documentation]: https://docs.rs/iced_winit
|
||||||
|
[`iced_native`]: ../native
|
||||||
|
[`winit`]: https://github.com/rust-windowing/winit
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
Add `iced_winit` as a dependency in your `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
iced_winit = "0.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
||||||
|
you want to learn about a specific release, check out [the release list].
|
||||||
|
|
||||||
|
[the release list]: https://github.com/hecrj/iced/releases
|
|
@ -0,0 +1,429 @@
|
||||||
|
use crate::{
|
||||||
|
mouse, Cache, Command, Element, Executor, Runtime, Size, Subscription,
|
||||||
|
UserInterface,
|
||||||
|
};
|
||||||
|
use iced_graphics::window;
|
||||||
|
use iced_graphics::Viewport;
|
||||||
|
use iced_winit::conversion;
|
||||||
|
use iced_winit::{Clipboard, Debug, Mode, Proxy, Settings};
|
||||||
|
|
||||||
|
/// An interactive, native cross-platform application.
|
||||||
|
///
|
||||||
|
/// This trait is the main entrypoint of Iced. Once implemented, you can run
|
||||||
|
/// your GUI application by simply calling [`run`](#method.run). It will run in
|
||||||
|
/// its own window.
|
||||||
|
///
|
||||||
|
/// An [`Application`](trait.Application.html) can execute asynchronous actions
|
||||||
|
/// by returning a [`Command`](struct.Command.html) in some of its methods.
|
||||||
|
///
|
||||||
|
/// When using an [`Application`] with the `debug` feature enabled, a debug view
|
||||||
|
/// can be toggled by pressing `F12`.
|
||||||
|
pub trait Application: Sized {
|
||||||
|
/// The graphics backend to use to draw the [`Application`].
|
||||||
|
///
|
||||||
|
/// [`Application`]: trait.Application.html
|
||||||
|
type Compositor: window::GLCompositor;
|
||||||
|
|
||||||
|
/// The [`Executor`] that will run commands and subscriptions.
|
||||||
|
///
|
||||||
|
/// [`Executor`]: trait.Executor.html
|
||||||
|
type Executor: Executor;
|
||||||
|
|
||||||
|
/// The type of __messages__ your [`Application`] will produce.
|
||||||
|
///
|
||||||
|
/// [`Application`]: trait.Application.html
|
||||||
|
type Message: std::fmt::Debug + Send;
|
||||||
|
|
||||||
|
/// The data needed to initialize your [`Application`].
|
||||||
|
///
|
||||||
|
/// [`Application`]: trait.Application.html
|
||||||
|
type Flags;
|
||||||
|
|
||||||
|
/// Initializes the [`Application`] with the flags provided to
|
||||||
|
/// [`run`] as part of the [`Settings`].
|
||||||
|
///
|
||||||
|
/// Here is where you should return the initial state of your app.
|
||||||
|
///
|
||||||
|
/// Additionally, you can return a [`Command`](struct.Command.html) if you
|
||||||
|
/// need to perform some async action in the background on startup. This is
|
||||||
|
/// useful if you want to load state from a file, perform an initial HTTP
|
||||||
|
/// request, etc.
|
||||||
|
///
|
||||||
|
/// [`Application`]: trait.Application.html
|
||||||
|
/// [`run`]: #method.run.html
|
||||||
|
/// [`Settings`]: struct.Settings.html
|
||||||
|
fn new(flags: Self::Flags) -> (Self, Command<Self::Message>);
|
||||||
|
|
||||||
|
/// Returns the current title of the [`Application`].
|
||||||
|
///
|
||||||
|
/// This title can be dynamic! The runtime will automatically update the
|
||||||
|
/// title of your application when necessary.
|
||||||
|
///
|
||||||
|
/// [`Application`]: trait.Application.html
|
||||||
|
fn title(&self) -> String;
|
||||||
|
|
||||||
|
/// Handles a __message__ and updates the state of the [`Application`].
|
||||||
|
///
|
||||||
|
/// This is where you define your __update logic__. All the __messages__,
|
||||||
|
/// produced by either user interactions or commands, will be handled by
|
||||||
|
/// this method.
|
||||||
|
///
|
||||||
|
/// Any [`Command`] returned will be executed immediately in the background.
|
||||||
|
///
|
||||||
|
/// [`Application`]: trait.Application.html
|
||||||
|
/// [`Command`]: struct.Command.html
|
||||||
|
fn update(&mut self, message: Self::Message) -> Command<Self::Message>;
|
||||||
|
|
||||||
|
/// Returns the event `Subscription` for the current state of the
|
||||||
|
/// application.
|
||||||
|
///
|
||||||
|
/// The messages produced by the `Subscription` will be handled by
|
||||||
|
/// [`update`](#tymethod.update).
|
||||||
|
///
|
||||||
|
/// A `Subscription` will be kept alive as long as you keep returning it!
|
||||||
|
///
|
||||||
|
/// By default, it returns an empty subscription.
|
||||||
|
fn subscription(&self) -> Subscription<Self::Message> {
|
||||||
|
Subscription::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the widgets to display in the [`Application`].
|
||||||
|
///
|
||||||
|
/// These widgets can produce __messages__ based on user interaction.
|
||||||
|
///
|
||||||
|
/// [`Application`]: trait.Application.html
|
||||||
|
fn view(
|
||||||
|
&mut self,
|
||||||
|
) -> Element<
|
||||||
|
'_,
|
||||||
|
Self::Message,
|
||||||
|
<Self::Compositor as window::GLCompositor>::Renderer,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Returns the current [`Application`] mode.
|
||||||
|
///
|
||||||
|
/// The runtime will automatically transition your application if a new mode
|
||||||
|
/// is returned.
|
||||||
|
///
|
||||||
|
/// By default, an application will run in windowed mode.
|
||||||
|
///
|
||||||
|
/// [`Application`]: trait.Application.html
|
||||||
|
fn mode(&self) -> Mode {
|
||||||
|
Mode::Windowed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs the [`Application`] with the provided [`Settings`].
|
||||||
|
///
|
||||||
|
/// On native platforms, this method will take control of the current thread
|
||||||
|
/// and __will NOT return__.
|
||||||
|
///
|
||||||
|
/// It should probably be that last thing you call in your `main` function.
|
||||||
|
///
|
||||||
|
/// [`Application`]: trait.Application.html
|
||||||
|
/// [`Settings`]: struct.Settings.html
|
||||||
|
fn run(
|
||||||
|
settings: Settings<Self::Flags>,
|
||||||
|
backend_settings: <Self::Compositor as window::GLCompositor>::Settings,
|
||||||
|
) where
|
||||||
|
Self: 'static,
|
||||||
|
{
|
||||||
|
use glutin::{
|
||||||
|
event::{self, WindowEvent},
|
||||||
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
ContextBuilder,
|
||||||
|
};
|
||||||
|
use iced_graphics::window::GLCompositor as _;
|
||||||
|
|
||||||
|
let mut debug = Debug::new();
|
||||||
|
|
||||||
|
debug.startup_started();
|
||||||
|
let event_loop = EventLoop::with_user_event();
|
||||||
|
let mut external_messages = Vec::new();
|
||||||
|
|
||||||
|
let mut runtime = {
|
||||||
|
let executor = Self::Executor::new().expect("Create executor");
|
||||||
|
|
||||||
|
Runtime::new(executor, Proxy::new(event_loop.create_proxy()))
|
||||||
|
};
|
||||||
|
|
||||||
|
let flags = settings.flags;
|
||||||
|
let (mut application, init_command) =
|
||||||
|
runtime.enter(|| Self::new(flags));
|
||||||
|
runtime.spawn(init_command);
|
||||||
|
|
||||||
|
let subscription = application.subscription();
|
||||||
|
runtime.track(subscription);
|
||||||
|
|
||||||
|
let mut title = application.title();
|
||||||
|
let mut mode = application.mode();
|
||||||
|
|
||||||
|
let context = {
|
||||||
|
let window_builder = settings.window.into_builder(
|
||||||
|
&title,
|
||||||
|
mode,
|
||||||
|
event_loop.primary_monitor(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let context = ContextBuilder::new()
|
||||||
|
.with_vsync(true)
|
||||||
|
.build_windowed(window_builder, &event_loop)
|
||||||
|
.expect("Open window");
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
unsafe {
|
||||||
|
context.make_current().expect("Make OpenGL context current")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let physical_size = context.window().inner_size();
|
||||||
|
let mut viewport = Viewport::with_physical_size(
|
||||||
|
Size::new(physical_size.width, physical_size.height),
|
||||||
|
context.window().scale_factor(),
|
||||||
|
);
|
||||||
|
let mut resized = false;
|
||||||
|
|
||||||
|
let clipboard = Clipboard::new(&context.window());
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
let (mut compositor, mut renderer) = unsafe {
|
||||||
|
Self::Compositor::new(backend_settings, |address| {
|
||||||
|
context.get_proc_address(address)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let user_interface = build_user_interface(
|
||||||
|
&mut application,
|
||||||
|
Cache::default(),
|
||||||
|
&mut renderer,
|
||||||
|
viewport.logical_size(),
|
||||||
|
&mut debug,
|
||||||
|
);
|
||||||
|
|
||||||
|
debug.draw_started();
|
||||||
|
let mut primitive = user_interface.draw(&mut renderer);
|
||||||
|
debug.draw_finished();
|
||||||
|
|
||||||
|
let mut cache = Some(user_interface.into_cache());
|
||||||
|
let mut events = Vec::new();
|
||||||
|
let mut mouse_interaction = mouse::Interaction::default();
|
||||||
|
let mut modifiers = glutin::event::ModifiersState::default();
|
||||||
|
debug.startup_finished();
|
||||||
|
|
||||||
|
context.window().request_redraw();
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| match event {
|
||||||
|
event::Event::MainEventsCleared => {
|
||||||
|
if events.is_empty() && external_messages.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut user_interface = build_user_interface(
|
||||||
|
&mut application,
|
||||||
|
cache.take().unwrap(),
|
||||||
|
&mut renderer,
|
||||||
|
viewport.logical_size(),
|
||||||
|
&mut debug,
|
||||||
|
);
|
||||||
|
|
||||||
|
debug.event_processing_started();
|
||||||
|
events
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.for_each(|event| runtime.broadcast(event));
|
||||||
|
|
||||||
|
let mut messages = user_interface.update(
|
||||||
|
events.drain(..),
|
||||||
|
clipboard
|
||||||
|
.as_ref()
|
||||||
|
.map(|c| c as &dyn iced_native::Clipboard),
|
||||||
|
&renderer,
|
||||||
|
);
|
||||||
|
messages.extend(external_messages.drain(..));
|
||||||
|
debug.event_processing_finished();
|
||||||
|
|
||||||
|
if messages.is_empty() {
|
||||||
|
debug.draw_started();
|
||||||
|
primitive = user_interface.draw(&mut renderer);
|
||||||
|
debug.draw_finished();
|
||||||
|
|
||||||
|
cache = Some(user_interface.into_cache());
|
||||||
|
} else {
|
||||||
|
// When there are messages, we are forced to rebuild twice
|
||||||
|
// for now :^)
|
||||||
|
let temp_cache = user_interface.into_cache();
|
||||||
|
|
||||||
|
for message in messages {
|
||||||
|
debug.log_message(&message);
|
||||||
|
|
||||||
|
debug.update_started();
|
||||||
|
let command =
|
||||||
|
runtime.enter(|| application.update(message));
|
||||||
|
runtime.spawn(command);
|
||||||
|
debug.update_finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
let subscription = application.subscription();
|
||||||
|
runtime.track(subscription);
|
||||||
|
|
||||||
|
// Update window title
|
||||||
|
let new_title = application.title();
|
||||||
|
|
||||||
|
if title != new_title {
|
||||||
|
context.window().set_title(&new_title);
|
||||||
|
|
||||||
|
title = new_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update window mode
|
||||||
|
let new_mode = application.mode();
|
||||||
|
|
||||||
|
if mode != new_mode {
|
||||||
|
context.window().set_fullscreen(
|
||||||
|
conversion::fullscreen(
|
||||||
|
context.window().current_monitor(),
|
||||||
|
new_mode,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
mode = new_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
let user_interface = build_user_interface(
|
||||||
|
&mut application,
|
||||||
|
temp_cache,
|
||||||
|
&mut renderer,
|
||||||
|
viewport.logical_size(),
|
||||||
|
&mut debug,
|
||||||
|
);
|
||||||
|
|
||||||
|
debug.draw_started();
|
||||||
|
primitive = user_interface.draw(&mut renderer);
|
||||||
|
debug.draw_finished();
|
||||||
|
|
||||||
|
cache = Some(user_interface.into_cache());
|
||||||
|
}
|
||||||
|
|
||||||
|
context.window().request_redraw();
|
||||||
|
}
|
||||||
|
event::Event::UserEvent(message) => {
|
||||||
|
external_messages.push(message);
|
||||||
|
}
|
||||||
|
event::Event::RedrawRequested(_) => {
|
||||||
|
debug.render_started();
|
||||||
|
|
||||||
|
if resized {
|
||||||
|
let physical_size = viewport.physical_size();
|
||||||
|
|
||||||
|
context.resize(glutin::dpi::PhysicalSize {
|
||||||
|
width: physical_size.width,
|
||||||
|
height: physical_size.height,
|
||||||
|
});
|
||||||
|
compositor.resize_viewport(physical_size);
|
||||||
|
|
||||||
|
resized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_mouse_interaction = compositor.draw(
|
||||||
|
&mut renderer,
|
||||||
|
&viewport,
|
||||||
|
&primitive,
|
||||||
|
&debug.overlay(),
|
||||||
|
);
|
||||||
|
|
||||||
|
context.swap_buffers().expect("Swap buffers");
|
||||||
|
debug.render_finished();
|
||||||
|
|
||||||
|
if new_mouse_interaction != mouse_interaction {
|
||||||
|
context.window().set_cursor_icon(
|
||||||
|
conversion::mouse_interaction(new_mouse_interaction),
|
||||||
|
);
|
||||||
|
|
||||||
|
mouse_interaction = new_mouse_interaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle animations!
|
||||||
|
// Maybe we can use `ControlFlow::WaitUntil` for this.
|
||||||
|
}
|
||||||
|
event::Event::WindowEvent {
|
||||||
|
event: window_event,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
match window_event {
|
||||||
|
WindowEvent::Resized(new_size) => {
|
||||||
|
let size = Size::new(new_size.width, new_size.height);
|
||||||
|
|
||||||
|
viewport = Viewport::with_physical_size(
|
||||||
|
size,
|
||||||
|
context.window().scale_factor(),
|
||||||
|
);
|
||||||
|
resized = true;
|
||||||
|
}
|
||||||
|
WindowEvent::CloseRequested => {
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
WindowEvent::ModifiersChanged(new_modifiers) => {
|
||||||
|
modifiers = new_modifiers;
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
WindowEvent::KeyboardInput {
|
||||||
|
input:
|
||||||
|
glutin::event::KeyboardInput {
|
||||||
|
virtual_keycode:
|
||||||
|
Some(glutin::event::VirtualKeyCode::Q),
|
||||||
|
state: glutin::event::ElementState::Pressed,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} if modifiers.logo() => {
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
WindowEvent::KeyboardInput {
|
||||||
|
input:
|
||||||
|
glutin::event::KeyboardInput {
|
||||||
|
virtual_keycode:
|
||||||
|
Some(glutin::event::VirtualKeyCode::F12),
|
||||||
|
state: glutin::event::ElementState::Pressed,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} => debug.toggle(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(event) = conversion::window_event(
|
||||||
|
&window_event,
|
||||||
|
viewport.scale_factor(),
|
||||||
|
modifiers,
|
||||||
|
) {
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
*control_flow = ControlFlow::Wait;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_user_interface<'a, A: Application>(
|
||||||
|
application: &'a mut A,
|
||||||
|
cache: Cache,
|
||||||
|
renderer: &mut <A::Compositor as window::GLCompositor>::Renderer,
|
||||||
|
size: Size,
|
||||||
|
debug: &mut Debug,
|
||||||
|
) -> UserInterface<
|
||||||
|
'a,
|
||||||
|
A::Message,
|
||||||
|
<A::Compositor as window::GLCompositor>::Renderer,
|
||||||
|
> {
|
||||||
|
debug.view_started();
|
||||||
|
let view = application.view();
|
||||||
|
debug.view_finished();
|
||||||
|
|
||||||
|
debug.layout_started();
|
||||||
|
let user_interface = UserInterface::build(view, size, cache, renderer);
|
||||||
|
debug.layout_finished();
|
||||||
|
|
||||||
|
user_interface
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
//#![deny(missing_docs)]
|
||||||
|
#![deny(missing_debug_implementations)]
|
||||||
|
#![deny(unused_results)]
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![forbid(rust_2018_idioms)]
|
||||||
|
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use iced_native::*;
|
||||||
|
|
||||||
|
mod application;
|
||||||
|
|
||||||
|
pub use application::Application;
|
||||||
|
|
||||||
|
pub use iced_winit::settings::{self, Settings};
|
||||||
|
pub use iced_winit::Mode;
|
|
@ -9,6 +9,7 @@ canvas = ["lyon"]
|
||||||
font-source = ["font-kit"]
|
font-source = ["font-kit"]
|
||||||
font-fallback = []
|
font-fallback = []
|
||||||
font-icons = []
|
font-icons = []
|
||||||
|
opengl = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = "1.2"
|
bytemuck = "1.2"
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
Vector, VerticalAlignment, Viewport,
|
Vector, VerticalAlignment, Viewport,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct Layer<'a> {
|
pub struct Layer<'a> {
|
||||||
pub bounds: Rectangle,
|
pub bounds: Rectangle,
|
||||||
pub quads: Vec<Quad>,
|
pub quads: Vec<Quad>,
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
mod compositor;
|
mod compositor;
|
||||||
|
|
||||||
|
#[cfg(feature = "opengl")]
|
||||||
|
mod gl_compositor;
|
||||||
|
|
||||||
pub use compositor::Compositor;
|
pub use compositor::Compositor;
|
||||||
|
|
||||||
|
#[cfg(feature = "opengl")]
|
||||||
|
pub use gl_compositor::GLCompositor;
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
use crate::{Size, Viewport};
|
||||||
|
use iced_native::mouse;
|
||||||
|
|
||||||
|
use core::ffi::c_void;
|
||||||
|
|
||||||
|
pub trait GLCompositor: Sized {
|
||||||
|
type Renderer: iced_native::Renderer;
|
||||||
|
type Settings: Default;
|
||||||
|
|
||||||
|
unsafe fn new(
|
||||||
|
settings: Self::Settings,
|
||||||
|
loader_function: impl FnMut(&str) -> *const c_void,
|
||||||
|
) -> (Self, Self::Renderer);
|
||||||
|
|
||||||
|
fn resize_viewport(&mut self, physical_size: Size<u32>);
|
||||||
|
|
||||||
|
fn draw<T: AsRef<str>>(
|
||||||
|
&mut self,
|
||||||
|
renderer: &mut Self::Renderer,
|
||||||
|
viewport: &Viewport,
|
||||||
|
output: &<Self::Renderer as iced_native::Renderer>::Output,
|
||||||
|
overlay: &[T],
|
||||||
|
) -> mouse::Interaction;
|
||||||
|
}
|
|
@ -188,19 +188,19 @@ pub trait Application: Sized {
|
||||||
{
|
{
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
let wgpu_settings = iced_wgpu::Settings {
|
let glow_settings = iced_glow::Settings {
|
||||||
default_font: settings.default_font,
|
default_font: settings.default_font,
|
||||||
antialiasing: if settings.antialiasing {
|
antialiasing: if settings.antialiasing {
|
||||||
Some(iced_wgpu::settings::Antialiasing::MSAAx4)
|
Some(iced_glow::settings::Antialiasing::MSAAx4)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
..iced_wgpu::Settings::default()
|
..iced_glow::Settings::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
<Instance<Self> as iced_winit::Application>::run(
|
<Instance<Self> as iced_glutin::Application>::run(
|
||||||
settings.into(),
|
settings.into(),
|
||||||
wgpu_settings,
|
glow_settings,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,11 +212,11 @@ pub trait Application: Sized {
|
||||||
struct Instance<A: Application>(A);
|
struct Instance<A: Application>(A);
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
impl<A> iced_winit::Application for Instance<A>
|
impl<A> iced_glutin::Application for Instance<A>
|
||||||
where
|
where
|
||||||
A: Application,
|
A: Application,
|
||||||
{
|
{
|
||||||
type Compositor = iced_wgpu::window::Compositor;
|
type Compositor = iced_glow::window::Compositor;
|
||||||
type Executor = A::Executor;
|
type Executor = A::Executor;
|
||||||
type Flags = A::Flags;
|
type Flags = A::Flags;
|
||||||
type Message = A::Message;
|
type Message = A::Message;
|
||||||
|
@ -231,10 +231,10 @@ where
|
||||||
self.0.title()
|
self.0.title()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mode(&self) -> iced_winit::Mode {
|
fn mode(&self) -> iced_glutin::Mode {
|
||||||
match self.0.mode() {
|
match self.0.mode() {
|
||||||
window::Mode::Windowed => iced_winit::Mode::Windowed,
|
window::Mode::Windowed => iced_glutin::Mode::Windowed,
|
||||||
window::Mode::Fullscreen => iced_winit::Mode::Fullscreen,
|
window::Mode::Fullscreen => iced_glutin::Mode::Fullscreen,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
/// This is an alias of an `iced_native` element with a default `Renderer`.
|
/// This is an alias of an `iced_native` element with a default `Renderer`.
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub type Element<'a, Message> =
|
pub type Element<'a, Message> =
|
||||||
iced_winit::Element<'a, Message, iced_wgpu::Renderer>;
|
iced_glutin::Element<'a, Message, iced_glow::Renderer>;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub use iced_web::Element;
|
pub use iced_web::Element;
|
||||||
|
|
|
@ -207,7 +207,7 @@ pub use sandbox::Sandbox;
|
||||||
pub use settings::Settings;
|
pub use settings::Settings;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use iced_winit as runtime;
|
use iced_glutin as runtime;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use iced_web as runtime;
|
use iced_web as runtime;
|
||||||
|
|
|
@ -51,10 +51,10 @@ impl<Flags> Settings<Flags> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
impl<Flags> From<Settings<Flags>> for iced_winit::Settings<Flags> {
|
impl<Flags> From<Settings<Flags>> for iced_glutin::Settings<Flags> {
|
||||||
fn from(settings: Settings<Flags>) -> iced_winit::Settings<Flags> {
|
fn from(settings: Settings<Flags>) -> iced_glutin::Settings<Flags> {
|
||||||
iced_winit::Settings {
|
iced_glutin::Settings {
|
||||||
window: iced_winit::settings::Window {
|
window: iced_glutin::settings::Window {
|
||||||
size: settings.window.size,
|
size: settings.window.size,
|
||||||
resizable: settings.window.resizable,
|
resizable: settings.window.resizable,
|
||||||
decorations: settings.window.decorations,
|
decorations: settings.window.decorations,
|
||||||
|
|
|
@ -18,29 +18,27 @@
|
||||||
//! [`text_input::State`]: text_input/struct.State.html
|
//! [`text_input::State`]: text_input/struct.State.html
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
mod platform {
|
mod platform {
|
||||||
pub use iced_wgpu::widget::{
|
pub use iced_glow::widget::{
|
||||||
button, checkbox, container, pane_grid, progress_bar, radio,
|
button, checkbox, container, pane_grid, progress_bar, radio,
|
||||||
scrollable, slider, text_input, Text,
|
scrollable, slider, text_input, Column, Row, Space, Text,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "canvas")]
|
#[cfg(feature = "canvas")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))]
|
||||||
pub use iced_wgpu::widget::canvas;
|
pub use iced_glow::widget::canvas;
|
||||||
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
|
||||||
pub mod image {
|
pub mod image {
|
||||||
//! Display images in your user interface.
|
//! Display images in your user interface.
|
||||||
pub use iced_winit::image::{Handle, Image};
|
pub use iced_glutin::image::{Handle, Image};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "svg")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "svg")))]
|
||||||
pub mod svg {
|
pub mod svg {
|
||||||
//! Display vector graphics in your user interface.
|
//! Display vector graphics in your user interface.
|
||||||
pub use iced_winit::svg::{Handle, Svg};
|
pub use iced_glutin::svg::{Handle, Svg};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use iced_winit::Space;
|
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use {
|
pub use {
|
||||||
button::Button, checkbox::Checkbox, container::Container, image::Image,
|
button::Button, checkbox::Checkbox, container::Container, image::Image,
|
||||||
|
@ -52,18 +50,6 @@ mod platform {
|
||||||
#[cfg(feature = "canvas")]
|
#[cfg(feature = "canvas")]
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use canvas::Canvas;
|
pub use canvas::Canvas;
|
||||||
|
|
||||||
/// A container that distributes its contents vertically.
|
|
||||||
///
|
|
||||||
/// This is an alias of an `iced_native` column with a default `Renderer`.
|
|
||||||
pub type Column<'a, Message> =
|
|
||||||
iced_winit::Column<'a, Message, iced_wgpu::Renderer>;
|
|
||||||
|
|
||||||
/// A container that distributes its contents horizontally.
|
|
||||||
///
|
|
||||||
/// This is an alias of an `iced_native` row with a default `Renderer`.
|
|
||||||
pub type Row<'a, Message> =
|
|
||||||
iced_winit::Row<'a, Message, iced_wgpu::Renderer>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
|
|
@ -129,7 +129,6 @@ pub trait Application: Sized {
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{self, WindowEvent},
|
event::{self, WindowEvent},
|
||||||
event_loop::{ControlFlow, EventLoop},
|
event_loop::{ControlFlow, EventLoop},
|
||||||
window::WindowBuilder,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut debug = Debug::new();
|
let mut debug = Debug::new();
|
||||||
|
@ -155,32 +154,11 @@ pub trait Application: Sized {
|
||||||
let mut title = application.title();
|
let mut title = application.title();
|
||||||
let mut mode = application.mode();
|
let mut mode = application.mode();
|
||||||
|
|
||||||
let window = {
|
let window = settings
|
||||||
let mut window_builder = WindowBuilder::new();
|
.window
|
||||||
|
.into_builder(&title, mode, event_loop.primary_monitor())
|
||||||
let (width, height) = settings.window.size;
|
.build(&event_loop)
|
||||||
|
.expect("Open window");
|
||||||
window_builder = window_builder
|
|
||||||
.with_title(&title)
|
|
||||||
.with_inner_size(winit::dpi::LogicalSize { width, height })
|
|
||||||
.with_resizable(settings.window.resizable)
|
|
||||||
.with_decorations(settings.window.decorations)
|
|
||||||
.with_fullscreen(conversion::fullscreen(
|
|
||||||
event_loop.primary_monitor(),
|
|
||||||
mode,
|
|
||||||
));
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
{
|
|
||||||
use winit::platform::windows::WindowBuilderExtWindows;
|
|
||||||
|
|
||||||
if let Some(parent) = settings.window.platform_specific.parent {
|
|
||||||
window_builder = window_builder.with_parent_window(parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window_builder.build(&event_loop).expect("Open window")
|
|
||||||
};
|
|
||||||
|
|
||||||
let physical_size = window.inner_size();
|
let physical_size = window.inner_size();
|
||||||
let mut viewport = Viewport::with_physical_size(
|
let mut viewport = Viewport::with_physical_size(
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
//! [`winit`]: https://github.com/rust-windowing/winit
|
//! [`winit`]: https://github.com/rust-windowing/winit
|
||||||
//! [`Application`]: trait.Application.html
|
//! [`Application`]: trait.Application.html
|
||||||
//! [`conversion`]: conversion
|
//! [`conversion`]: conversion
|
||||||
#![deny(missing_docs)]
|
//#![deny(missing_docs)]
|
||||||
#![deny(missing_debug_implementations)]
|
#![deny(missing_debug_implementations)]
|
||||||
#![deny(unused_results)]
|
#![deny(unused_results)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
@ -44,8 +44,7 @@ mod debug;
|
||||||
|
|
||||||
pub use application::Application;
|
pub use application::Application;
|
||||||
pub use clipboard::Clipboard;
|
pub use clipboard::Clipboard;
|
||||||
|
pub use debug::Debug;
|
||||||
pub use mode::Mode;
|
pub use mode::Mode;
|
||||||
|
pub use proxy::Proxy;
|
||||||
pub use settings::Settings;
|
pub use settings::Settings;
|
||||||
|
|
||||||
use debug::Debug;
|
|
||||||
use proxy::Proxy;
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use iced_native::futures::{
|
||||||
};
|
};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Proxy<Message: 'static> {
|
pub struct Proxy<Message: 'static> {
|
||||||
raw: winit::event_loop::EventLoopProxy<Message>,
|
raw: winit::event_loop::EventLoopProxy<Message>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,11 @@ mod platform;
|
||||||
|
|
||||||
pub use platform::PlatformSpecific;
|
pub use platform::PlatformSpecific;
|
||||||
|
|
||||||
|
use crate::conversion;
|
||||||
|
use crate::Mode;
|
||||||
|
use winit::monitor::MonitorHandle;
|
||||||
|
use winit::window::WindowBuilder;
|
||||||
|
|
||||||
/// The settings of an application.
|
/// The settings of an application.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||||
pub struct Settings<Flags> {
|
pub struct Settings<Flags> {
|
||||||
|
@ -38,6 +43,37 @@ pub struct Window {
|
||||||
pub platform_specific: platform::PlatformSpecific,
|
pub platform_specific: platform::PlatformSpecific,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Window {
|
||||||
|
pub fn into_builder(
|
||||||
|
self,
|
||||||
|
title: &str,
|
||||||
|
mode: Mode,
|
||||||
|
primary_monitor: MonitorHandle,
|
||||||
|
) -> WindowBuilder {
|
||||||
|
let mut window_builder = WindowBuilder::new();
|
||||||
|
|
||||||
|
let (width, height) = self.size;
|
||||||
|
|
||||||
|
window_builder = window_builder
|
||||||
|
.with_title(title)
|
||||||
|
.with_inner_size(winit::dpi::LogicalSize { width, height })
|
||||||
|
.with_resizable(self.resizable)
|
||||||
|
.with_decorations(self.decorations)
|
||||||
|
.with_fullscreen(conversion::fullscreen(primary_monitor, mode));
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
use winit::platform::windows::WindowBuilderExtWindows;
|
||||||
|
|
||||||
|
if let Some(parent) = self.platform_specific.parent {
|
||||||
|
window_builder = window_builder.with_parent_window(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window_builder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Window {
|
impl Default for Window {
|
||||||
fn default() -> Window {
|
fn default() -> Window {
|
||||||
Window {
|
Window {
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
pub struct Size {
|
|
||||||
physical: winit::dpi::PhysicalSize<u32>,
|
|
||||||
logical: winit::dpi::LogicalSize<f64>,
|
|
||||||
scale_factor: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Size {
|
|
||||||
pub fn new(
|
|
||||||
physical: winit::dpi::PhysicalSize<u32>,
|
|
||||||
scale_factor: f64,
|
|
||||||
) -> Size {
|
|
||||||
Size {
|
|
||||||
logical: physical.to_logical(scale_factor),
|
|
||||||
physical,
|
|
||||||
scale_factor,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn physical(&self) -> winit::dpi::PhysicalSize<u32> {
|
|
||||||
self.physical
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn logical(&self) -> winit::dpi::LogicalSize<f64> {
|
|
||||||
self.logical
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scale_factor(&self) -> f64 {
|
|
||||||
self.scale_factor
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue