From 108d85ac883a2f8eb8b1271b74e8facc23102268 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Mon, 21 Oct 2019 01:59:17 +0200
Subject: Add `ROADMAP`

---
 ROADMAP.md            | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++
 docs/crates_graph.dot |  12 +++
 docs/crates_graph.png | Bin 0 -> 40251 bytes
 3 files changed, 299 insertions(+)
 create mode 100644 ROADMAP.md
 create mode 100644 docs/crates_graph.dot
 create mode 100644 docs/crates_graph.png

diff --git a/ROADMAP.md b/ROADMAP.md
new file mode 100644
index 00000000..10404c85
--- /dev/null
+++ b/ROADMAP.md
@@ -0,0 +1,287 @@
+# Roadmap
+This document describes the current state of Iced and some of the most important next steps we should take before it can become a production-ready GUI library.
+
+## Context
+Before we get into the actual roadmap, let's quickly review what is the current state of the library.
+
+### Users
+
+Iced is meant to be used by 2 different types of users:
+
+- __End-users__. They should be able to:
+  - get started quickly,
+  - have many widgets available,
+  - keep things simple,
+  - and build applications that are __maintainable__ and __performant__.
+- __GUI toolkit developers / Ecosystem contributors__. They should be able to:
+  - build new kinds of widgets,
+  - implement custom runtimes,
+  - integrate existing runtimes in their own system (like game engines),
+  - and create their own custom renderers.
+
+### Current state
+Iced consists of different crates which offer different layers of abstractions for our users. This modular architecture helps us keep implementation details hidden and decoupled, which should allow us to rewrite or change strategies in the future.
+
+![Crates graph](docs/crates_graph.png)
+
+#### `iced_core`
+
+`iced_core` holds most of the reusable types of the public API. For instance, common widgets (like `Column`, `Row`, `Button`...) and basic data types (`Point`, `Rectangle`, `Length`...).
+
+This crate is meant to be a starting point for an Iced runtime.
+
+#### `iced_native`
+`iced_native` takes `iced_core` and builds a native runtime on top of it, featuring:
+- A flexbox-based layout engine, powered by [`stretch`]
+- Event handling for all the built-in widgets
+- A renderer-agnostic API
+
+To achieve this, it introduces a bunch of reusable interfaces:
+- A `Widget` trait, which is used to implement new widgets: from layout requirements to event and drawing logic.
+- A bunch of `Renderer` traits, meant to keep the crate renderer-agnostic.
+- A `Windowed` trait, which can be implemented by graphical renderers that target _windows_. Window-based runtimes can use this trait to stay renderer-agnostic.
+
+[`stretch`]: https://github.com/vislyhq/stretch
+
+#### `iced_web`
+`iced_web` takes `iced_core` and builds a WebAssembly runtime on top. It achieves this by introducing a `Widget` trait that can be used to produce VDOM nodes.
+
+The crate is a quite simple abstraction layer over [`dodrio`].
+
+[`dodrio`]: https://github.com/fitzgen/dodrio
+
+#### `iced_wgpu`
+`iced_wgpu` is a [`wgpu`] renderer for `iced_native`. It is meant to become the default renderer of Iced in native platforms.
+
+[`wgpu`] supports most modern graphics backends: Vulkan, Metal, DX11, and DX12 (OpenGL and WebGL are still WIP). Additionally, it will support the incoming [WebGPU API].
+
+Currently, `iced_wgpu` only supports a couple of primitives:
+- Text, which is rendered using [`wgpu_glyph`].
+- Quads or rectangles, with rounded borders and a solid background color.
+
+[`wgpu`]: https://github.com/gfx-rs/wgpu-rs
+[WebGPU API]: https://gpuweb.github.io/gpuweb/
+[`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph
+
+#### `iced_winit`
+`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.
+
+[`winit`]: https://github.com/rust-windowing/winit
+
+#### `iced`
+Finally, `iced` unifies everything into a simple abstraction to create cross-platform applications:
+
+- On native, it uses `iced_winit` and `iced_wgpu`.
+- On web, it uses `iced_web`.
+
+This is the crate meant to be used by __end-users__.
+
+
+## Next steps
+This section describes some important features that should be implemented before Iced can be considered production-ready (before a 1.0 release).
+
+Most of the work related to these features needs to happen in the `iced_native` path of the ecosystem, as the web already supports many of them.
+
+### Scrollables / Clippables
+Content that can take a (practically) infinite amount of space and can be viewed using a scrollbar. This is a very basic feature.
+
+The end-user API could look like this:
+
+```rust
+Column::new()
+    .push(content)
+    .scroll(&mut self.scroll_state);
+```
+
+The challenge here is __composability__. Nested scrollables should work as expected.
+
+When it comes to `iced_native`, we may need to add the concept of _event propagation_, so mouse wheel events can be captured by the inner-most scrollable and stop propagation.
+
+When it comes to `iced_wgpu`, we should be able to use scissoring and transformations. [`wgpu`] has a [`RenderPass::set_scissor_rect`] that should work nicely.
+
+The main issue here will be [`wgpu_glyph`], which is used currently to render text primitives. [`wgpu_glyph`] is powered by [`glyph-brush`], which caches glyphs to render text very fast. However, the current cache model does not seem to be composable (i.e. once you issue a draw call the cache is purged). We will need to change it (and potentially contribute) to accomodate for this use case.
+
+[`RenderPass::set_scissor_rect`]: https://docs.rs/wgpu/0.3.0/src/wgpu/lib.rs.html#1246-1248
+[`glyph-brush`]: https://github.com/alexheretic/glyph-brush
+
+### Text input widget
+A widget where the user can type raw text and passwords.
+
+This widget will have a quite complex event logic, potentially coupled with text rendering. Some examples are:
+- Text cursor positioning based on a mouse click
+- Text selection
+- Clipboard interaction (copy & paste)
+- Text editing shortcuts (go to start, go to end, etc.)
+
+It also needs scrollable / clippable text support, as the introduced text may not fit the input and scrolling based on the text cursor will need to be implemented.
+
+Additionally, the text cursor should blink at a regular interval, which can be considered an _animation_.
+
+I think we should start simple here, and build a text widget with the most basic functionality: click to focus and type to fill. We can improve the implementation with time as the library matures.
+
+The end-user API could look like this:
+
+```rust
+pub enum Message {
+    TextChanged(String),
+}
+
+let text_input = text_input::State::new();
+let text = "Hello";
+
+TextInput::new(&mut text_input, &text, Message::TextChanged);
+```
+
+### TodoMVC example
+Once we have scrollables support and a text widget, we could build a [TodoMVC] example. It seems to be a very simple example and could showcase the API quite well.
+
+We could also consider releasing a `0.1.0` version at this point and share it as a milestone on different social platforms.
+
+[TodoMVC]: http://todomvc.com/
+
+### Async actions
+Most applications need to perform work in the background, without freezing the UI while they work. The current architecture can be easily extended to achieve this.
+
+We can let users return an asynchronous action (i.e. a future) producing a `Message` in `Application::update`. The runtime will spawn each returned action in a thread pool and, once it finishes, feed the produced message back to `update`. This is also how [Elm] does it.
+
+When it comes to implementing this, [`winit`] already supports user-specific events that can be sent from another thread. Accomodating `iced_winit` for this functionality should not be too complicated.
+
+[Elm]: https://elm-lang.org/
+
+Here is an example of how the end-user API could look:
+
+```rust
+impl Application for WeatherReport {
+    fn update(&mut self, message: Message) -> Command<Message> {
+        match message {
+            Message::Refresh => {
+                self.state = State::Loading;
+
+                Command::from_future(
+                    Weather::request(self.location),
+                    Message::ReportReceived,
+                )
+            }
+            Message::ReportReceived(Ok(report)) => {
+                self.state = State::Show(report);
+
+                Command::none()
+            },
+            Message::ReportReceived(Err(error)) => {
+                self.state = State::Error(error);
+
+                Command::none()
+            }
+        }
+    }
+}
+```
+
+### Event subscriptions
+Besides performing async actions on demand, most applications also need to listen to events passively. An example of this could be a WebSocket connection, where messages can come in at any time.
+
+The idea here is to also follow [Elm]'s footsteps. We can add a method `subscriptions(&self) -> Subscription<Message>` to `Application` and keep the subscriptions alive in the runtime.
+
+The challenge here is designing the public API of subscriptions, so users can build their own, and _subscription diffing_, or basically detecting when a subscription is added/changed/removed. For this, we can take a look at the source code of [Elm] for inspiration.
+
+### Layers
+Currently, Iced assumes widgets cannot be laid out on top of each other. We should implement support for multiple layers of widgets.
+
+This is a necessary feature to implement many kind of interactables, like dropdown menus, select fields, etc.
+
+`iced_native` will need to group widgets to perform layouting and process some events first for widgets positioned on top.
+
+`iced_wgpu` will also need to process the scene graph and sort draw calls based on the different layers.
+
+### Multi-window support
+Open and control multiple windows at runtime.
+
+I think this could be achieved by implementing an additional trait in `iced_winit` similar to `Application` but with a slightly different `view` method, allowing users to control what is shown in each window.
+
+This approach should also allow us to perform custom optimizations for this particular use case.
+
+### Animations
+Allow widgets to request a redraw at a specific time.
+
+This is a necessary feature to render loading spinners, a blinking text cursor, GIF images, etc.
+
+[`winit`] allows controlling the event loop in a flexible way. We may be able to use [`ControlFlow::WaitUntil`](https://docs.rs/winit/0.20.0-alpha3/winit/event_loop/enum.ControlFlow.html#variant.WaitUntil) for this purpose.
+
+### Canvas widget
+A widget to draw freely in 2D or 3D. It could be used to draw charts, implement a Paint clone, a CAD application, etc.
+
+As a first approach, we could expose the underlying renderer directly here, and couple this widget with it ([`wgpu`] for now). Once [`wgpu`] gets WebGL or WebGPU support, this widget will be able to run on web too. The renderer primitive could be a simple texture that the widget draws to.
+
+In the long run, we could expose a renderer-agnostic abstraction to perform the drawing.
+
+### Text shaping and font fallback
+[`wgpu_glyph`] uses [`glyph-brush`], which in turn uses [`rusttype`]. While the current implementation is able to layout text quite nicely, it does not perform any [text shaping].
+
+[Text shaping] with font fallback is a necessary feature for any serious GUI toolkit. It unlocks support to truly localize your application, supporting many different scripts.
+
+The only available library that does a great job at shaping is [HarfBuzz], which is implemented in C++. [`skribo`] seems to be a nice [HarfBuzz] wrapper for Rust.
+
+This feature will probably imply rewriting [`wgpu_glyph`] entirely, as caching will be more complicated and the API will probably need to ask for more data.
+
+[`rusttype`]: https://github.com/redox-os/rusttype
+[text shaping]: https://en.wikipedia.org/wiki/Complex_text_layout
+[HarfBuzz]: https://github.com/harfbuzz/harfbuzz
+[`skribo`]: https://github.com/linebender/skribo
+
+### Grid layout and text layout
+Currently, `iced_native` only supports flexbox items. For instance, it is not possible to create a grid of items or make text float around an image.
+
+We will need to enhance the layouting engine to support different strategies and improve the way we measure text to lay it out in a more flexible way.
+
+
+## Ideas that may be worth exploring
+
+### Reuse existing 2D renderers
+While I believe [`wgpu`] has a great future ahead of it, implementing `iced_wgpu` and making it performant will definitely be a challenge.
+
+We should keep an eye on existing 2D graphic libraries, like [`piet`] or [`pathfinder`], and give them a try once/if they mature a bit more.
+
+The good news here is that most of Iced is renderer-agnostic, so changing the rendering strategy, if we deem it worth it, should be really easy. Also, a 2D graphics library will expose a higher-level API than [`wgpu`], so implementing a new renderer on top of it should be fairly straightforward.
+
+[`piet`]: https://github.com/linebender/piet
+[`pathfinder`]: https://github.com/servo/pathfinder
+
+### Remove explicit state handling and lifetimes
+Currently, `iced_native` forces users to provide the local state of each widget. While this could be considered a really pure form of describing a GUI, it makes some optimizations harder because of the borrow checker.
+
+The current borrow checker is not able to detect a drop was performed before reassigning a value to a mutable variable. Thus, keeping the generated widgets in `Application::view` alive between iterations of the event loop is not possible, which forces us to call this method quite often. `unsafe` could be used to workaround this, but it would feel fishy.
+
+We could take a different approach, and keep some kind of state tree decoupled from the actual widget definitions. This would force us to perform diffing of nodes, as the widgets will represent the desired state and not the whole state.
+
+Once the state lifetime of widgets is removed, we could keep them alive between iterations and even make `Application::view` take a non-mutable reference. This would also improve the end-user API, as it will not be necessary to constantly provide mutable state to widgets.
+
+### Improve style definitions
+As of now, each widget defines its own styling options with methods, following the builder pattern.
+
+A unified way of defining and reusing styles would be great. I am not proposing something like CSS, we should try to stay as type-safe and intuitive as possible.
+
+I think [`elm-ui`] could serve as an inspiration.
+
+[`elm-ui`]: https://www.youtube.com/watch?v=Ie-gqwSHQr0
+
+### Try a different font rasterizer
+[`wgpu_glyph`] depends indirectly on [`rusttype`]. We may be able to gain performance by using a different font rasterizer. [`fontdue`], for instance, has reported noticeable speedups.
+
+[`fontdue`]: https://github.com/mooman219/fontdue
+
+### Connect `iced_web` with `web-view`
+It may be interesting to try to connect `iced_web` with [`web-view`]. It would give users a feature-complete renderer for free, and applications would still be leaner than with Electron.
+
+[`web-view`]: https://github.com/Boscop/web-view
+
+### Implement a lazy widget
+Once we remove state lifetimes from widgets, we should be able to implement a widget storing a function that generates additional widgets. The runtime would then be able to control when to call this function and cache the generated widgets while some given value does not change.
+
+This could be very useful to build very performant user interfaces with a lot of different items.
+
+[Elm does it very well!](https://guide.elm-lang.org/optimization/lazy.html)
+
+### Build a custom layout engine
+It may be possible to build an optimized layout engine only for `iced_native` if it turns out that there are some flexbox features we end up not using.
diff --git a/docs/crates_graph.dot b/docs/crates_graph.dot
new file mode 100644
index 00000000..85e375d0
--- /dev/null
+++ b/docs/crates_graph.dot
@@ -0,0 +1,12 @@
+digraph G {
+  "iced_core" -> "iced_native"
+  "iced_core" -> "iced_web"
+  "iced_native" -> "iced_wgpu"
+  "iced_native" -> "iced_winit"
+  "iced_web" -> "iced"
+  "iced_wgpu" -> "iced"
+  "iced_winit" -> "iced"
+
+  node[shape=box];
+  "iced" -> "cross-platform application"
+}
diff --git a/docs/crates_graph.png b/docs/crates_graph.png
new file mode 100644
index 00000000..d598c1dd
Binary files /dev/null and b/docs/crates_graph.png differ
-- 
cgit 


From d66dc4aee64ec1ec5b0661da5b60a9c5ef6b3d81 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Wed, 23 Oct 2019 05:05:48 +0200
Subject: Move "Multi-window support" up in the `ROADMAP`

---
 ROADMAP.md | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/ROADMAP.md b/ROADMAP.md
index 10404c85..b116f218 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -141,6 +141,13 @@ We could also consider releasing a `0.1.0` version at this point and share it as
 
 [TodoMVC]: http://todomvc.com/
 
+### Multi-window support
+Open and control multiple windows at runtime.
+
+I think this could be achieved by implementing an additional trait in `iced_winit` similar to `Application` but with a slightly different `view` method, allowing users to control what is shown in each window.
+
+This approach should also allow us to perform custom optimizations for this particular use case.
+
 ### Async actions
 Most applications need to perform work in the background, without freezing the UI while they work. The current architecture can be easily extended to achieve this.
 
@@ -195,13 +202,6 @@ This is a necessary feature to implement many kind of interactables, like dropdo
 
 `iced_wgpu` will also need to process the scene graph and sort draw calls based on the different layers.
 
-### Multi-window support
-Open and control multiple windows at runtime.
-
-I think this could be achieved by implementing an additional trait in `iced_winit` similar to `Application` but with a slightly different `view` method, allowing users to control what is shown in each window.
-
-This approach should also allow us to perform custom optimizations for this particular use case.
-
 ### Animations
 Allow widgets to request a redraw at a specific time.
 
-- 
cgit 


From e3cf59fd99ad96e47e00a9434c01da8bc2942bc9 Mon Sep 17 00:00:00 2001
From: Héctor Ramón <hector0193@gmail.com>
Date: Fri, 25 Oct 2019 22:44:17 +0200
Subject: Fix spelling and grammar in `ROADMAP`

Co-Authored-By: memoryruins <memoryruinsmusic@gmail.com>
---
 ROADMAP.md | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/ROADMAP.md b/ROADMAP.md
index b116f218..3602b702 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -74,7 +74,7 @@ It exposes a renderer-agnostic `Application` trait that can be implemented and t
 Finally, `iced` unifies everything into a simple abstraction to create cross-platform applications:
 
 - On native, it uses `iced_winit` and `iced_wgpu`.
-- On web, it uses `iced_web`.
+- On the web, it uses `iced_web`.
 
 This is the crate meant to be used by __end-users__.
 
@@ -101,7 +101,7 @@ When it comes to `iced_native`, we may need to add the concept of _event propaga
 
 When it comes to `iced_wgpu`, we should be able to use scissoring and transformations. [`wgpu`] has a [`RenderPass::set_scissor_rect`] that should work nicely.
 
-The main issue here will be [`wgpu_glyph`], which is used currently to render text primitives. [`wgpu_glyph`] is powered by [`glyph-brush`], which caches glyphs to render text very fast. However, the current cache model does not seem to be composable (i.e. once you issue a draw call the cache is purged). We will need to change it (and potentially contribute) to accomodate for this use case.
+The main issue here will be [`wgpu_glyph`], which is used currently to render text primitives. [`wgpu_glyph`] is powered by [`glyph-brush`], which caches glyphs to render text very fast. However, the current cache model does not seem to be composable (i.e. once you issue a draw call the cache is purged). We will need to change it (and potentially contribute) to accommodate for this use case.
 
 [`RenderPass::set_scissor_rect`]: https://docs.rs/wgpu/0.3.0/src/wgpu/lib.rs.html#1246-1248
 [`glyph-brush`]: https://github.com/alexheretic/glyph-brush
@@ -153,7 +153,7 @@ Most applications need to perform work in the background, without freezing the U
 
 We can let users return an asynchronous action (i.e. a future) producing a `Message` in `Application::update`. The runtime will spawn each returned action in a thread pool and, once it finishes, feed the produced message back to `update`. This is also how [Elm] does it.
 
-When it comes to implementing this, [`winit`] already supports user-specific events that can be sent from another thread. Accomodating `iced_winit` for this functionality should not be too complicated.
+When it comes to implementing this, [`winit`] already supports user-specific events that can be sent from another thread. Accommodating `iced_winit` for this functionality should not be too complicated.
 
 [Elm]: https://elm-lang.org/
 
@@ -196,7 +196,7 @@ The challenge here is designing the public API of subscriptions, so users can bu
 ### Layers
 Currently, Iced assumes widgets cannot be laid out on top of each other. We should implement support for multiple layers of widgets.
 
-This is a necessary feature to implement many kind of interactables, like dropdown menus, select fields, etc.
+This is a necessary feature to implement many kinds of interactables, like dropdown menus, select fields, etc.
 
 `iced_native` will need to group widgets to perform layouting and process some events first for widgets positioned on top.
 
@@ -207,12 +207,12 @@ Allow widgets to request a redraw at a specific time.
 
 This is a necessary feature to render loading spinners, a blinking text cursor, GIF images, etc.
 
-[`winit`] allows controlling the event loop in a flexible way. We may be able to use [`ControlFlow::WaitUntil`](https://docs.rs/winit/0.20.0-alpha3/winit/event_loop/enum.ControlFlow.html#variant.WaitUntil) for this purpose.
+[`winit`] allows flexible control of its event loop. We may be able to use [`ControlFlow::WaitUntil`](https://docs.rs/winit/0.20.0-alpha3/winit/event_loop/enum.ControlFlow.html#variant.WaitUntil) for this purpose.
 
 ### Canvas widget
 A widget to draw freely in 2D or 3D. It could be used to draw charts, implement a Paint clone, a CAD application, etc.
 
-As a first approach, we could expose the underlying renderer directly here, and couple this widget with it ([`wgpu`] for now). Once [`wgpu`] gets WebGL or WebGPU support, this widget will be able to run on web too. The renderer primitive could be a simple texture that the widget draws to.
+As a first approach, we could expose the underlying renderer directly here, and couple this widget with it ([`wgpu`] for now). Once [`wgpu`] gets WebGL or WebGPU support, this widget will be able to run on the web too. The renderer primitive could be a simple texture that the widget draws to.
 
 In the long run, we could expose a renderer-agnostic abstraction to perform the drawing.
 
-- 
cgit 


From 5e3cfb358ec1bfe7d6e3cfc73d64bb3196e78f50 Mon Sep 17 00:00:00 2001
From: Héctor Ramón <hector0193@gmail.com>
Date: Fri, 25 Oct 2019 23:21:50 +0200
Subject: Clarify event subscriptions in `ROADMAP`

---
 ROADMAP.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ROADMAP.md b/ROADMAP.md
index 3602b702..c4663441 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -191,7 +191,7 @@ Besides performing async actions on demand, most applications also need to liste
 
 The idea here is to also follow [Elm]'s footsteps. We can add a method `subscriptions(&self) -> Subscription<Message>` to `Application` and keep the subscriptions alive in the runtime.
 
-The challenge here is designing the public API of subscriptions, so users can build their own, and _subscription diffing_, or basically detecting when a subscription is added/changed/removed. For this, we can take a look at the source code of [Elm] for inspiration.
+The challenge here is designing the public API of subscriptions. Ideally, users should be able to create their own subscriptions and the GUI runtime should keep them alive by performing _subscription diffing_ (i.e. detecting when a subscription is added, changed, or removed). For this, we can take a look at [Elm] for inspiration.
 
 ### Layers
 Currently, Iced assumes widgets cannot be laid out on top of each other. We should implement support for multiple layers of widgets.
-- 
cgit 


From 00ea9ca5c7840a2793103d7426a829c46088d77a Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Sat, 26 Oct 2019 20:28:46 +0200
Subject: Mention roadmap and show crate graph in `README`

---
 README.md | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/README.md b/README.md
index f7035fb4..6ffb6777 100644
--- a/README.md
+++ b/README.md
@@ -23,9 +23,10 @@ Inspired by [Elm].
   * Built-in widgets
   * Custom widget support
 
-__Iced is in a experimental stage.__ [Check out the issues] and
-[feel free to contribute!].
+__Iced is in a experimental stage.__ [Take a look at the roadmap],
+[check out the issues], and [feel free to contribute!].
 
+[Take a look at the roadmap]: https://github.com/hecrj/iced/blob/master/ROADMAP.md
 [check out the issues]: https://github.com/hecrj/iced/issues
 [feel free to contribute!]: #contributing--feedback
 
@@ -96,7 +97,7 @@ impl Counter {
             .push(
                 // The increment button. We tell it to produce an
                 // `IncrementPressed` message when pressed
-                Button::new(&mut self.increment_button, "+")
+                Button::new(&mut self.increment_button, Text::new("+"))
                     .on_press(Message::IncrementPressed),
             )
             .push(
@@ -106,7 +107,7 @@ impl Counter {
             .push(
                 // The decrement button. We tell it to produce a
                 // `DecrementPressed` message when pressed
-                Button::new(&mut self.decrement_button, "-")
+                Button::new(&mut self.decrement_button, Text::new("-"))
                     .on_press(Message::DecrementPressed),
             )
     }
@@ -156,21 +157,26 @@ its own standalone crate, as it could potentially benefit other engines and
 applications. I thought it was a great idea, and after a bit of work... Iced is
 here!
 
-As an interesting note, the core of Iced does not rely on interior mutability.
-Usage of types like `RefCell` is restricted to runtime boundaries. As a
-consequence, compiler guarantees stay intact and many kinds of pesky bugs and
-runtime errors are banished. No spooky action at a distance!
+Iced consists of different crates which offer different layers of abstractions
+for our users. This modular architecture helps us keep implementation details
+hidden and decoupled, which should allow us to rewrite or change strategies in
+the future.
+
+![Iced ecosystem](https://github.com/hecrj/iced/raw/master/docs/crates_graph.png)
+
+Read [the roadmap] if you want to learn more!
 
 [this pull request]: https://github.com/hecrj/coffee/pull/35
 [`stretch`]: https://github.com/vislyhq/stretch
 [Coffee 0.3.0]: https://github.com/hecrj/coffee/releases/tag/0.3.0
 [`ui` module]: https://docs.rs/coffee/0.3.2/coffee/ui/index.html
+[the roadmap]: https://github.com/hecrj/iced/blob/master/ROADMAP.md
 
 ## Contributing / Feedback
 If you want to contribute, you are more than welcome to be a part of the
-project! Check out the current [issues] if you want to find something to work
-on. Try to share you thoughts first! Feel free to open a new issue if you want
-to discuss new ideas.
+project! Check out [the roadmap] and [the current issues] if you want to find
+something to work on. Try to share you thoughts first! Feel free to open a new
+issue if you want to discuss new ideas.
 
 Any kind of feedback is welcome! You can open an issue or, if you want to talk,
 you can find me (and a bunch of awesome folks) over the `#games-and-graphics`
@@ -182,5 +188,5 @@ and `#gui-and-ui` channels in the [Rust Community Discord]. I go by
 [Coffee]: https://github.com/hecrj/coffee
 [Elm]: https://elm-lang.org/
 [The Elm Architecture]: https://guide.elm-lang.org/architecture/
-[issues]: https://github.com/hecrj/iced/issues
+[the current issues]: https://github.com/hecrj/iced/issues
 [Rust Community Discord]: https://bit.ly/rust-community
-- 
cgit 


From c1f6e66175a1b691841831b6ae03a11daf7fc945 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Sat, 26 Oct 2019 20:35:07 +0200
Subject: Clarify a couple of ideas in the `ROADMAP`

---
 ROADMAP.md | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/ROADMAP.md b/ROADMAP.md
index c4663441..35865e60 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -257,12 +257,14 @@ We could take a different approach, and keep some kind of state tree decoupled f
 
 Once the state lifetime of widgets is removed, we could keep them alive between iterations and even make `Application::view` take a non-mutable reference. This would also improve the end-user API, as it will not be necessary to constantly provide mutable state to widgets.
 
+This is a big undertaking and introduces a new set of problems. We should research and consider the implications of this approach in detail before going for it.
+
 ### Improve style definitions
 As of now, each widget defines its own styling options with methods, following the builder pattern.
 
-A unified way of defining and reusing styles would be great. I am not proposing something like CSS, we should try to stay as type-safe and intuitive as possible.
+A unified way of defining and reusing styles would be great. I think we must avoid replicating CSS, we should try to stay as type-safe, explicit, and intuitive as possible.
 
-I think [`elm-ui`] could serve as an inspiration.
+I think many different ideas in [`elm-ui`] could serve as an inspiration.
 
 [`elm-ui`]: https://www.youtube.com/watch?v=Ie-gqwSHQr0
 
-- 
cgit 


From de3c87b9a793c0d0799948e16ad1b14e5b4892ba Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Sat, 26 Oct 2019 21:08:15 +0200
Subject: Link to specific issues in the `ROADMAP`

---
 ROADMAP.md | 40 +++++++++++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 11 deletions(-)

diff --git a/ROADMAP.md b/ROADMAP.md
index 35865e60..8a6c7869 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -84,7 +84,7 @@ This section describes some important features that should be implemented before
 
 Most of the work related to these features needs to happen in the `iced_native` path of the ecosystem, as the web already supports many of them.
 
-### Scrollables / Clippables
+### Scrollables / Clippables ([#24])
 Content that can take a (practically) infinite amount of space and can be viewed using a scrollbar. This is a very basic feature.
 
 The end-user API could look like this:
@@ -103,10 +103,11 @@ When it comes to `iced_wgpu`, we should be able to use scissoring and transforma
 
 The main issue here will be [`wgpu_glyph`], which is used currently to render text primitives. [`wgpu_glyph`] is powered by [`glyph-brush`], which caches glyphs to render text very fast. However, the current cache model does not seem to be composable (i.e. once you issue a draw call the cache is purged). We will need to change it (and potentially contribute) to accommodate for this use case.
 
+[#24]: https://github.com/hecrj/iced/issues/24
 [`RenderPass::set_scissor_rect`]: https://docs.rs/wgpu/0.3.0/src/wgpu/lib.rs.html#1246-1248
 [`glyph-brush`]: https://github.com/alexheretic/glyph-brush
 
-### Text input widget
+### Text input widget ([#25])
 A widget where the user can type raw text and passwords.
 
 This widget will have a quite complex event logic, potentially coupled with text rendering. Some examples are:
@@ -134,21 +135,26 @@ let text = "Hello";
 TextInput::new(&mut text_input, &text, Message::TextChanged);
 ```
 
-### TodoMVC example
+[#25]: https://github.com/hecrj/iced/issues/25
+
+### TodoMVC example ([#26])
 Once we have scrollables support and a text widget, we could build a [TodoMVC] example. It seems to be a very simple example and could showcase the API quite well.
 
 We could also consider releasing a `0.1.0` version at this point and share it as a milestone on different social platforms.
 
+[#26]: https://github.com/hecrj/iced/issues/26
 [TodoMVC]: http://todomvc.com/
 
-### Multi-window support
+### Multi-window support ([#27])
 Open and control multiple windows at runtime.
 
 I think this could be achieved by implementing an additional trait in `iced_winit` similar to `Application` but with a slightly different `view` method, allowing users to control what is shown in each window.
 
 This approach should also allow us to perform custom optimizations for this particular use case.
 
-### Async actions
+[#27]: https://github.com/hecrj/iced/issues/27
+
+### Async actions ([#28])
 Most applications need to perform work in the background, without freezing the UI while they work. The current architecture can be easily extended to achieve this.
 
 We can let users return an asynchronous action (i.e. a future) producing a `Message` in `Application::update`. The runtime will spawn each returned action in a thread pool and, once it finishes, feed the produced message back to `update`. This is also how [Elm] does it.
@@ -186,14 +192,18 @@ impl Application for WeatherReport {
 }
 ```
 
-### Event subscriptions
+[#28]: https://github.com/hecrj/iced/issues/28
+
+### Event subscriptions ([#29])
 Besides performing async actions on demand, most applications also need to listen to events passively. An example of this could be a WebSocket connection, where messages can come in at any time.
 
 The idea here is to also follow [Elm]'s footsteps. We can add a method `subscriptions(&self) -> Subscription<Message>` to `Application` and keep the subscriptions alive in the runtime.
 
 The challenge here is designing the public API of subscriptions. Ideally, users should be able to create their own subscriptions and the GUI runtime should keep them alive by performing _subscription diffing_ (i.e. detecting when a subscription is added, changed, or removed). For this, we can take a look at [Elm] for inspiration.
 
-### Layers
+[#29]: https://github.com/hecrj/iced/issues/29
+
+### Layers ([#30])
 Currently, Iced assumes widgets cannot be laid out on top of each other. We should implement support for multiple layers of widgets.
 
 This is a necessary feature to implement many kinds of interactables, like dropdown menus, select fields, etc.
@@ -202,21 +212,27 @@ This is a necessary feature to implement many kinds of interactables, like dropd
 
 `iced_wgpu` will also need to process the scene graph and sort draw calls based on the different layers.
 
-### Animations
+[#30]: https://github.com/hecrj/iced/issues/30
+
+### Animations ([#31])
 Allow widgets to request a redraw at a specific time.
 
 This is a necessary feature to render loading spinners, a blinking text cursor, GIF images, etc.
 
 [`winit`] allows flexible control of its event loop. We may be able to use [`ControlFlow::WaitUntil`](https://docs.rs/winit/0.20.0-alpha3/winit/event_loop/enum.ControlFlow.html#variant.WaitUntil) for this purpose.
 
-### Canvas widget
+[#31]: https://github.com/hecrj/iced/issues/31
+
+### Canvas widget ([#32])
 A widget to draw freely in 2D or 3D. It could be used to draw charts, implement a Paint clone, a CAD application, etc.
 
 As a first approach, we could expose the underlying renderer directly here, and couple this widget with it ([`wgpu`] for now). Once [`wgpu`] gets WebGL or WebGPU support, this widget will be able to run on the web too. The renderer primitive could be a simple texture that the widget draws to.
 
 In the long run, we could expose a renderer-agnostic abstraction to perform the drawing.
 
-### Text shaping and font fallback
+[#32]: https://github.com/hecrj/iced/issues/32
+
+### Text shaping and font fallback ([#33])
 [`wgpu_glyph`] uses [`glyph-brush`], which in turn uses [`rusttype`]. While the current implementation is able to layout text quite nicely, it does not perform any [text shaping].
 
 [Text shaping] with font fallback is a necessary feature for any serious GUI toolkit. It unlocks support to truly localize your application, supporting many different scripts.
@@ -225,16 +241,18 @@ The only available library that does a great job at shaping is [HarfBuzz], which
 
 This feature will probably imply rewriting [`wgpu_glyph`] entirely, as caching will be more complicated and the API will probably need to ask for more data.
 
+[#33]: https://github.com/hecrj/iced/issues/33
 [`rusttype`]: https://github.com/redox-os/rusttype
 [text shaping]: https://en.wikipedia.org/wiki/Complex_text_layout
 [HarfBuzz]: https://github.com/harfbuzz/harfbuzz
 [`skribo`]: https://github.com/linebender/skribo
 
-### Grid layout and text layout
+### Grid layout and text layout ([#34])
 Currently, `iced_native` only supports flexbox items. For instance, it is not possible to create a grid of items or make text float around an image.
 
 We will need to enhance the layouting engine to support different strategies and improve the way we measure text to lay it out in a more flexible way.
 
+[#34]: https://github.com/hecrj/iced/issues/34
 
 ## Ideas that may be worth exploring
 
-- 
cgit 


From 022dc0139b7437f167a8d3ae483bf8e83f1dab04 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Sat, 2 Nov 2019 02:44:57 +0100
Subject: Show Ferris at the end of the scrollable section

---
 examples/tour.rs | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/examples/tour.rs b/examples/tour.rs
index 7d8e4e3e..f63b4cfe 100644
--- a/examples/tour.rs
+++ b/examples/tour.rs
@@ -510,20 +510,7 @@ impl<'a> Step {
     ) -> Column<'a, StepMessage> {
         Self::container("Image")
             .push(Text::new("An image that tries to keep its aspect ratio."))
-            .push(
-                // This should go away once we unify resource loading on native
-                // platforms
-                if cfg!(target_arch = "wasm32") {
-                    Image::new("resources/ferris.png")
-                } else {
-                    Image::new(format!(
-                        "{}/examples/resources/ferris.png",
-                        env!("CARGO_MANIFEST_DIR")
-                    ))
-                }
-                .width(Length::Units(width))
-                .align_self(Align::Center),
-            )
+            .push(ferris(width))
             .push(Slider::new(
                 slider,
                 100.0..=500.0,
@@ -555,6 +542,7 @@ impl<'a> Step {
                     .horizontal_alignment(HorizontalAlignment::Center),
             )
             .push(Column::new().height(Length::Units(4096)))
+            .push(ferris(300))
             .push(
                 Text::new("You made it!")
                     .size(50)
@@ -589,6 +577,21 @@ impl<'a> Step {
     }
 }
 
+fn ferris(width: u16) -> Image {
+    // This should go away once we unify resource loading on native
+    // platforms
+    if cfg!(target_arch = "wasm32") {
+        Image::new("resources/ferris.png")
+    } else {
+        Image::new(format!(
+            "{}/examples/resources/ferris.png",
+            env!("CARGO_MANIFEST_DIR")
+        ))
+    }
+    .width(Length::Units(width))
+    .align_self(Align::Center)
+}
+
 fn button<'a, Message>(
     state: &'a mut button::State,
     label: &str,
-- 
cgit 


From ba470a2b2a334fa961af19ef9412ad2dfb4acbeb Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Tue, 5 Nov 2019 02:58:42 +0100
Subject: Remove unnecessary code in `Value`

---
 core/src/widget/text_input.rs | 19 +------------------
 1 file changed, 1 insertion(+), 18 deletions(-)

diff --git a/core/src/widget/text_input.rs b/core/src/widget/text_input.rs
index 6c7dff67..e5d6b70d 100644
--- a/core/src/widget/text_input.rs
+++ b/core/src/widget/text_input.rs
@@ -1,7 +1,5 @@
 use crate::Length;
 
-use std::ops::{Index, RangeTo};
-
 pub struct TextInput<'a, Message> {
     pub state: &'a mut State,
     pub placeholder: String,
@@ -93,13 +91,6 @@ impl State {
         Self::default()
     }
 
-    pub fn focused() -> Self {
-        Self {
-            is_focused: true,
-            ..Self::default()
-        }
-    }
-
     pub fn move_cursor_right(&mut self, value: &Value) {
         let current = self.cursor_position(value);
 
@@ -134,7 +125,7 @@ impl Value {
     }
 
     pub fn until(&self, index: usize) -> Self {
-        Self(self.0[..index].iter().cloned().collect())
+        Self(self.0[..index.min(self.len())].iter().cloned().collect())
     }
 
     pub fn to_string(&self) -> String {
@@ -155,11 +146,3 @@ impl Value {
         self.0.remove(index);
     }
 }
-
-impl Index<RangeTo<usize>> for Value {
-    type Output = [char];
-
-    fn index(&self, index: RangeTo<usize>) -> &[char] {
-        &self.0[index]
-    }
-}
-- 
cgit 


From 470266f54069a1c9b6147026d018b437b6457f7b Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Tue, 5 Nov 2019 03:16:46 +0100
Subject: Add horizontal offset to `Primitive::Clip`

---
 core/src/vector.rs              | 21 ++++++++++++++++-----
 native/src/lib.rs               |  4 +---
 wgpu/src/primitive.rs           |  4 ++--
 wgpu/src/renderer.rs            | 28 +++++++++++++++++-----------
 wgpu/src/renderer/scrollable.rs |  4 ++--
 wgpu/src/renderer/text_input.rs |  4 ++--
 6 files changed, 40 insertions(+), 25 deletions(-)

diff --git a/core/src/vector.rs b/core/src/vector.rs
index f45daab9..92bf64ff 100644
--- a/core/src/vector.rs
+++ b/core/src/vector.rs
@@ -1,15 +1,26 @@
 /// A 2D vector.
 #[derive(Debug, Clone, Copy, PartialEq)]
-pub struct Vector {
-    pub x: f32,
-    pub y: f32,
+pub struct Vector<T = f32> {
+    pub x: T,
+    pub y: T,
 }
 
-impl Vector {
+impl<T> Vector<T> {
     /// Creates a new [`Vector`] with the given components.
     ///
     /// [`Vector`]: struct.Vector.html
-    pub fn new(x: f32, y: f32) -> Self {
+    pub fn new(x: T, y: T) -> Self {
         Self { x, y }
     }
 }
+
+impl<T> std::ops::Add for Vector<T>
+where
+    T: std::ops::Add<Output = T>,
+{
+    type Output = Self;
+
+    fn add(self, b: Self) -> Self {
+        Self::new(self.x + b.x, self.y + b.y)
+    }
+}
diff --git a/native/src/lib.rs b/native/src/lib.rs
index fa72a553..56399e57 100644
--- a/native/src/lib.rs
+++ b/native/src/lib.rs
@@ -211,10 +211,8 @@ mod node;
 mod style;
 mod user_interface;
 
-pub(crate) use iced_core::Vector;
-
 pub use iced_core::{
-    Align, Background, Color, Justify, Length, Point, Rectangle,
+    Align, Background, Color, Justify, Length, Point, Rectangle, Vector,
 };
 
 #[doc(no_inline)]
diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs
index 354b0851..8e40e3a6 100644
--- a/wgpu/src/primitive.rs
+++ b/wgpu/src/primitive.rs
@@ -1,4 +1,4 @@
-use iced_native::{text, Background, Color, Rectangle};
+use iced_native::{text, Background, Color, Rectangle, Vector};
 
 #[derive(Debug, Clone)]
 pub enum Primitive {
@@ -25,7 +25,7 @@ pub enum Primitive {
     },
     Clip {
         bounds: Rectangle,
-        offset: u32,
+        offset: Vector<u32>,
         content: Box<Primitive>,
     },
 }
diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs
index fbc39327..ca4cbb58 100644
--- a/wgpu/src/renderer.rs
+++ b/wgpu/src/renderer.rs
@@ -1,7 +1,7 @@
 use crate::{quad, Image, Primitive, Quad, Transformation};
 use iced_native::{
     renderer::Debugger, renderer::Windowed, Background, Color, Layout,
-    MouseCursor, Point, Rectangle, Widget,
+    MouseCursor, Point, Rectangle, Vector, Widget,
 };
 
 use raw_window_handle::HasRawWindowHandle;
@@ -44,17 +44,17 @@ pub struct Target {
 
 pub struct Layer<'a> {
     bounds: Rectangle<u32>,
-    y_offset: u32,
+    offset: Vector<u32>,
     quads: Vec<Quad>,
     images: Vec<Image>,
     text: Vec<wgpu_glyph::Section<'a>>,
 }
 
 impl<'a> Layer<'a> {
-    pub fn new(bounds: Rectangle<u32>, y_offset: u32) -> Self {
+    pub fn new(bounds: Rectangle<u32>, offset: Vector<u32>) -> Self {
         Self {
             bounds,
-            y_offset,
+            offset,
             quads: Vec::new(),
             images: Vec::new(),
             text: Vec::new(),
@@ -157,7 +157,7 @@ impl Renderer {
                 width: u32::from(target.width),
                 height: u32::from(target.height),
             },
-            0,
+            Vector::new(0, 0),
         ));
 
         self.draw_primitive(primitive, &mut layers);
@@ -257,7 +257,10 @@ impl Renderer {
                 border_radius,
             } => {
                 layer.quads.push(Quad {
-                    position: [bounds.x, bounds.y - layer.y_offset as f32],
+                    position: [
+                        bounds.x - layer.offset.x as f32,
+                        bounds.y - layer.offset.y as f32,
+                    ],
                     scale: [bounds.width, bounds.height],
                     color: match background {
                         Background::Color(color) => color.into_linear(),
@@ -279,15 +282,15 @@ impl Renderer {
             } => {
                 let clip_layer = Layer::new(
                     Rectangle {
-                        x: bounds.x as u32,
-                        y: bounds.y as u32 - layer.y_offset,
+                        x: bounds.x as u32 - layer.offset.x,
+                        y: bounds.y as u32 - layer.offset.y,
                         width: bounds.width as u32,
                         height: bounds.height as u32,
                     },
-                    layer.y_offset + offset,
+                    layer.offset + *offset,
                 );
 
-                let new_layer = Layer::new(layer.bounds, layer.y_offset);
+                let new_layer = Layer::new(layer.bounds, layer.offset);
 
                 layers.push(clip_layer);
 
@@ -307,7 +310,10 @@ impl Renderer {
         target: &wgpu::TextureView,
     ) {
         let translated = transformation
-            * Transformation::translate(0.0, -(layer.y_offset as f32));
+            * Transformation::translate(
+                -(layer.offset.x as f32),
+                -(layer.offset.y as f32),
+            );
 
         if layer.quads.len() > 0 {
             self.quad_pipeline.draw(
diff --git a/wgpu/src/renderer/scrollable.rs b/wgpu/src/renderer/scrollable.rs
index 72d77cc8..360759a5 100644
--- a/wgpu/src/renderer/scrollable.rs
+++ b/wgpu/src/renderer/scrollable.rs
@@ -1,7 +1,7 @@
 use crate::{Primitive, Renderer};
 use iced_native::{
     scrollable, Background, Color, Layout, MouseCursor, Point, Rectangle,
-    Scrollable, Widget,
+    Scrollable, Vector, Widget,
 };
 
 const SCROLLBAR_WIDTH: u16 = 10;
@@ -58,7 +58,7 @@ impl scrollable::Renderer for Renderer {
 
         let clip = Primitive::Clip {
             bounds,
-            offset,
+            offset: Vector::new(0, offset),
             content: Box::new(content),
         };
 
diff --git a/wgpu/src/renderer/text_input.rs b/wgpu/src/renderer/text_input.rs
index deb8eae7..95ea964e 100644
--- a/wgpu/src/renderer/text_input.rs
+++ b/wgpu/src/renderer/text_input.rs
@@ -2,7 +2,7 @@ use crate::{Primitive, Renderer};
 
 use iced_native::{
     text::HorizontalAlignment, text::VerticalAlignment, text_input, Background,
-    Color, MouseCursor, Point, Rectangle, TextInput,
+    Color, MouseCursor, Point, Rectangle, TextInput, Vector,
 };
 use std::f32;
 
@@ -89,7 +89,7 @@ impl text_input::Renderer for Renderer {
 
         let content = Primitive::Clip {
             bounds: text_bounds,
-            offset: 0,
+            offset: Vector::new(0, 0),
             content: Box::new(if text_input.state.is_focused {
                 use wgpu_glyph::{GlyphCruncher, Scale, Section};
 
-- 
cgit 


From a2161586dab6837d8c641b6f93ad476f861d8580 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Tue, 5 Nov 2019 03:33:24 +0100
Subject: Implement state-less scrolling in `TextInput`

---
 wgpu/src/renderer/text_input.rs | 121 +++++++++++++++++++++-------------------
 1 file changed, 65 insertions(+), 56 deletions(-)

diff --git a/wgpu/src/renderer/text_input.rs b/wgpu/src/renderer/text_input.rs
index 95ea964e..cff8bf23 100644
--- a/wgpu/src/renderer/text_input.rs
+++ b/wgpu/src/renderer/text_input.rs
@@ -87,70 +87,79 @@ impl text_input::Renderer for Renderer {
             vertical_alignment: VerticalAlignment::Center,
         };
 
-        let content = Primitive::Clip {
-            bounds: text_bounds,
-            offset: Vector::new(0, 0),
-            content: Box::new(if text_input.state.is_focused {
-                use wgpu_glyph::{GlyphCruncher, Scale, Section};
-
-                let text_before_cursor = &text_input
-                    .value
-                    .until(text_input.state.cursor_position(&text_input.value))
-                    .to_string();
-
-                let mut text_value_width = self
-                    .glyph_brush
-                    .borrow_mut()
-                    .glyph_bounds(Section {
-                        text: text_before_cursor,
-                        bounds: (f32::INFINITY, text_bounds.height),
-                        scale: Scale { x: size, y: size },
-                        ..Default::default()
-                    })
-                    .map(|bounds| bounds.width().round())
-                    .unwrap_or(0.0);
-
-                let spaces_at_the_end = text_before_cursor.len()
-                    - text_before_cursor.trim_end().len();
-
-                if spaces_at_the_end > 0 {
-                    let space_width = {
-                        let glyph_brush = self.glyph_brush.borrow();
-
-                        // TODO: Select appropriate font
-                        let font = &glyph_brush.fonts()[0];
-
-                        font.glyph(' ')
-                            .scaled(Scale { x: size, y: size })
-                            .h_metrics()
-                            .advance_width
-                    };
-
-                    text_value_width += spaces_at_the_end as f32 * space_width;
-                }
-
-                let cursor = Primitive::Quad {
-                    bounds: Rectangle {
-                        x: text_bounds.x + text_value_width,
-                        y: text_bounds.y,
-                        width: 1.0,
-                        height: text_bounds.height,
-                    },
-                    background: Background::Color(Color::BLACK),
-                    border_radius: 0,
+        let (contents_primitive, offset) = if text_input.state.is_focused {
+            use wgpu_glyph::{GlyphCruncher, Scale, Section};
+
+            let text_before_cursor = &text_input
+                .value
+                .until(text_input.state.cursor_position(&text_input.value))
+                .to_string();
+
+            let mut text_value_width = self
+                .glyph_brush
+                .borrow_mut()
+                .glyph_bounds(Section {
+                    text: text_before_cursor,
+                    bounds: (f32::INFINITY, text_bounds.height),
+                    scale: Scale { x: size, y: size },
+                    ..Default::default()
+                })
+                .map(|bounds| bounds.width().round())
+                .unwrap_or(0.0);
+
+            let spaces_at_the_end =
+                text_before_cursor.len() - text_before_cursor.trim_end().len();
+
+            if spaces_at_the_end > 0 {
+                let space_width = {
+                    let glyph_brush = self.glyph_brush.borrow();
+
+                    // TODO: Select appropriate font
+                    let font = &glyph_brush.fonts()[0];
+
+                    font.glyph(' ')
+                        .scaled(Scale { x: size, y: size })
+                        .h_metrics()
+                        .advance_width
                 };
 
+                text_value_width += spaces_at_the_end as f32 * space_width;
+            }
+
+            let cursor = Primitive::Quad {
+                bounds: Rectangle {
+                    x: text_bounds.x + text_value_width,
+                    y: text_bounds.y,
+                    width: 1.0,
+                    height: text_bounds.height,
+                },
+                background: Background::Color(Color::BLACK),
+                border_radius: 0,
+            };
+
+            (
                 Primitive::Group {
                     primitives: vec![value, cursor],
-                }
-            } else {
-                value
-            }),
+                },
+                Vector::new(
+                    ((text_value_width + 5.0) - text_bounds.width).max(0.0)
+                        as u32,
+                    0,
+                ),
+            )
+        } else {
+            (value, Vector::new(0, 0))
+        };
+
+        let contents = Primitive::Clip {
+            bounds: text_bounds,
+            offset,
+            content: Box::new(contents_primitive),
         };
 
         (
             Primitive::Group {
-                primitives: vec![border, input, content],
+                primitives: vec![border, input, contents],
             },
             if is_mouse_over {
                 MouseCursor::Text
-- 
cgit