summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/src/length.rs6
-rw-r--r--core/src/point.rs12
-rw-r--r--native/src/renderer/null.rs9
-rw-r--r--native/src/size.rs12
-rw-r--r--native/src/widget/image.rs1
-rw-r--r--native/src/widget/scrollable.rs175
-rw-r--r--src/settings.rs6
-rw-r--r--web/CHANGELOG.md2
-rw-r--r--web/src/lib.rs42
-rw-r--r--wgpu/Cargo.toml4
-rw-r--r--wgpu/fonts/Lato-Regular.ttfbin0 -> 75136 bytes
-rw-r--r--wgpu/fonts/OFL.txt93
-rw-r--r--wgpu/src/image.rs2
-rw-r--r--wgpu/src/quad.rs2
-rw-r--r--wgpu/src/renderer.rs2
-rw-r--r--wgpu/src/renderer/widget/scrollable.rs120
-rw-r--r--wgpu/src/renderer/widget/text_input.rs2
-rw-r--r--wgpu/src/text.rs46
-rw-r--r--winit/Cargo.toml3
-rw-r--r--winit/src/application.rs54
-rw-r--r--winit/src/debug/basic.rs2
-rw-r--r--winit/src/settings/mod.rs (renamed from winit/src/settings.rs)14
-rw-r--r--winit/src/settings/not_windows.rs6
-rw-r--r--winit/src/settings/windows.rs9
24 files changed, 456 insertions, 168 deletions
diff --git a/core/src/length.rs b/core/src/length.rs
index 63ba6207..10873e89 100644
--- a/core/src/length.rs
+++ b/core/src/length.rs
@@ -27,3 +27,9 @@ impl Length {
}
}
}
+
+impl From<u16> for Length {
+ fn from(units: u16) -> Self {
+ Length::Units(units)
+ }
+}
diff --git a/core/src/point.rs b/core/src/point.rs
index 183998dd..47c8b142 100644
--- a/core/src/point.rs
+++ b/core/src/point.rs
@@ -19,6 +19,18 @@ impl Point {
}
}
+impl From<[f32; 2]> for Point {
+ fn from([x, y]: [f32; 2]) -> Self {
+ Point { x, y }
+ }
+}
+
+impl From<[u16; 2]> for Point {
+ fn from([x, y]: [u16; 2]) -> Self {
+ Point::new(x.into(), y.into())
+ }
+}
+
impl std::ops::Add<Vector> for Point {
type Output = Self;
diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs
index 182f033a..da0e5159 100644
--- a/native/src/renderer/null.rs
+++ b/native/src/renderer/null.rs
@@ -61,13 +61,13 @@ impl text::Renderer for Null {
}
impl scrollable::Renderer for Null {
- fn is_mouse_over_scrollbar(
+ fn scrollbar(
&self,
_bounds: Rectangle,
_content_bounds: Rectangle,
- _cursor_position: Point,
- ) -> bool {
- false
+ _offset: u32,
+ ) -> Option<scrollable::Scrollbar> {
+ None
}
fn draw(
@@ -77,6 +77,7 @@ impl scrollable::Renderer for Null {
_content_bounds: Rectangle,
_is_mouse_over: bool,
_is_mouse_over_scrollbar: bool,
+ _scrollbar: Option<scrollable::Scrollbar>,
_offset: u32,
_content: Self::Output,
) {
diff --git a/native/src/size.rs b/native/src/size.rs
index 30e2a57e..389b3247 100644
--- a/native/src/size.rs
+++ b/native/src/size.rs
@@ -37,3 +37,15 @@ impl Size {
}
}
}
+
+impl From<[f32; 2]> for Size {
+ fn from([width, height]: [f32; 2]) -> Self {
+ Size { width, height }
+ }
+}
+
+impl From<[u16; 2]> for Size {
+ fn from([width, height]: [u16; 2]) -> Self {
+ Size::new(width.into(), height.into())
+ }
+}
diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs
index 0d73fdb0..7a7138ff 100644
--- a/native/src/widget/image.rs
+++ b/native/src/widget/image.rs
@@ -102,6 +102,7 @@ where
}
fn hash_layout(&self, state: &mut Hasher) {
+ self.path.hash(state);
self.width.hash(state);
self.height.hash(state);
}
diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs
index 678d837a..3c2625b7 100644
--- a/native/src/widget/scrollable.rs
+++ b/native/src/widget/scrollable.rs
@@ -150,12 +150,6 @@ where
let content = layout.children().next().unwrap();
let content_bounds = content.bounds();
- let is_mouse_over_scrollbar = renderer.is_mouse_over_scrollbar(
- bounds,
- content_bounds,
- cursor_position,
- );
-
// TODO: Event capture. Nested scrollables should capture scroll events.
if is_mouse_over {
match event {
@@ -174,49 +168,66 @@ where
}
}
- if self.state.is_scrollbar_grabbed() || is_mouse_over_scrollbar {
+ let offset = self.state.offset(bounds, content_bounds);
+ let scrollbar = renderer.scrollbar(bounds, content_bounds, offset);
+ let is_mouse_over_scrollbar = scrollbar
+ .as_ref()
+ .map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
+ .unwrap_or(false);
+
+ if self.state.is_scroller_grabbed() {
match event {
Event::Mouse(mouse::Event::Input {
button: mouse::Button::Left,
- state,
- }) => match state {
- ButtonState::Pressed => {
- self.state.scroll_to(
- cursor_position.y / (bounds.y + bounds.height),
- bounds,
- content_bounds,
- );
-
- self.state.scrollbar_grabbed_at = Some(cursor_position);
- }
- ButtonState::Released => {
- self.state.scrollbar_grabbed_at = None;
- }
- },
+ state: ButtonState::Released,
+ }) => {
+ self.state.scroller_grabbed_at = None;
+ }
Event::Mouse(mouse::Event::CursorMoved { .. }) => {
- if let Some(scrollbar_grabbed_at) =
- self.state.scrollbar_grabbed_at
+ if let (Some(scrollbar), Some(scroller_grabbed_at)) =
+ (scrollbar, self.state.scroller_grabbed_at)
{
- let ratio = content_bounds.height / bounds.height;
- let delta = scrollbar_grabbed_at.y - cursor_position.y;
-
- self.state.scroll(
- delta * ratio,
+ self.state.scroll_to(
+ scrollbar.scroll_percentage(
+ scroller_grabbed_at,
+ cursor_position,
+ ),
bounds,
content_bounds,
);
-
- self.state.scrollbar_grabbed_at = Some(cursor_position);
+ }
+ }
+ _ => {}
+ }
+ } else if is_mouse_over_scrollbar {
+ match event {
+ Event::Mouse(mouse::Event::Input {
+ button: mouse::Button::Left,
+ state: ButtonState::Pressed,
+ }) => {
+ if let Some(scrollbar) = scrollbar {
+ if let Some(scroller_grabbed_at) =
+ scrollbar.grab_scroller(cursor_position)
+ {
+ self.state.scroll_to(
+ scrollbar.scroll_percentage(
+ scroller_grabbed_at,
+ cursor_position,
+ ),
+ bounds,
+ content_bounds,
+ );
+
+ self.state.scroller_grabbed_at =
+ Some(scroller_grabbed_at);
+ }
}
}
_ => {}
}
}
- let cursor_position = if is_mouse_over
- && !(is_mouse_over_scrollbar
- || self.state.scrollbar_grabbed_at.is_some())
- {
+ let cursor_position = if is_mouse_over && !is_mouse_over_scrollbar {
Point::new(
cursor_position.x,
cursor_position.y
@@ -249,13 +260,13 @@ where
let content_layout = layout.children().next().unwrap();
let content_bounds = content_layout.bounds();
let offset = self.state.offset(bounds, content_bounds);
+ let scrollbar = renderer.scrollbar(bounds, content_bounds, offset);
let is_mouse_over = bounds.contains(cursor_position);
- let is_mouse_over_scrollbar = renderer.is_mouse_over_scrollbar(
- bounds,
- content_bounds,
- cursor_position,
- );
+ let is_mouse_over_scrollbar = scrollbar
+ .as_ref()
+ .map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
+ .unwrap_or(false);
let content = {
let cursor_position = if is_mouse_over && !is_mouse_over_scrollbar {
@@ -274,6 +285,7 @@ where
content_layout.bounds(),
is_mouse_over,
is_mouse_over_scrollbar,
+ scrollbar,
offset,
content,
)
@@ -294,7 +306,7 @@ where
/// [`Scrollable`]: struct.Scrollable.html
#[derive(Debug, Clone, Copy, Default)]
pub struct State {
- scrollbar_grabbed_at: Option<Point>,
+ scroller_grabbed_at: Option<f32>,
offset: f32,
}
@@ -356,12 +368,68 @@ impl State {
self.offset.min(hidden_content as f32) as u32
}
- /// Returns whether the scrollbar is currently grabbed or not.
- pub fn is_scrollbar_grabbed(&self) -> bool {
- self.scrollbar_grabbed_at.is_some()
+ /// Returns whether the scroller is currently grabbed or not.
+ pub fn is_scroller_grabbed(&self) -> bool {
+ self.scroller_grabbed_at.is_some()
}
}
+/// The scrollbar of a [`Scrollable`].
+///
+/// [`Scrollable`]: struct.Scrollable.html
+#[derive(Debug)]
+pub struct Scrollbar {
+ /// The bounds of the [`Scrollbar`].
+ ///
+ /// [`Scrollbar`]: struct.Scrollbar.html
+ pub bounds: Rectangle,
+
+ /// The bounds of the [`Scroller`].
+ ///
+ /// [`Scroller`]: struct.Scroller.html
+ pub scroller: Scroller,
+}
+
+impl Scrollbar {
+ fn is_mouse_over(&self, cursor_position: Point) -> bool {
+ self.bounds.contains(cursor_position)
+ }
+
+ fn grab_scroller(&self, cursor_position: Point) -> Option<f32> {
+ if self.bounds.contains(cursor_position) {
+ Some(if self.scroller.bounds.contains(cursor_position) {
+ (cursor_position.y - self.scroller.bounds.y)
+ / self.scroller.bounds.height
+ } else {
+ 0.5
+ })
+ } else {
+ None
+ }
+ }
+
+ fn scroll_percentage(
+ &self,
+ grabbed_at: f32,
+ cursor_position: Point,
+ ) -> f32 {
+ (cursor_position.y + self.bounds.y
+ - self.scroller.bounds.height * grabbed_at)
+ / (self.bounds.height - self.scroller.bounds.height)
+ }
+}
+
+/// The handle of a [`Scrollbar`].
+///
+/// [`Scrollbar`]: struct.Scrollbar.html
+#[derive(Debug, Clone, Copy)]
+pub struct Scroller {
+ /// The bounds of the [`Scroller`].
+ ///
+ /// [`Scroller`]: struct.Scrollbar.html
+ pub bounds: Rectangle,
+}
+
/// The renderer of a [`Scrollable`].
///
/// Your [renderer] will need to implement this trait before being
@@ -370,27 +438,31 @@ impl State {
/// [`Scrollable`]: struct.Scrollable.html
/// [renderer]: ../../renderer/index.html
pub trait Renderer: crate::Renderer + Sized {
- /// Returns whether the mouse is over the scrollbar given the bounds of
- /// the [`Scrollable`] and its contents.
+ /// Returns the [`Scrollbar`] given the bounds and content bounds of a
+ /// [`Scrollable`].
///
+ /// [`Scrollbar`]: struct.Scrollbar.html
/// [`Scrollable`]: struct.Scrollable.html
- fn is_mouse_over_scrollbar(
+ fn scrollbar(
&self,
bounds: Rectangle,
content_bounds: Rectangle,
- cursor_position: Point,
- ) -> bool;
+ offset: u32,
+ ) -> Option<Scrollbar>;
/// Draws the [`Scrollable`].
///
/// It receives:
/// - the [`State`] of the [`Scrollable`]
- /// - the bounds of the [`Scrollable`]
+ /// - the bounds of the [`Scrollable`] widget
+ /// - the bounds of the [`Scrollable`] content
/// - whether the mouse is over the [`Scrollable`] or not
- /// - whether the mouse is over the scrollbar or not
+ /// - whether the mouse is over the [`Scrollbar`] or not
+ /// - a optional [`Scrollbar`] to be rendered
/// - the scrolling offset
/// - the drawn content
///
+ /// [`Scrollbar`]: struct.Scrollbar.html
/// [`Scrollable`]: struct.Scrollable.html
/// [`State`]: struct.State.html
fn draw(
@@ -400,6 +472,7 @@ pub trait Renderer: crate::Renderer + Sized {
content_bounds: Rectangle,
is_mouse_over: bool,
is_mouse_over_scrollbar: bool,
+ scrollbar: Option<Scrollbar>,
offset: u32,
content: Self::Output,
) -> Self::Output;
diff --git a/src/settings.rs b/src/settings.rs
index 2556c51b..62a1a614 100644
--- a/src/settings.rs
+++ b/src/settings.rs
@@ -19,6 +19,9 @@ pub struct Window {
/// Whether the window should be resizable or not.
pub resizable: bool,
+
+ /// Whether the window should have a border, a title bar, etc. or not.
+ pub decorations: bool,
}
impl Default for Window {
@@ -26,6 +29,7 @@ impl Default for Window {
Window {
size: (1024, 768),
resizable: true,
+ decorations: true,
}
}
}
@@ -37,6 +41,8 @@ impl From<Settings> for iced_winit::Settings {
window: iced_winit::settings::Window {
size: settings.window.size,
resizable: settings.window.resizable,
+ decorations: settings.window.decorations,
+ platform_specific: Default::default(),
},
}
}
diff --git a/web/CHANGELOG.md b/web/CHANGELOG.md
index 49ddf5a3..0bdb9c37 100644
--- a/web/CHANGELOG.md
+++ b/web/CHANGELOG.md
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
+### Fixed
+- Render not being scheduled after `Command` futures finishing.
## [0.1.0] - 2019-11-25
### Added
diff --git a/web/src/lib.rs b/web/src/lib.rs
index 8239ffc9..782bcf93 100644
--- a/web/src/lib.rs
+++ b/web/src/lib.rs
@@ -138,19 +138,9 @@ pub trait Application {
Self: 'static + Sized,
{
let (app, command) = Self::new();
- let mut instance = Instance::new(app);
- instance.spawn(command);
-
- let window = web_sys::window().unwrap();
-
- let document = window.document().unwrap();
- document.set_title(&instance.title);
-
- let body = document.body().unwrap();
- let vdom = dodrio::Vdom::new(&body, instance);
-
- vdom.forget();
+ let instance = Instance::new(app);
+ instance.run(command);
}
}
@@ -158,6 +148,7 @@ pub trait Application {
struct Instance<Message> {
title: String,
ui: Rc<RefCell<Box<dyn Application<Message = Message>>>>,
+ vdom: Rc<RefCell<Option<dodrio::VdomWeak>>>,
}
impl<Message> Instance<Message>
@@ -168,6 +159,7 @@ where
Self {
title: ui.title(),
ui: Rc::new(RefCell::new(Box::new(ui))),
+ vdom: Rc::new(RefCell::new(None)),
}
}
@@ -192,11 +184,35 @@ where
for future in command.futures() {
let mut instance = self.clone();
- let future = future.map(move |message| instance.update(message));
+
+ let future = future.map(move |message| {
+ instance.update(message);
+
+ if let Some(ref vdom) = *instance.vdom.borrow() {
+ vdom.schedule_render();
+ }
+ });
wasm_bindgen_futures::spawn_local(future);
}
}
+
+ fn run(mut self, command: Command<Message>) {
+ let window = web_sys::window().unwrap();
+
+ let document = window.document().unwrap();
+ document.set_title(&self.title);
+
+ let body = document.body().unwrap();
+
+ let weak = self.vdom.clone();
+ self.spawn(command);
+
+ let vdom = dodrio::Vdom::new(&body, self);
+ *weak.borrow_mut() = Some(vdom.weak());
+
+ vdom.forget();
+ }
}
impl<Message> dodrio::Render for Instance<Message>
diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml
index f008a99c..47ec0537 100644
--- a/wgpu/Cargo.toml
+++ b/wgpu/Cargo.toml
@@ -4,14 +4,14 @@ version = "0.1.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "A wgpu renderer for Iced"
-license = "MIT"
+license = "MIT AND OFL-1.1"
repository = "https://github.com/hecrj/iced"
[dependencies]
iced_native = { version = "0.1.0", path = "../native" }
wgpu = "0.4"
glyph_brush = "0.6"
-wgpu_glyph = "0.6"
+wgpu_glyph = { version = "0.7", git = "https://github.com/hecrj/wgpu_glyph", branch = "fix/font-load-panic" }
raw-window-handle = "0.3"
image = "0.22"
glam = "0.8"
diff --git a/wgpu/fonts/Lato-Regular.ttf b/wgpu/fonts/Lato-Regular.ttf
new file mode 100644
index 00000000..33eba8b1
--- /dev/null
+++ b/wgpu/fonts/Lato-Regular.ttf
Binary files differ
diff --git a/wgpu/fonts/OFL.txt b/wgpu/fonts/OFL.txt
new file mode 100644
index 00000000..dfca0da4
--- /dev/null
+++ b/wgpu/fonts/OFL.txt
@@ -0,0 +1,93 @@
+Copyright (c) 2010-2014 by tyPoland Lukasz Dziedzic (team@latofonts.com) with Reserved Font Name "Lato"
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs
index 4e814468..7e4e2670 100644
--- a/wgpu/src/image.rs
+++ b/wgpu/src/image.rs
@@ -491,6 +491,7 @@ pub struct Image {
pub scale: [f32; 2],
}
+#[repr(C)]
#[derive(Clone, Copy)]
pub struct Vertex {
_position: [f32; 2],
@@ -513,6 +514,7 @@ const QUAD_VERTS: [Vertex; 4] = [
},
];
+#[repr(C)]
#[derive(Clone, Copy)]
struct Instance {
_position: [f32; 2],
diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs
index 3d797758..c292dec3 100644
--- a/wgpu/src/quad.rs
+++ b/wgpu/src/quad.rs
@@ -248,6 +248,7 @@ impl Pipeline {
}
}
+#[repr(C)]
#[derive(Clone, Copy)]
pub struct Vertex {
_position: [f32; 2],
@@ -270,6 +271,7 @@ const QUAD_VERTS: [Vertex; 4] = [
},
];
+#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Quad {
pub position: [f32; 2],
diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs
index 8f0f7432..fa52bd96 100644
--- a/wgpu/src/renderer.rs
+++ b/wgpu/src/renderer.rs
@@ -49,7 +49,7 @@ impl<'a> Layer<'a> {
impl Renderer {
fn new() -> Self {
let adapter = Adapter::request(&RequestAdapterOptions {
- power_preference: PowerPreference::LowPower,
+ power_preference: PowerPreference::Default,
backends: BackendBit::all(),
})
.expect("Request adapter");
diff --git a/wgpu/src/renderer/widget/scrollable.rs b/wgpu/src/renderer/widget/scrollable.rs
index 58dc3df9..6ef57185 100644
--- a/wgpu/src/renderer/widget/scrollable.rs
+++ b/wgpu/src/renderer/widget/scrollable.rs
@@ -1,45 +1,58 @@
use crate::{Primitive, Renderer};
-use iced_native::{
- scrollable, Background, MouseCursor, Point, Rectangle, Vector,
-};
+use iced_native::{scrollable, Background, MouseCursor, Rectangle, Vector};
const SCROLLBAR_WIDTH: u16 = 10;
const SCROLLBAR_MARGIN: u16 = 2;
-fn scrollbar_bounds(bounds: Rectangle) -> Rectangle {
- Rectangle {
- x: bounds.x + bounds.width
- - f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
- y: bounds.y,
- width: f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
- height: bounds.height,
- }
-}
-
impl scrollable::Renderer for Renderer {
- fn is_mouse_over_scrollbar(
+ fn scrollbar(
&self,
bounds: Rectangle,
content_bounds: Rectangle,
- cursor_position: Point,
- ) -> bool {
- content_bounds.height > bounds.height
- && scrollbar_bounds(bounds).contains(cursor_position)
+ offset: u32,
+ ) -> Option<scrollable::Scrollbar> {
+ if content_bounds.height > bounds.height {
+ let scrollbar_bounds = Rectangle {
+ x: bounds.x + bounds.width
+ - f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
+ y: bounds.y,
+ width: f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
+ height: bounds.height,
+ };
+
+ let ratio = bounds.height / content_bounds.height;
+ let scrollbar_height = bounds.height * ratio;
+ let y_offset = offset as f32 * ratio;
+
+ let scroller_bounds = Rectangle {
+ x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN),
+ y: scrollbar_bounds.y + y_offset,
+ width: scrollbar_bounds.width - f32::from(2 * SCROLLBAR_MARGIN),
+ height: scrollbar_height,
+ };
+
+ Some(scrollable::Scrollbar {
+ bounds: scrollbar_bounds,
+ scroller: scrollable::Scroller {
+ bounds: scroller_bounds,
+ },
+ })
+ } else {
+ None
+ }
}
fn draw(
&mut self,
state: &scrollable::State,
bounds: Rectangle,
- content_bounds: Rectangle,
+ _content_bounds: Rectangle,
is_mouse_over: bool,
is_mouse_over_scrollbar: bool,
+ scrollbar: Option<scrollable::Scrollbar>,
offset: u32,
(content, mouse_cursor): Self::Output,
) -> Self::Output {
- let is_content_overflowing = content_bounds.height > bounds.height;
- let scrollbar_bounds = scrollbar_bounds(bounds);
-
let clip = Primitive::Clip {
bounds,
offset: Vector::new(0, offset),
@@ -47,51 +60,46 @@ impl scrollable::Renderer for Renderer {
};
(
- if is_content_overflowing
- && (is_mouse_over || state.is_scrollbar_grabbed())
- {
- let ratio = bounds.height / content_bounds.height;
- let scrollbar_height = bounds.height * ratio;
- let y_offset = offset as f32 * ratio;
-
- let scrollbar = Primitive::Quad {
- bounds: Rectangle {
- x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN),
- y: scrollbar_bounds.y + y_offset,
- width: scrollbar_bounds.width
- - f32::from(2 * SCROLLBAR_MARGIN),
- height: scrollbar_height,
- },
- background: Background::Color([0.0, 0.0, 0.0, 0.7].into()),
- border_radius: 5,
- };
-
- if is_mouse_over_scrollbar || state.is_scrollbar_grabbed() {
- let scrollbar_background = Primitive::Quad {
- bounds: Rectangle {
- x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN),
- width: scrollbar_bounds.width
- - f32::from(2 * SCROLLBAR_MARGIN),
- ..scrollbar_bounds
- },
+ if let Some(scrollbar) = scrollbar {
+ if is_mouse_over || state.is_scroller_grabbed() {
+ let scroller = Primitive::Quad {
+ bounds: scrollbar.scroller.bounds,
background: Background::Color(
- [0.0, 0.0, 0.0, 0.3].into(),
+ [0.0, 0.0, 0.0, 0.7].into(),
),
border_radius: 5,
};
- Primitive::Group {
- primitives: vec![clip, scrollbar_background, scrollbar],
+ if is_mouse_over_scrollbar || state.is_scroller_grabbed() {
+ let scrollbar = Primitive::Quad {
+ bounds: Rectangle {
+ x: scrollbar.bounds.x
+ + f32::from(SCROLLBAR_MARGIN),
+ width: scrollbar.bounds.width
+ - f32::from(2 * SCROLLBAR_MARGIN),
+ ..scrollbar.bounds
+ },
+ background: Background::Color(
+ [0.0, 0.0, 0.0, 0.3].into(),
+ ),
+ border_radius: 5,
+ };
+
+ Primitive::Group {
+ primitives: vec![clip, scrollbar, scroller],
+ }
+ } else {
+ Primitive::Group {
+ primitives: vec![clip, scroller],
+ }
}
} else {
- Primitive::Group {
- primitives: vec![clip, scrollbar],
- }
+ clip
}
} else {
clip
},
- if is_mouse_over_scrollbar || state.is_scrollbar_grabbed() {
+ if is_mouse_over_scrollbar || state.is_scroller_grabbed() {
MouseCursor::Idle
} else {
mouse_cursor
diff --git a/wgpu/src/renderer/widget/text_input.rs b/wgpu/src/renderer/widget/text_input.rs
index 9ed3b415..d64fca6d 100644
--- a/wgpu/src/renderer/widget/text_input.rs
+++ b/wgpu/src/renderer/widget/text_input.rs
@@ -45,7 +45,7 @@ impl text_input::Renderer for Renderer {
height: bounds.height - 2.0,
},
background: Background::Color(Color::WHITE),
- border_radius: 5,
+ border_radius: 4,
};
let size = f32::from(size);
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index bf37abe5..e9a1602f 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -11,6 +11,8 @@ pub const BUILTIN_ICONS: iced_native::Font = iced_native::Font::External {
pub const CHECKMARK_ICON: char = '\u{F00C}';
+const FALLBACK_FONT: &[u8] = include_bytes!("../fonts/Lato-Regular.ttf");
+
#[derive(Debug)]
pub struct Pipeline {
draw_brush: RefCell<wgpu_glyph::GlyphBrush<'static, ()>>,
@@ -26,24 +28,31 @@ impl Pipeline {
let default_font = font_source
.load(&[font::Family::SansSerif, font::Family::Serif])
- .expect("Find sans-serif or serif font");
+ .unwrap_or_else(|_| FALLBACK_FONT.to_vec());
+
+ let load_glyph_brush = |font: Vec<u8>| {
+ let builder =
+ wgpu_glyph::GlyphBrushBuilder::using_fonts_bytes(vec![
+ font.clone()
+ ])?;
+
+ Ok((
+ builder,
+ glyph_brush::GlyphBrushBuilder::using_font_bytes(font).build(),
+ ))
+ };
+
+ let (brush_builder, measure_brush) = load_glyph_brush(default_font)
+ .unwrap_or_else(|_: wgpu_glyph::rusttype::Error| {
+ log::warn!("System font failed to load. Falling back to embedded font...");
- let mono_font = font_source
- .load(&[font::Family::Monospace])
- .expect("Find monospace font");
+ load_glyph_brush(FALLBACK_FONT.to_vec()).expect("Load fallback font")
+ });
- let draw_brush =
- wgpu_glyph::GlyphBrushBuilder::using_fonts_bytes(vec![
- mono_font,
- default_font.clone(),
- ])
+ let draw_brush = brush_builder
.initial_cache_size((2048, 2048))
.build(device, wgpu::TextureFormat::Bgra8UnormSrgb);
- let measure_brush =
- glyph_brush::GlyphBrushBuilder::using_font_bytes(default_font)
- .build();
-
Pipeline {
draw_brush: RefCell::new(draw_brush),
draw_font_map: RefCell::new(HashMap::new()),
@@ -95,14 +104,7 @@ impl Pipeline {
text: content,
scale: wgpu_glyph::Scale { x: size, y: size },
bounds: (bounds.width, bounds.height),
-
- // TODO: This is a bit hacky. We are loading the debug font as the
- // first font in the `draw_brush`. The `measure_brush` does not
- // contain this, hence we subtract 1.
- //
- // This should go away once we unify `draw_brush` and
- // `measure_brush`.
- font_id: wgpu_glyph::FontId(font_id - 1),
+ font_id: wgpu_glyph::FontId(font_id),
..Default::default()
};
@@ -143,7 +145,7 @@ impl Pipeline {
pub fn find_font(&self, font: iced_native::Font) -> wgpu_glyph::FontId {
match font {
- iced_native::Font::Default => wgpu_glyph::FontId(1),
+ iced_native::Font::Default => wgpu_glyph::FontId(0),
iced_native::Font::External { name, bytes } => {
if let Some(font_id) = self.draw_font_map.borrow().get(name) {
return *font_id;
diff --git a/winit/Cargo.toml b/winit/Cargo.toml
index 2a33255d..b5b07449 100644
--- a/winit/Cargo.toml
+++ b/winit/Cargo.toml
@@ -15,3 +15,6 @@ iced_native = { version = "0.1.0-alpha", path = "../native" }
winit = { version = "0.20.0-alpha3", git = "https://github.com/rust-windowing/winit", rev = "709808eb4e69044705fcb214bcc30556db761405"}
futures = { version = "0.3", features = ["thread-pool"] }
log = "0.4"
+
+[target.'cfg(target_os = "windows")'.dependencies.winapi]
+version = "0.3.6"
diff --git a/winit/src/application.rs b/winit/src/application.rs
index 1042b412..3772a667 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -96,21 +96,35 @@ pub trait Application: Sized {
let mut title = application.title();
- let (width, height) = settings.window.size;
-
- let window = WindowBuilder::new()
- .with_title(&title)
- .with_inner_size(winit::dpi::LogicalSize {
- width: f64::from(width),
- height: f64::from(height),
- })
- .with_resizable(settings.window.resizable)
- .build(&event_loop)
- .expect("Open window");
+ let window = {
+ let mut window_builder = WindowBuilder::new();
+
+ let (width, height) = settings.window.size;
+
+ window_builder = window_builder
+ .with_title(&title)
+ .with_inner_size(winit::dpi::LogicalSize {
+ width: f64::from(width),
+ height: f64::from(height),
+ })
+ .with_resizable(settings.window.resizable)
+ .with_decorations(settings.window.decorations);
+
+ #[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 dpi = window.hidpi_factor();
let mut size = window.inner_size();
- let mut new_size: Option<winit::dpi::LogicalSize> = None;
+ let mut resized = false;
let mut renderer = Self::Renderer::new();
@@ -143,6 +157,11 @@ pub trait Application: Sized {
event_loop.run(move |event, _, control_flow| match event {
event::Event::MainEventsCleared => {
+ if events.is_empty() && external_messages.is_empty() && !resized
+ {
+ return;
+ }
+
// TODO: We should be able to keep a user interface alive
// between events once we remove state references.
//
@@ -217,9 +236,9 @@ pub trait Application: Sized {
event::Event::RedrawRequested(_) => {
debug.render_started();
- if let Some(new_size) = new_size.take() {
+ if resized {
let dpi = window.hidpi_factor();
- let (width, height) = to_physical(new_size, dpi);
+ let (width, height) = to_physical(size, dpi);
target.resize(
width,
@@ -228,7 +247,7 @@ pub trait Application: Sized {
&renderer,
);
- size = new_size;
+ resized = false;
}
let new_mouse_cursor =
@@ -320,8 +339,9 @@ pub trait Application: Sized {
WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
- WindowEvent::Resized(size) => {
- new_size = Some(size.into());
+ WindowEvent::Resized(new_size) => {
+ size = new_size;
+ resized = true;
log::debug!("Resized: {:?}", new_size);
}
diff --git a/winit/src/debug/basic.rs b/winit/src/debug/basic.rs
index 67c6d8a2..c9da392c 100644
--- a/winit/src/debug/basic.rs
+++ b/winit/src/debug/basic.rs
@@ -146,7 +146,7 @@ impl Debug {
let mut lines = Vec::new();
fn key_value<T: std::fmt::Debug>(key: &str, value: T) -> String {
- format!("{: <30} {:?}", key, value)
+ format!("{} {:?}", key, value)
}
lines.push(format!(
diff --git a/winit/src/settings.rs b/winit/src/settings/mod.rs
index d257ecd8..151d73d7 100644
--- a/winit/src/settings.rs
+++ b/winit/src/settings/mod.rs
@@ -1,5 +1,11 @@
//! Configure your application.
+#[cfg_attr(target_os = "windows", path = "windows.rs")]
+#[cfg_attr(not(target_os = "windows"), path = "not_windows.rs")]
+mod platform;
+
+pub use platform::PlatformSpecific;
+
/// The settings of an application.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Settings {
@@ -17,6 +23,12 @@ pub struct Window {
/// Whether the window should be resizable or not.
pub resizable: bool,
+
+ /// Whether the window should have a border, a title bar, etc.
+ pub decorations: bool,
+
+ /// Platform specific settings.
+ pub platform_specific: platform::PlatformSpecific,
}
impl Default for Window {
@@ -24,6 +36,8 @@ impl Default for Window {
Window {
size: (1024, 768),
resizable: true,
+ decorations: true,
+ platform_specific: Default::default(),
}
}
}
diff --git a/winit/src/settings/not_windows.rs b/winit/src/settings/not_windows.rs
new file mode 100644
index 00000000..5d703f84
--- /dev/null
+++ b/winit/src/settings/not_windows.rs
@@ -0,0 +1,6 @@
+#![cfg(not(target_os = "windows"))]
+//! Platform specific settings for not Windows.
+
+/// The platform specific window settings of an application.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+pub struct PlatformSpecific {}
diff --git a/winit/src/settings/windows.rs b/winit/src/settings/windows.rs
new file mode 100644
index 00000000..76b8d067
--- /dev/null
+++ b/winit/src/settings/windows.rs
@@ -0,0 +1,9 @@
+#![cfg(target_os = "windows")]
+//! Platform specific settings for Windows.
+
+/// The platform specific window settings of an application.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+pub struct PlatformSpecific {
+ /// Parent Window
+ pub parent: Option<winapi::shared::windef::HWND>,
+}