Compare commits

...

839 Commits

Author SHA1 Message Date
2dc42b4a22 Use less iterator magic to avoid compile error on phone 2021-06-26 20:27:44 +01:00
343e6332d7 Format code 2021-06-26 20:19:55 +01:00
3a5f866782 Downgrade OpenGL and GLSL for glow renderer 2021-06-26 20:19:51 +01:00
e4b626b91f Use glow_glyph_compat 2021-06-26 19:47:12 +01:00
45ecf02504 Add tour_glow for OpenGL platforms 2021-06-26 16:09:25 +01:00
Héctor Ramón Jiménez
1b6cf05f5f
Install libxkbcommon-dev for ubuntu-latest in CI 2021-06-26 12:19:23 +02:00
Héctor Ramón
c6c3594c83
Merge pull request #927 from diegodox/fix-typo
Fix typo in documentation of `canvas::Program`
2021-06-26 11:57:31 +02:00
Héctor Ramón
06d0158efb
Merge pull request #917 from derezzedex/macos-url
Enable receiving URLs on MacOS
2021-06-25 14:47:14 +02:00
Richard
612585109f
Use winit and glutin forks in iced-rs org 2021-06-25 14:15:11 +02:00
Richard
96a462d2f2
Use new enum variant and new winit repo 2021-06-25 14:14:03 +02:00
Richard
9ae22b58d8
Added events for url handling and create example 2021-06-25 14:14:03 +02:00
Héctor Ramón
d2c8a3e04b
Merge pull request #919 from Imberflur/winit-0.25
Bump winit to 0.25
2021-06-24 19:30:59 +02:00
Imbris
ba51661a2a Bump winit to 0.25 2021-06-23 17:38:08 -04:00
Diego Fujii
80df17ab55 fix-typo 2021-06-24 00:16:08 +09:00
Héctor Ramón
b62fcca9b9
Merge pull request #915 from yusdacra/docs/update-links
docs: update all 0.2 github links to 0.3
2021-06-22 12:19:38 +02:00
Héctor Ramón
94ee2566c4
Merge pull request #920 from clarkmoody/feature/pane-grid-title-bar-overlay
Pane Grid Title Bar Overlay
2021-06-22 12:02:07 +02:00
Héctor Ramón
bb6e06127e
Merge pull request #925 from PolyMeilex/master
Update `wgpu` to `0.9`
2021-06-22 11:39:18 +02:00
Héctor Ramón Jiménez
15c17a7250
Use match statement in Content::overlay
... to improve readability a bit.
2021-06-22 11:36:36 +02:00
Poly
a53e7559fe Use vertex_attr_array macro 2021-06-22 11:23:11 +02:00
Poly
c70f90f320 Update wgpu 0.9 2021-06-22 11:23:10 +02:00
Clark Moody
27b42ca6b6 Allow overlay from pane grid title bar 2021-06-17 14:51:23 -05:00
Yusuf Bera Ertan
83d19689c8
docs: update all 0.2 github links to 0.3 2021-06-14 21:01:37 +03:00
Héctor Ramón
e68da229b3
Merge pull request #646 from mtsr/disable-button
Disabled button docs and consistent behavior
2021-06-10 19:12:11 +07:00
Héctor Ramón
d1797dda87 Revert changes in tour example 2021-06-10 18:58:44 +07:00
Héctor Ramón
d46dd67a91 Update disabled example of Button in docs 2021-06-10 18:58:40 +07:00
Jonas Matser
e66120b9c1 Fix failing doctests 2021-06-10 18:28:38 +07:00
Jonas Matser
dbc1181011 Adds doc comment for disabled button
Makes disabled button behavior consistent in web
2021-06-10 18:28:37 +07:00
Héctor Ramón
f6ff87bb8f
Merge pull request #818 from thenlevy/check_bounds
Prevent scissor_rect region to be larger than the target texture in wgpu::Backend::flush
2021-06-10 18:24:42 +07:00
Héctor Ramón
56f673d819 Revert "Attempt to fix scissor_rect validation error"
This reverts commit 656dc357f87849f2506ce402f8484a7d7484f250.
2021-06-09 21:30:48 +07:00
Héctor Ramón
5224cc7f26 Floor width and height in Rectangle::floor 2021-06-09 21:30:20 +07:00
nlevy
656dc357f8 Attempt to fix scissor_rect validation error
Update wgpu/src/backend.rs

Cargo fmt
2021-06-09 21:30:00 +07:00
Héctor Ramón
0e70b11e00
Merge pull request #607 from yusdacra/scrollable_programmatically
Add methods to control `Scrollable` programmatically
2021-06-07 22:00:07 +07:00
Héctor Ramón
ce3a5f19b9 Add scrolling progress indicators to scrollable example 2021-06-04 20:46:47 +07:00
Héctor Ramón
3051d4ec76 Introduce on_scroll event in Scrollable 2021-06-04 20:46:27 +07:00
Héctor Ramón
57510c43c8 Add buttons to control scrolling in scrollable example 2021-06-04 20:15:06 +07:00
Héctor Ramón
827577c179 Introduce snap_to and unsnap to scrollable::State 2021-06-04 20:09:15 +07:00
Yusuf Bera Ertan
f7d6e40bf0 feat(native): Make scrollable programmatically scrollable for some use cases, add snap_to_bottom by default 2021-06-04 19:29:58 +07:00
Héctor Ramón
397a5c06ec
Merge pull request #535 from Kaiden42/toggler
Implement `Toggler` widget for iced_native
2021-06-03 20:55:50 +07:00
Héctor Ramón
d3d6f3efb3 Add some horizontal padding to toggler section in tour example 2021-06-03 20:35:26 +07:00
Héctor Ramón
ef5f46bcdd Use intra-doc links in Toggler docs 2021-06-03 20:28:36 +07:00
Héctor Ramón
a32ce271bd Rename text_align to text_alignment in Toggler 2021-06-03 20:27:32 +07:00
Kaiden42
2a5aa69024 Fix format 2021-06-03 20:21:55 +07:00
Kaiden42
e00fca6372 Add Toggler widget to iced_web 2021-06-03 20:21:55 +07:00
Kaiden42
c0cfd9d5cf Update documentation of Toggler 2021-06-03 20:21:55 +07:00
Kaiden42
be3ee9adf1 Add Toggler to tour example 2021-06-03 20:21:55 +07:00
Kaiden42
1ef38cc207 Add Toggler to styling example 2021-06-03 20:21:55 +07:00
Kaiden42
7a626f3b7b Change label of Toggler to optional 2021-06-03 20:21:55 +07:00
Kaiden42
aa18a6e0d5 Add alignment of Toggler label. 2021-06-03 20:21:55 +07:00
Kaiden42
bab71971fb fix format 2021-06-03 20:21:55 +07:00
Kaiden42
88da268724 add missing glow support 2021-06-03 20:21:53 +07:00
Kaiden42
7370dfac6e fix missing semicolon in doc test 2021-06-03 20:21:04 +07:00
Kaiden42
52a185fbab Implement Toggler widget for iced_native 2021-06-03 20:21:02 +07:00
Héctor Ramón
1dce929dfc
Merge pull request #893 from traxys/drag_and_drop
Allow disabling drag and drop on windows
2021-06-01 19:59:33 +07:00
Héctor Ramón
aab2176802
Merge pull request #630 from blefevre/asymmetric-padding
Add support for asymmetrical padding
2021-06-01 19:59:02 +07:00
Héctor Ramón
8a3b71df8b Replace ignored doc-tests with additional documentation for Padding 2021-06-01 19:45:47 +07:00
Héctor Ramón
b94cd7a2a8 Use Padding::horizontal and Padding::vertical helpers 2021-06-01 19:21:43 +07:00
Héctor Ramón
2e17d7860b Fix unused variable warning in iced_web::text_input 2021-06-01 19:14:04 +07:00
Héctor Ramón
0a14492343 Fix Tooltip widget 2021-06-01 19:13:52 +07:00
Héctor Ramón
92361ef07d Fix overlay::Menu implementation 2021-06-01 19:13:34 +07:00
Héctor Ramón
d83e263abe Introduce vertical and horizontal methods to Padding 2021-06-01 19:13:11 +07:00
Ben LeFevre
fe0a27c56d Add support for asymmetrical padding 2021-06-01 19:05:39 +07:00
Héctor Ramón
903570846e Fix documentation of PlatformSpecific settings 2021-06-01 18:57:36 +07:00
Héctor Ramón
a9eb591628
Merge pull request #901 from hecrj/feature/default-rule-style
Implement `Default` for `Style` in `rule`
2021-06-01 18:54:08 +07:00
Héctor Ramón
662889bb83 Implement Default for Style in rule 2021-06-01 18:32:56 +07:00
Quentin Boyer
f04bc94b80 allow disabling drag and drop on windows 2021-05-27 14:22:11 +02:00
Héctor Ramón
e292821c37
Merge pull request #892 from clarkmoody/title-bar-events
PaneGrid Events in Title Bar Area
2021-05-25 16:34:17 +07:00
Clark Moody
d4c5f3ee95 Enable event handling within the title elements
Shrink the pick area to avoid both the controls and the title elements.
Handle events and merge title area event status with control events.
2021-05-24 16:37:47 -05:00
Clark Moody
1a2fd4e743 Example: Add Pin button to prevent closing a pane
Functionality will not work until PaneGrid implementation is updated
to support events within the title area.
2021-05-24 15:53:20 -05:00
Clark Moody
e6f8b32583 Example: Add close button to pane grid controls
Refactors the state data structure to hold content and controls in
separate fields. Adds a new button style for the control button.
2021-05-24 14:28:52 -05:00
Héctor Ramón
df971ac99b
Merge pull request #830 from Dispersia/upgrade-wgpu
Upgrade wgpu
2021-05-24 20:26:56 +07:00
Héctor Ramón
4cbc345245 Use FilterMode::Nearest in triangle::msaa 2021-05-21 20:34:08 +07:00
Héctor Ramón
ebec84ea7c Revert "Remove padding from triangle"
This reverts commit 2d549d806cd9ff1d7b7b237d818cd24c84957c83.
2021-05-21 20:29:17 +07:00
Dispersia
0772310c4f Fix duplicating fragment position 2021-05-20 23:10:22 -07:00
Dispersia
a70715ad9e run format 2021-05-19 22:07:27 -07:00
Dispersia
2d549d806c Remove padding from triangle 2021-05-19 21:09:19 -07:00
Dispersia
b40c441646 Add padding to quad to fix alignment issue 2021-05-19 21:04:47 -07:00
Dispersia
d91422e345 temporary up 2021-05-19 08:09:03 -07:00
Aaron Housh
ae484429d3 Merge branch 'hecrj:master' into upgrade-wgpu 2021-05-19 07:14:26 -07:00
Héctor Ramón
cf6af4c256 Use latest wgpu releases instead of patched sources 2021-05-19 17:18:43 +07:00
Héctor Ramón
8b7452a55d Fix formatting with cargo fmt 2021-05-19 16:26:04 +07:00
Héctor Ramón
3918257883
Merge pull request #886 from Chiheisen/fix/pick_list_layouting
pick_list: fix layouting not respecting fonts
2021-05-19 15:40:17 +07:00
chiheisen
59f3896392 fix pick_list layouting not respecting fonts 2021-05-18 12:37:23 +02:00
zdevwu
40d21d2365
Added text color and font options for native radio and checkbox (#831)
* text color and font options to radio

* code formatting

* code formatting

* code formatting

* Added text_color for native checkbox

* Removed clone as color has Copy

* Fix code formatting with `cargo fmt`

Co-authored-by: Héctor Ramón <hector@lich.io>
2021-05-17 20:22:55 +07:00
Héctor Ramón
0ce6a2db21
Merge pull request #876 from Cupnfish/master
Add a primary backend that can be set
2021-05-17 19:54:28 +07:00
Héctor Ramón
70ee917bac
Merge pull request #875 from ZakisM/optimize_svg_algorithm
This commit optimizes the algorithm used to convert rgba pixels into bgra pixels for SVG's.
2021-05-17 19:51:17 +07:00
Downtime
88defb65ca update doc 2021-05-14 21:21:25 +08:00
Héctor Ramón
faa68534cf
Merge pull request #877 from RDambrosio016/patch-1
Change examples to point to 0.3 examples, not 0.2
2021-05-14 20:05:49 +07:00
Riccardo D'Ambrosio
5f1b880521
Change examples to point to 0.3 examples, not 0.2 2021-05-13 11:04:09 -04:00
Downtime
e6db439870 Add a primary backend that can be set
Add a primary backend that can be set
2021-05-13 16:46:20 +08:00
Zak
77a17cde83 This commit optimizes the function used to converg rgba pixels into bgra pixels. 2021-05-11 22:41:55 +01:00
Héctor Ramón
08f5591148
Merge pull request #868 from hecrj/wgpu-compatible-surface
Provide `compatible_surface` in `iced_wgpu::Compositor`
2021-05-08 01:24:26 +07:00
Héctor Ramón
3840b75bea Provide compatible_surface in iced_wgpu::Compositor 2021-05-05 14:33:30 +07:00
Héctor Ramón
6b4bf34bf9
Merge pull request #851 from hecrj/fix/scrollbar-under-content
Fix `Scrollable` scrollbar being rendered behind contents
2021-05-04 13:03:43 +07:00
Héctor Ramón
59c2500c55 Fix Scrollable scrollbar being rendered behind contents
... by issuing a new clip layer just for the scrollbar itself.
2021-05-03 15:42:02 +07:00
Dispersia
983aa1b366 Run cargo fmt 2021-04-12 23:23:47 -07:00
Dispersia
0722d5e3ec add temporary fix for image wgsl 2021-04-12 23:07:58 -07:00
Dispersia
c719091c3d Add staging belt fix 2021-04-12 22:06:16 -07:00
Dispersia
9a2c78c405 Upgrade wgpu 2021-04-11 18:55:57 -07:00
Héctor Ramón
4b8ba8309f
Merge pull request #825 from tarkah/feat/window-visibility
add window visibility
2021-04-11 10:38:52 +07:00
Cory Forsstrom
84c0c9bc7a use Mode::Hidden instead 2021-04-09 09:04:30 -07:00
Cory Forsstrom
6f6f1d82e8 add to glutin 2021-04-08 13:30:38 -07:00
Cory Forsstrom
cdab8f90fb add window visibility 2021-04-08 12:58:08 -07:00
Héctor Ramón
3ea2c4595a
Merge pull request #815 from taiki-e/docs
Enable qr_code feature on docs.rs
2021-04-06 13:47:30 +07:00
Taiki Endo
8473d8e984 Enable qr_code feature on docs.rs 2021-04-06 02:46:44 +09:00
Héctor Ramón
854b2e0c4d
Merge pull request #810 from Cupnfish/master
fix typo
2021-04-01 17:54:39 +02:00
Downtime
ca4257ff5c Update frame.rs 2021-04-01 21:58:25 +08:00
Héctor Ramón Jiménez
90fee3a923 Fix iced_wgpu link in CHANGELOG 2021-03-31 20:46:59 +02:00
Héctor Ramón
06517aa7e8
Merge pull request #806 from hecrj/release/0.3.0
Release 0.3 — Touch support, clipboard write access, image viewer, tooltips, and more!
2021-03-31 20:34:45 +02:00
Héctor Ramón Jiménez
0864e63bde Bump versions 🎉 2021-03-31 20:07:17 +02:00
Héctor Ramón Jiménez
2b20512a3d Update CHANGELOG 2021-03-31 19:59:23 +02:00
Héctor Ramón
b9ec44446e
Merge pull request #804 from hecrj/feature/graceful-exit
Graceful exiting for `Application`
2021-03-31 10:20:22 +02:00
Héctor Ramón Jiménez
8f952452ce Showcase graceful exiting in events example 2021-03-30 21:45:49 +02:00
Héctor Ramón Jiménez
67db13ff7c Add support for graceful exits in Application
- `Settings` now contains an `exit_on_close_request` field
- `Application` has a new `should_exit` method
2021-03-30 21:44:19 +02:00
Héctor Ramón Jiménez
00de9d0c9b Add CloseRequested variant to window::Event 2021-03-30 21:33:57 +02:00
Héctor Ramón
bbb4e4678f
Merge pull request #796 from hecrj/fix/redraw-empty-window
Skip redrawing if window has no surface
2021-03-26 15:16:28 +01:00
Héctor Ramón Jiménez
1207afa7d0 Skip redrawing if window has no surface 2021-03-26 14:46:19 +01:00
Héctor Ramón
bf09f44d56
Merge pull request #789 from Cupnfish/master
Add WGPU_BACKEND environment variable
2021-03-25 11:41:52 +01:00
Héctor Ramón Jiménez
883c7e71ae Introduce internal_backend to iced_wgpu::Settings 2021-03-25 11:29:40 +01:00
Downtime
ab8dcf91bd Support choosing wgpu backend using env var 2021-03-25 11:29:26 +01:00
Héctor Ramón Jiménez
2b520ca098 Convert ScaleFactorChanged into Resized events in iced_glutin
... instead of just dropping them when calling `to_static`.
2021-03-24 05:29:19 +01:00
Héctor Ramón Jiménez
d66a34b272 Convert ScaleFactorChanged into Resized events in iced_winit
... instead of just dropping them when calling `to_static`.
2021-03-24 04:59:13 +01:00
Nicolas Levy
0333a8daff
Overwrite overlay method in Widget implementation for Button (#764)
* Overwrite `overlay` method in Widget implementation for Button

* Overwrite `overlay` method in Widget implementation for Button (cargo fmt)

* Fix button overlay
2021-03-14 23:39:01 +01:00
Héctor Ramón
c1f70f1e92
Merge pull request #773 from hecrj/feature/clipboard-access-in-update
Clipboard access in `Application::update`
2021-03-12 02:54:13 +01:00
Héctor Ramón Jiménez
7da3fb1b22 Implement stub Clipboard in iced_web
We need to figure out browser permissions and use of unstable `web-sys`
APIs
2021-03-11 03:52:41 +01:00
Héctor Ramón Jiménez
a365998264 Expose read and write methods in iced_winit::Clipboard directly 2021-03-11 03:49:15 +01:00
Héctor Ramón Jiménez
ae517b9fa0 Add clipboard argument to Application::update 2021-03-11 03:38:20 +01:00
Héctor Ramón
7eb5127748
Merge pull request #770 from hecrj/feature/clipboard-write
Write clipboard support and `TextInput` copy and cut behavior
2021-03-10 21:13:07 +01:00
Héctor Ramón
939fcfe9db
Merge pull request #771 from hecrj/fix/tooltip-layering
Reposition `Tooltip` inside `viewport` bounds
2021-03-10 03:28:04 +01:00
Héctor Ramón Jiménez
17dcfa8faf Implement copy and cut behavior for TextInput 2021-03-10 01:59:20 +01:00
Héctor Ramón Jiménez
21971e0037 Make Clipboard argument in Widget trait mutable 2021-03-10 01:59:02 +01:00
Héctor Ramón Jiménez
35425001ed Introduce write method to Clipboard trait 2021-03-10 01:18:22 +01:00
Héctor Ramón Jiménez
b22b0dd7ff Update window_clipboard to 0.2 2021-03-10 01:16:26 +01:00
Héctor Ramón Jiménez
bbca5c4bde Call hash_layout for controls in pane_grid::TitleBar 2021-03-09 04:49:17 +01:00
Héctor Ramón
a74974a8e4
Merge pull request #760 from TriedAngle/master
Update: rand in solar_system example
2021-03-05 03:10:55 +01:00
Sebastian
5f27ed4720 Update: rand 2021-03-03 01:23:18 +01:00
Héctor Ramón Jiménez
c51b771519 Reposition Tooltip inside viewport bounds
... only when out of bounds.
2021-02-27 03:47:13 +01:00
Héctor Ramón Jiménez
f52f8c1337 Fix viewport argument in PaneGrid draw calls 2021-02-27 03:36:46 +01:00
Héctor Ramón
a5fddf9ee6
Merge pull request #465 from yusdacra/tooltip-widget
Tooltip widget
2021-02-24 01:42:08 +01:00
Héctor Ramón Jiménez
2736e4ca35 Hide Text as an implementation detail of Tooltip 2021-02-24 00:59:29 +01:00
Héctor Ramón Jiménez
5e2743361b Generate new layers only for clip primitives in Layer::generate 2021-02-23 04:02:55 +01:00
Héctor Ramón Jiménez
4e923290cc Add style and padding to Tooltip 2021-02-23 04:00:35 +01:00
Héctor Ramón Jiménez
9d4996cbab Export Tooltip in iced_glow 2021-02-23 03:18:47 +01:00
Héctor Ramón Jiménez
2f766b7341 Introduce Tooltip::gap to control spacing 2021-02-23 03:16:37 +01:00
Héctor Ramón Jiménez
9f60a256fc Remove viewport from Overlay::draw for now 2021-02-23 03:12:00 +01:00
Héctor Ramón Jiménez
81c75c1524 Change Tooltip to support Text only for now 2021-02-23 03:09:16 +01:00
Héctor Ramón Jiménez
6759a5c56f Log event subscription error as a warning 2021-02-23 02:16:12 +01:00
Héctor Ramón
842d54732b
Merge pull request #739 from hecrj/fix/beta-warnings
Fix warnings in the `beta` toolchain
2021-02-16 00:41:06 +01:00
Héctor Ramón Jiménez
ec20763aef Use string literal as panic message in iced_glow 2021-02-16 00:04:36 +01:00
Héctor Ramón Jiménez
9ba9558429 Allow dead code explicitly in iced_web 2021-02-16 00:03:20 +01:00
Yusuf Bera Ertan
a19f89d3a6
feat(native): add Tooltip widget 2021-02-15 19:37:46 +03:00
Héctor Ramón
4de164dcc7
Merge pull request #392 from unrelentingtech/image-debloat
Add image format options to reduce code bloat
2021-02-13 16:18:40 +01:00
Héctor Ramón Jiménez
e1b1227f0c Fix image feature name in glow and iced 2021-02-13 16:05:51 +01:00
Greg V
8f126c212b Add image format options to reduce code bloat, fixes #376 2021-02-13 15:53:24 +01:00
Folyd
9f5c2eb0c4
Improve download_progress example (#283)
* Add advanced download example

* Rename to task fields and variables

* Cargo fmt advanced_download/src/download.rs

* Add progress bar for advanced download example

* Merge two download examples to single one

* Apply great review suggestions

* Change to url::Url instead of plain String

* Simplify `download_progress` example

* Update `README` of `download_progress` example

Co-authored-by: Héctor Ramón Jiménez <hector0193@gmail.com>
2021-02-12 22:00:52 +01:00
anunge
9e453843b2
Touch support for PaneGrid and PickList (#650)
* touch events properly parsed and converted to logical size, button working

* scrolling with a nice touch

* fixed application state level touch cursor. panel_grid is touchable now.

* format glicthes fixes

* format glitches

* tight format

* fixed pane grid

* fixing with upstream

* Remove unused `touch` module from `iced_core`

* Remove unused `crate::text` import in `iced_native`

* Remove redundant match branch in `iced_winit`

* Keep removed line break in `UserInterface::update`

* Compute `text_size` only when bounds contains cursor in `overlay::menu`

Co-authored-by: Héctor Ramón Jiménez <hector0193@gmail.com>
2021-02-12 20:52:20 +01:00
Héctor Ramón
2f10a1f2a2
Merge pull request #725 from PolyMeilex/wgpu-7.0
Update to wgpu 0.7
2021-02-06 16:18:19 +01:00
Héctor Ramón Jiménez
74b9ea520f Enable filtering in wgpu::image 2021-02-06 16:04:43 +01:00
Héctor Ramón Jiménez
7eefad34fc List color_blend first in wgpu::quad 2021-02-06 15:55:03 +01:00
Héctor Ramón Jiménez
15c4901aba Remove unnecessary line break in triangle::msaa 2021-02-06 15:39:12 +01:00
Héctor Ramón Jiménez
ffdf87fbe2 Use lowercase in wgpu labels for consistency 2021-02-06 15:39:06 +01:00
Héctor Ramón Jiménez
5fc4210270 Use the latest release of wgpu_glyph 2021-02-06 15:27:27 +01:00
Poly
b0d1be69d6 Change PowerPreference from default() to LowPower
There is no reason to hide the fact that this is always in `LowPower` mode
2021-02-03 23:50:03 +01:00
Poly
09a5348740 [wgpu 0.7] Update integration example 2021-02-03 22:38:45 +01:00
Poly
1fb60c5dcb Fix TextureViewDimension for image
wgpu validation helped to find this long standing type error
2021-02-03 22:26:53 +01:00
Poly
bd6b8304bd Fix ScissorRect
- Breaks `TODO: Address anti-aliasing adjustments properly`
2021-02-03 21:51:11 +01:00
Poly
c5d6ddc126 [wgpu 0.7] triangle/msaa disable filtering 2021-02-03 21:13:51 +01:00
Poly
4a6db30d47 [wgpu 0.7] Update image.rs 2021-02-03 20:24:48 +01:00
Poly
e2595ac0aa [wgpu 0.7] Update triangle.rs 2021-02-03 20:06:07 +01:00
Poly
5f935c34fd [wgpu 0.7] Update triangle/msaa.rs
Notes:
- not sure if `filtering sampler` should be used, so for now it is not used
.
2021-02-03 20:05:37 +01:00
Poly
98d108d2b7 [wgpu 0.7] Update window/compositor.rs
Notes:
- wgpu::PowerPreference::Default no longer exists, maybe there is another way to replicate its behavior.
2021-02-03 19:32:30 +01:00
Poly
2d76c7165c [wgpu 0.7] Update quad.rs 2021-02-03 19:21:02 +01:00
Poly
4a727dfb8b The beginning of wgpu 0.7 update
hecrj/iced#723
2021-02-03 19:20:23 +01:00
Héctor Ramón
12c0c18d66
Merge pull request #720 from taiki-e/style-clone
impl Clone and Copy for all Style types in iced_style
2021-01-29 19:56:33 +01:00
Héctor Ramón
c7898a101c
Merge pull request #719 from taiki-e/error-send-sync
Make iced::Error Send + Sync
2021-01-29 19:55:25 +01:00
Taiki Endo
2969558afd impl Clone and Copy for all Style types in iced_style 2021-01-29 14:08:14 +09:00
Taiki Endo
14d900d835 Make iced::Error Send + Sync 2021-01-29 14:03:27 +09:00
GunpowderGuy
8d882d787e
update example description at sandbox's documentation (#710)
* Update sandbox.rs

* Update sandbox.rs

* format

Co-authored-by: Diego Rosario <diegorosario2013@gmail.com>
2021-01-22 01:36:05 +01:00
Héctor Ramón Jiménez
d1c4239ac7 Disable default features of qrcode for iced_graphics 2021-01-21 05:07:41 +01:00
Héctor Ramón Jiménez
9da0a3de54 Use smol::Timer::interval for time::Every 2021-01-15 21:07:37 +01:00
Héctor Ramón Jiménez
803cc88483 Fix consistency in CHANGELOG 2021-01-15 19:05:20 +01:00
Héctor Ramón
2056304e39
Merge pull request #699 from JayceFayne/smol
Add `smol` async runtime support
2021-01-15 19:04:23 +01:00
Héctor Ramón Jiménez
fd2c96c8e3 Fix time::Every implementation for smol runtime 2021-01-15 18:52:12 +01:00
Héctor Ramón Jiménez
bcc54b0831 Add latest release (0.2.0) to CHANGELOG 2021-01-15 18:37:20 +01:00
Héctor Ramón Jiménez
a42a0844c2 Keep old behavior for Executor feature flags 2021-01-15 18:31:30 +01:00
Héctor Ramón Jiménez
984583b0cc Merge pull request #701 from cossonfork/focus_event 2021-01-15 18:23:50 +01:00
Héctor Ramón Jiménez
45dc02e9bd Split window::Event::Focused into two variants 2021-01-15 18:21:44 +01:00
cossonleo
0b140488b4 add focus event 2021-01-15 22:40:16 +08:00
Héctor Ramón Jiménez
0646280d67 Fix Widget::width implementation for PickList 2021-01-15 14:26:23 +01:00
Héctor Ramón
049999b982
Merge pull request #700 from TannerRogalsky/fix_viewport_getter
Fix `physical_width` getter incorrectly returning the height
2021-01-15 02:02:26 +01:00
Tanner Rogalsky
766bb7f5cc Fix physical_width getter incorrectly returning the height 2021-01-14 10:38:12 -05:00
Jayce Fayne
c542224f4b Update CHANGELOG.md 2021-01-14 12:28:06 +01:00
Jayce Fayne
b2415eee61 Add smol async runtime 2021-01-14 12:28:02 +01:00
Héctor Ramón
92d647d1a6
Merge pull request #694 from hecrj/fix/image-viewer-event-capturing
Capture relevant events in `image::Viewer`
2021-01-12 20:06:32 +01:00
Héctor Ramón Jiménez
c7f6b2a5c7 Capture relevant events in image::Viewer 2021-01-11 19:31:34 +01:00
Héctor Ramón Jiménez
e7344d03b4 Use BTreeMap for splits and regions in pane_grid
This preserves ordering between calls to update and draw logic.
2021-01-07 21:07:44 +01:00
Héctor Ramón Jiménez
31522e30aa Remove unnecessary SaveError variant in todos example 2021-01-04 23:38:07 +01:00
Héctor Ramón
80a490ebb9
Merge pull request #672 from yusdacra/tokio-1.0
Update tokio to v1.0
2021-01-04 23:33:09 +01:00
Héctor Ramón Jiménez
09ea73bd2a Use Instant::into_std in futures::time 2021-01-04 23:20:40 +01:00
Yusuf Bera Ertan
50452e62b4 Update tokio to 1.0 2021-01-04 23:20:21 +01:00
Héctor Ramón
2665860b4d
Merge pull request #678 from hecrj/feature/pane-grid-split-highlight
Split highlight for the `PaneGrid` widget
2021-01-04 19:33:26 +01:00
Héctor Ramón Jiménez
a7bb7bb2ea Implement split highlight on hover for PaneGrid 2021-01-01 15:28:38 +01:00
Héctor Ramón
f8aef03456
Merge pull request #657 from clarkmoody/feature/pane-grid-title-contents
Generic Element Content in Pane Grid TitleBar
2020-12-22 14:58:39 +01:00
Héctor Ramón Jiménez
e815c5bbd7 Remove unnecessary lifetime bound in TitleBar 2020-12-22 14:47:18 +01:00
Héctor Ramón Jiménez
f2c2f3fc75 Remove unnecessary text::Renderer bound for PaneGrid
This is no longer necessary, as we do not render text directly anymore.
2020-12-22 14:44:44 +01:00
Héctor Ramón
a366600e73
Merge pull request #669 from hecrj/improvement/update-resvg-and-font-kit
Update `resvg` and `font-kit`
2020-12-20 02:50:38 +01:00
Héctor Ramón Jiménez
4bbfdef14b Update font-kit to 0.10 2020-12-19 01:24:46 +01:00
Greg V
81f37123ad Update resvg to 0.12 2020-12-19 01:24:40 +01:00
Héctor Ramón
86361f003c
Merge pull request #668 from hecrj/fix/propagate-button-events
Propagate `Button` events to contents
2020-12-18 23:30:49 +01:00
Héctor Ramón
0e9f649cb7
Merge pull request #319 from tarkah/image-pane
Add `ImagePane` widget
2020-12-18 23:29:51 +01:00
Héctor Ramón Jiménez
10d6df73e3 Remove max_width and max_height from image::Viewer
The support for these layout constraints is currently not ideal. We
should reintroduce these methods once our layout engine improves.
2020-12-18 11:35:01 +01:00
Héctor Ramón Jiménez
c54a6446a3 Use intra-doc links in image::viewer 2020-12-18 11:35:01 +01:00
Héctor Ramón Jiménez
6a51282933 Simplify cursor_to_center in image::Viewer 2020-12-18 11:34:52 +01:00
Héctor Ramón Jiménez
149098cb68 Remove use of unwrap in image::Viewer 2020-12-18 11:20:48 +01:00
Héctor Ramón Jiménez
43ef85ae5c Rename starting_cursor_pos to cursor_grabbed_at in image::Viewer 2020-12-18 11:20:18 +01:00
Héctor Ramón Jiménez
8245a11766 Negate values instead of multipling by -1.0 in image::Viewer 2020-12-18 11:01:20 +01:00
Héctor Ramón Jiménez
4eb5779542 Remove redundant f32 conversions in image::Viewer 2020-12-18 11:00:32 +01:00
Héctor Ramón Jiménez
cf97982929 Build todos examples instead of pokedex in CI 2020-12-18 10:57:51 +01:00
Héctor Ramón Jiménez
64af860ad2 Remove unnecessary Option in image::viewer::State 2020-12-18 10:55:18 +01:00
Héctor Ramón Jiménez
e6f23e3771 Rename scale_pct to scale_step in image::Viewer 2020-12-18 10:53:38 +01:00
Héctor Ramón Jiménez
ca3e4e9f1b Simplify pattern match in image::Viewer::on_event 2020-12-18 10:49:10 +01:00
Héctor Ramón Jiménez
add167d6a0 Pan image::Viewer even if the cursor is out of bounds 2020-12-18 10:47:29 +01:00
Héctor Ramón Jiménez
21b10dc103 Fix layout of image::Viewer 2020-12-18 10:44:24 +01:00
Héctor Ramón Jiménez
0cdf8d56ee Use image::Viewer in pokedex example 2020-12-18 10:44:06 +01:00
Héctor Ramón Jiménez
71de341684 Turn methods into helper functions in image::viewer 2020-12-18 10:24:04 +01:00
Héctor Ramón Jiménez
74ee7cca81 Format use declarations in image::viewer 2020-12-18 10:18:39 +01:00
Héctor Ramón Jiménez
0b73e5fbfa Merge remote-tracking branch 'tarkah/image-pane' into image-pane 2020-12-18 10:15:30 +01:00
Héctor Ramón Jiménez
8fb0ede72e Propagate Button events to contents 2020-12-18 09:40:10 +01:00
Nils Martel
07b570036a Mention birth year in READMEs 2020-12-17 05:26:28 +01:00
Héctor Ramón
89e604d160
Merge pull request #57 from simlay/ios-support-wip
Touch support
2020-12-17 05:19:14 +01:00
Héctor Ramón Jiménez
277ae74d68 Produce logical coordinates for touch::Event 2020-12-15 06:58:15 +01:00
Héctor Ramón Jiménez
70164f68a6 Fix text selection with touch events in TextInput 2020-12-15 06:48:12 +01:00
Héctor Ramón Jiménez
056f7e6951 Change cursor position on touch event 2020-12-15 06:44:00 +01:00
Héctor Ramón Jiménez
3bdf931925 Turn Touch into a touch::Event enum 2020-12-15 06:38:46 +01:00
Héctor Ramón Jiménez
09110a93b0 Merge branch 'ios-support-wip' into feature/touch-support 2020-12-15 06:13:19 +01:00
Héctor Ramón
a42b3c6998
Merge pull request #658 from hecrj/update-winit-and-glutin
Update `winit` and `glutin`
2020-12-15 03:27:42 +01:00
Héctor Ramón Jiménez
742086e190 Update winit and glutin
We avoid a breaking change in `mouse::Button::Other` for the time being.
2020-12-12 00:54:25 +01:00
Clark Moody
fb478a4014 Update PaneGrid example with more complex TitleBar 2020-12-10 12:18:28 -06:00
Clark Moody
f54590d7ad Replace TitleBar string title with generic Content 2020-12-10 12:17:36 -06:00
Héctor Ramón
d16b9cf7cd
Merge pull request #637 from hecrj/0.2
Release `0.2` — Canvas interactivity, overlay support, a renderer alternative, and more!
2020-11-26 17:05:49 +01:00
Héctor Ramón Jiménez
f78108a514 Bump versions 🎉 2020-11-26 16:47:41 +01:00
Héctor Ramón Jiménez
745aa49025 Update example links to point to 0.2 branch 2020-11-26 16:37:33 +01:00
Héctor Ramón Jiménez
b5c41a8815 Update game_of_life capture 2020-11-26 16:36:56 +01:00
Héctor Ramón
35df13686f
Merge pull request #636 from hecrj/improvement/update-ecosystem-and-roadmap
Update `ECOSYSTEM` and `ROADMAP`
2020-11-26 16:10:20 +01:00
Héctor Ramón Jiménez
29ad61d377 Add missing metadata to iced_graphics subcrate 2020-11-26 15:57:55 +01:00
Héctor Ramón Jiménez
7de72d6a27 Update READMEs of subcrates 2020-11-26 07:40:00 +01:00
Héctor Ramón Jiménez
278d40d8c6 Reduce size of foundations graph in ECOSYSTEM 2020-11-26 07:24:55 +01:00
Héctor Ramón Jiménez
11798dcc03 Update graphs in crate docs 2020-11-26 07:22:03 +01:00
Héctor Ramón Jiménez
0525d76ff9 Reduce size of graphs in README and ECOSYSTEM 2020-11-26 07:10:34 +01:00
Héctor Ramón Jiménez
d8c3982160 Update ROADMAP 2020-11-26 06:49:42 +01:00
Héctor Ramón Jiménez
a9ea921383 Update ECOSYSTEM 2020-11-26 06:43:37 +01:00
Héctor Ramón Jiménez
ebe34b03cb Update README 2020-11-26 06:43:29 +01:00
Héctor Ramón
50a1f78996
Merge pull request #527 from rubik83/master
Account for empty ranges in `Slider` and `ProgressBar`
2020-11-26 03:51:07 +01:00
Héctor Ramón Jiménez
c23136a5df Account for empty ranges in Slider and ProgressBar 2020-11-26 03:33:08 +01:00
rubik83
955b62ea2d fix slider handle_offset formula
change :
let handle_offset = (bounds.width - handle_width) * ((value - range_start) / (range_end - range_start).max(1.0))
to :
let handle_offset = (bounds.width - handle_width) * ((value - range_start) / (range_end - range_start).max(f32::EPSILON)).max(0.0).min(1.0)
2020-11-26 03:09:46 +01:00
rubik83
9991a89428 fix active_progress_width formula
change :
let active_progress_width = bounds.width * ((value - range_start) / (range_end - range_start).max(1.0))
to :
let active_progress_width = bounds.width * ((value - range_start) / (range_end - range_start).max(f32::EPSILON)).max(0.0).min(1.0)
2020-11-26 03:09:46 +01:00
Héctor Ramón
1f7e8b7f3d
Merge pull request #632 from hecrj/improvement/update-docs
Use intra-doc links
2020-11-26 02:52:34 +01:00
Héctor Ramón Jiménez
01322f69a4 Use recently stabilized intra-doc links
See RFC: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md
2020-11-26 02:05:43 +01:00
Héctor Ramón Jiménez
d612bf5678 Rename keyboard::ModifiersState to Modifiers 2020-11-26 02:05:42 +01:00
Héctor Ramón Jiménez
08e0b9ffbd Fix broken links in API documentation 2020-11-26 01:59:20 +01:00
Héctor Ramón
bffaeed9fd
Merge pull request #634 from myfreeweb/graphics-license
Add license to iced-graphics' Cargo.toml
2020-11-25 21:30:39 +01:00
Greg V
775c1c5873 Add license to iced-graphics' Cargo.toml 2020-11-25 23:02:50 +03:00
Héctor Ramón
18aa14c7bb
Merge pull request #605 from ZakisM/text_input_select_all_fix
This PR fixes a bug with select all (CMD + A on MacOS) when using a text_input.
2020-11-25 19:50:24 +01:00
Héctor Ramón
87c9df294c
Merge pull request #595 from valbendan/master
upgrade tokio to latest version(v0.3)
2020-11-25 04:24:44 +01:00
Héctor Ramón Jiménez
1d23db1866 Track keyboard modifiers in text_input 2020-11-25 04:10:23 +01:00
Zak
d275a4ed32 This PR fixes a bug with select all (CMD + A on MacOS) when using a text_input.
Previous behaviour: when selecting all (CMD + A) would delete the current text inside the input and replace the content with just the letter 'a'.

Now we check if the logo key (modifier key) has been pressed before checking any other key and save it to the state level. This way we can prevent any text being deleted when using the select all shortcut or text being entered at all when a modifier key is pressed (this behaviour matches other text input behaviour i.e text inputs in the browser etc...).
2020-11-25 03:57:18 +01:00
Héctor Ramón Jiménez
782dd2f522 Introduce tokio_old feature
This feature allows users to rely on the `0.2` version of `tokio` while
the async ecosystem upgrades to the latest version.
2020-11-25 03:06:24 +01:00
Héctor Ramón
8f081bad77
Merge pull request #629 from hecrj/wgpu-present-mode-setting
Add `present_mode` field to `iced_wgpu::Settings`
2020-11-24 00:17:59 +01:00
Héctor Ramón
556cf24b95
Merge pull request #627 from hecrj/fix/canvas-rotation
Fix backwards `Frame::rotate` in `canvas`
2020-11-24 00:17:46 +01:00
Héctor Ramón
5615643c52
Merge pull request #628 from hecrj/improvement/float-border-radius
Use `f32` for `border_width` and `border_radius`
2020-11-24 00:17:30 +01:00
Héctor Ramón Jiménez
1916755b6b Limit border radius to max dimension in quad pipeline 2020-11-23 00:43:59 +01:00
Héctor Ramón Jiménez
f41eacc3dc Use f32 for border_width and border_radius 2020-11-23 00:31:50 +01:00
Héctor Ramón Jiménez
0f00d14297 Add present_mode field to iced_wgpu::Settings 2020-11-23 00:00:13 +01:00
Héctor Ramón Jiménez
77c7ad1fef Fix backwards Frame::rotate in canvas
The angle direction has been fixed upstream in `euclid` (see
https://github.com/servo/euclid/pull/413).
2020-11-22 11:05:08 +01:00
Héctor Ramón
ea1a7248d2
Merge pull request #622 from hecrj/feature/qr_code-widget
`QRCode` widget
2020-11-20 23:33:51 +01:00
Héctor Ramón Jiménez
f259d44186 Implement qr_code example 2020-11-20 10:29:40 +01:00
Héctor Ramón Jiménez
3296be845c Implement QRCode widget 2020-11-20 10:29:33 +01:00
Héctor Ramón Jiménez
209056e1cd Fix deprecation warnings from image 2020-11-20 10:29:11 +01:00
Héctor Ramón
1af6fb3ec0
Merge pull request #620 from hecrj/fix/trackpad-text-input-selection
Disable dragging in `TextInput` after double click
2020-11-20 00:33:48 +01:00
Héctor Ramón Jiménez
140bea352e Disable dragging in TextInput after double click
When using a trackpad, mouse move events may happen between the
press/release events. This was incorrectly triggering selection dragging in
the `TextInput` widget.

Eventually, we should implement proper word-aware selection dragging.
2020-11-19 02:45:47 +01:00
Héctor Ramón Jiménez
c03d46719e Remove Focus in pane_grid
Since #608, the `PaneGrid` widget does not handle pane focus.
2020-11-17 06:13:56 +01:00
Héctor Ramón Jiménez
df712f9ccf Implement flexible TextInput::draw helper 2020-11-17 05:13:06 +01:00
Héctor Ramón
62295f554b
Merge pull request #614 from hecrj/feature/event-capturing
Event capturing
2020-11-14 02:17:21 +01:00
Héctor Ramón Jiménez
bf2d2561b8 Batch event processing in UserInterface::update 2020-11-12 02:51:26 +01:00
Héctor Ramón Jiménez
69c50c8511 Introduce event::Status to Subscription 2020-11-12 02:22:22 +01:00
Héctor Ramón Jiménez
33d80b5a0b Return event::Status in UserInterface::update 2020-11-12 02:00:08 +01:00
Héctor Ramón Jiménez
6e9bd0d9d1 Make Overlay::on_event return event::Status 2020-11-12 01:29:11 +01:00
Héctor Ramón Jiménez
3aca177132 Implement event capturing for Canvas 2020-11-12 01:24:59 +01:00
Héctor Ramón Jiménez
bf6c65b5ad Implement event capturing for TextInput 2020-11-12 01:11:09 +01:00
Héctor Ramón Jiménez
c361fe48c7 Implement event capturing for Slider 2020-11-12 00:56:50 +01:00
Héctor Ramón Jiménez
fd275a2fee Implement event capturing for Scrollable 2020-11-12 00:53:39 +01:00
Héctor Ramón Jiménez
451bf8dc84 Implement event capturing for Row 2020-11-12 00:48:40 +01:00
Héctor Ramón Jiménez
18172f80c9 Implement event capturing for Radio 2020-11-12 00:47:58 +01:00
Héctor Ramón Jiménez
7ff95f3a88 Implement event capturing for PickList 2020-11-12 00:47:21 +01:00
Héctor Ramón Jiménez
31c509b206 Implement event capturing for PaneGrid 2020-11-12 00:40:55 +01:00
Héctor Ramón Jiménez
3bcee62beb Implement event capturing for Column 2020-11-12 00:40:52 +01:00
Héctor Ramón Jiménez
04468a7147 Implement event capturing for Checkbox 2020-11-12 00:20:09 +01:00
Héctor Ramón Jiménez
a44cd07212 Implement event capturing for Button 2020-11-12 00:19:12 +01:00
Héctor Ramón Jiménez
3f968b8c87 Make Widget::on_event return an event::Status 2020-11-12 00:09:52 +01:00
Héctor Ramón Jiménez
1db11ba69a Introduce event::Status in iced_native 2020-11-11 23:54:59 +01:00
Héctor Ramón
73811c394a
Merge pull request #610 from hecrj/improvement/update-dependencies
Update dependencies
2020-11-11 18:06:27 +01:00
Héctor Ramón Jiménez
0400f6716b Use directories-next in todos example 2020-11-11 02:34:17 +01:00
Héctor Ramón
2f5a3dacd9
Merge pull request #608 from hecrj/remove-pane-grid-focus
Improve flexibility of `PaneGrid`
2020-11-10 22:57:19 +01:00
Héctor Ramón Jiménez
86fa12229e Introduce is_command_pressed to ModifiersState 2020-11-10 21:18:21 +01:00
Héctor Ramón Jiménez
1475b10dff Update font-kit dependency in iced_graphics 2020-11-10 20:33:45 +01:00
Héctor Ramón Jiménez
6f52eb4d3a Update lyon dependency in iced_graphics 2020-11-10 20:13:47 +01:00
Héctor Ramón Jiménez
fa98dbad16 Update glam dependency in iced_graphics 2020-11-10 20:12:15 +01:00
Héctor Ramón Jiménez
45c749f28c Update bytemuck dependency in iced_graphics 2020-11-10 20:11:23 +01:00
Héctor Ramón Jiménez
9d4f664c94 Update bytemuck and remove zerocopy in iced_wgpu 2020-11-10 20:06:24 +01:00
Héctor Ramón Jiménez
b86accfe1c Update bytemuck dependency in iced_glow 2020-11-10 19:52:43 +01:00
Héctor Ramón Jiménez
fb3cd68dde Update glow and glow_glyph dependencies in iced_glow 2020-11-10 19:48:40 +01:00
Héctor Ramón Jiménez
0c2787eada Update euclid dependency in iced_glow 2020-11-10 19:15:07 +01:00
Héctor Ramón Jiménez
17a4647fce Update directories dependency in todos example 2020-11-10 19:13:40 +01:00
Héctor Ramón Jiménez
860de97b42 Update env_logger in tour and integration examples 2020-11-10 19:12:28 +01:00
Héctor Ramón Jiménez
3b2ed0d6f0 Remove unnecessary move in PaneGrid::new 2020-11-10 03:18:46 +01:00
Héctor Ramón Jiménez
d6d5cf0294 Restore hotkeys in pane_grid example
- Implement `subscription::events_with`
- Remove `pane_grid::KeyPressEvent`
- Return closest sibling in `pane_grid::State::close`
2020-11-10 02:32:57 +01:00
Héctor Ramón Jiménez
c53022e8df Fix typo in documentation of pane_grid::Content 2020-11-10 01:51:27 +01:00
Héctor Ramón Jiménez
8008ea5286 Introduce on_click handler in PaneGrid 2020-11-10 01:48:11 +01:00
Héctor Ramón Jiménez
5681c83d3c Remove focus concept from pane_grid 2020-11-10 01:38:27 +01:00
Héctor Ramón
d0402d072d
Merge pull request #598 from oknozor/input-text-focus
Add textinput focus method
2020-11-09 20:49:42 +01:00
Héctor Ramón Jiménez
1a2cb2f35b Split focus and unfocus methods in text_input 2020-11-09 20:32:58 +01:00
Paul Delafosse
f7d67598cb Add textinput focus method 2020-11-09 20:32:50 +01:00
Héctor Ramón
da1a3eed1e
Merge pull request #597 from hecrj/improvement/reuse-view-in-event-loop
Rebuild widget tree only after an application update
2020-11-08 13:31:08 +01:00
Héctor Ramón
ef76f16900
Merge pull request #600 from aentity/update_guillotiere
update guillotiere to 0.6
2020-11-06 19:10:59 +01:00
aentity
66509784cb update guillotiere to 0.6 2020-11-06 01:49:37 -08:00
dabaichi
a4ad1b297e
Update src/executor.rs
fix executor other than tokio

Co-authored-by: Héctor Ramón <hector0193@gmail.com>
2020-11-06 04:20:19 +00:00
Héctor Ramón Jiménez
631c9e4a21 Write missing documentation in iced_winit 2020-11-06 02:25:56 +01:00
Héctor Ramón Jiménez
e966cd5b59 Remove a bit of code duplication in both shells 2020-11-05 04:50:57 +01:00
valbendan
eacb2e913f upgrade tokio to latest version(v0.3) 2020-11-05 11:36:23 +08:00
Héctor Ramón Jiménez
d5a15419e9 Drop UserInterface manually after exit request 2020-11-05 04:13:09 +01:00
Héctor Ramón Jiménez
6619fab044 Update iced_glutin with new event loop logic 2020-11-05 04:09:40 +01:00
Héctor Ramón Jiménez
88993fb092 Relayout UserInterface on resize in iced_winit 2020-11-05 04:09:40 +01:00
Héctor Ramón Jiménez
86b26f65d6 Handle event loop ControlFlow in iced_winit 2020-11-05 04:09:40 +01:00
Héctor Ramón Jiménez
fee46fd653 Introduce application::State in iced_winit 2020-11-05 04:09:40 +01:00
Héctor Ramón Jiménez
ed2b9a91b4 Initialize runtime values in application::run 2020-11-05 04:09:40 +01:00
Héctor Ramón Jiménez
ee38b04d8b Use static noop Waker in application::run 2020-11-05 04:09:40 +01:00
Héctor Ramón Jiménez
c153d11aa6 Draft strategy to reuse view result in event loop 2020-11-05 04:09:31 +01:00
Héctor Ramón
e6131783e9
Merge pull request #590 from Limeth/master
Fix lifetimes in `Layout::children`
2020-11-02 17:57:56 +01:00
Jakub Hlusička
1d51025993
Take self by value in Layout::children 2020-11-02 16:27:28 +01:00
Héctor Ramón
28280600d7
Merge pull request #592 from sum-elier/fix-window-icon-dimensionsmismatch-error
Fixes #591 DimensionsMismatch error message
2020-11-02 15:06:01 +01:00
sum-elier
2b1d438ad4 Fix DimensionsMismatch error message
The values passed to write! were shifted 1 to the left.

Fixes #591
2020-11-01 09:21:42 -05:00
Jakub Hlusička
4dc93e8138
Fix lifetimes in Layout::children 2020-10-31 16:51:11 +01:00
Héctor Ramón
f46431600c
Merge pull request #586 from hecrj/fix/subscription-map
Accept a function pointer in `Subscription::map`
2020-10-30 08:04:23 +01:00
Héctor Ramón
820abdc98e
Merge pull request #583 from Limeth/master
Add conversion functions to Size and Vector
2020-10-29 16:03:10 +01:00
Jakub Hlusička
16646ffc41
Apply suggestions 2020-10-29 14:57:37 +01:00
Héctor Ramón
b8825966d4
Merge pull request #533 from Kaiden42/gitignore
Fix: ignoring all `target` directories
2020-10-29 10:45:34 +01:00
Héctor Ramón Jiménez
dd1b1cac0a Accept a function pointer in Subscription::map
Instead of a closure, a function pointer can be hashed and used to
uniquely identify a particular `Subscription`.

This should fix a bug where two different instances of `Subscription`
producing the same output were not treated differently by the runtime,
causing one of them to be ignored.
2020-10-29 10:27:18 +01:00
Héctor Ramón
b40775fb74
Merge pull request #584 from hecrj/improvement/viewport-aware-drawing
Viewport aware drawing
2020-10-29 02:00:56 +01:00
Jakub Hlusička
9090fa6a22 Add conversion functions to Size and Vector 2020-10-28 15:33:38 +01:00
Héctor Ramón Jiménez
91b1886968 Fix Widget::draw for Rule 2020-10-28 06:21:07 +01:00
Héctor Ramón Jiménez
7f02765214 Draw only visible options in overlay::Menu 2020-10-28 06:21:07 +01:00
Héctor Ramón Jiménez
d328b07b39 Introduce viewport to Widget::draw
This should eventually allow us to only generate primitives that are
visible.
2020-10-28 06:21:07 +01:00
Héctor Ramón
8a3ce90959
Merge pull request #575 from clarkmoody/scrollable-width
Custom Scrollbar Width
2020-10-27 23:35:52 +01:00
Héctor Ramón Jiménez
2ca05520ba Update screenshot of scrollable example 2020-10-24 10:32:26 +02:00
Héctor Ramón Jiménez
ed458d33d9 Reduce contrast of dark theme in scrollable example 2020-10-24 10:29:19 +02:00
Héctor Ramón Jiménez
7f66345d5a Improve minor details in scrollable example
- Rename `Config` to `Variant`
- Include `State` in `Variant` to avoid `zip`
- Break long string literal
- Split `style` module into its own file
2020-10-24 10:29:12 +02:00
Héctor Ramón Jiménez
d3b04bf892 Introduce Eq requirement to build a PickList 2020-10-24 09:32:23 +02:00
Clark Moody
e43a46952a Add scrollable example program 2020-10-22 16:24:54 -05:00
Clark Moody
f05578c8f8 Update scrollbar logic and introduce outer_bounds 2020-10-22 16:05:44 -05:00
Clark Moody
09e67c5c27 Replace hard-coded params with struct members 2020-10-22 14:07:07 -05:00
Héctor Ramón
23647d2f50
Merge pull request #545 from MonliH/master
Remove outdated `Fill` comment for `Column` and `Row`
2020-10-17 21:12:09 +02:00
Héctor Ramón
befeb32225
Merge pull request #569 from hecrj/improvement/hide-null-executor
Remove `executor::Null` from the root public API
2020-10-17 21:10:59 +02:00
Héctor Ramón
5d0f7ba3fc
Merge pull request #568 from hecrj/improvement/early-clone-message-bounds
Require `Clone` for `Message` early when needed
2020-10-17 21:10:26 +02:00
Jonathan Li
461499dd62 Remove entirely 2020-10-17 10:48:31 -04:00
Héctor Ramón Jiménez
ae5a2502d6 Remove executor::Null from the root public API
Using an `Application` with `executor::Null` does not make sense, as the
whole purpose of an `Application` is to allow executing async actions.

When async actions are not needed, `Sandbox` should be used instead.
2020-10-17 08:46:16 +02:00
Héctor Ramón Jiménez
d7a5e54455 Require Clone for Message early when needed
Prior to this change, the widgets that needed a `Clone` bound on `Message` to
implement the `Widget` trait could be created with a non-cloneable `Message`.

As a consequence, the compiler complained only when actually trying to use the
`Widget` trait. Normally, this happens when trying to `push` the widget in a
container or turn it into an `Element`.

Furthermore, the compiler error in this case does not mention `Message` nor the
`Clone` bound, but instead complains about a missing `From` implementation.
Thus, it can easily cause confusion!

This change introduces `Clone` bounds in the main implementation of the
widgets that need it to properly implement the `Widget` trait. As a
result, the compiler complains early when trying to create one of these widgets
with a non-cloneable `Message` and explicitly mentions that the `Message` needs
to implement `Clone`.
2020-10-17 08:10:30 +02:00
Héctor Ramón
17f0db57c3
Merge pull request #563 from Limeth/master
Fix typo in `Row`'s and `Column`'s `hash_layout`
2020-10-14 02:48:51 +02:00
Jakub Hlusička
4910e03833 Fix typo in Row's and Column's hash_layout 2020-10-13 20:48:53 +02:00
Héctor Ramón
be61d84cae
Merge pull request #558 from Azorlogh/master
Adds From<Point> and From<Size> for [f32; 2]
2020-10-08 15:50:09 +02:00
Azorlogh
e6bcb7211f add From<Point> and From<Size> for [f32; 2] 2020-10-08 09:54:22 +02:00
Héctor Ramón
2e0ba65a20
Merge pull request #542 from aentity/winit_023
update to winit 0.23 api
2020-10-08 03:55:02 +02:00
Héctor Ramón Jiménez
16cd38a198 Keep KeyCode names synchronized with winit 2020-10-08 03:44:22 +02:00
aentity
159e8a6abc update to winit 0.23 api 2020-10-03 12:58:28 -07:00
Jonathan Li
7c24277210 Document better 2020-10-02 21:53:40 -04:00
Jonathan Li
8346209c37 Satify documented behaviour 2020-10-01 17:10:13 -04:00
Héctor Ramón
c393e450a1
Merge pull request #543 from twitchyliquid64/master
Fixes #539: Allow windows to be set always_on_top
2020-09-30 19:03:56 +02:00
Tom
f2247a70dc Fixes #539: Allow windows to be set always_on_top 2020-09-28 21:05:15 -07:00
Kaiden42
7dc762ad9c Fix ignoring all target directories 2020-09-18 09:57:46 +02:00
Héctor Ramón Jiménez
4f2962d73f Move version from Grid to GameOfLife struct 2020-09-12 20:35:51 +02:00
Héctor Ramón
49076c6ac2
Merge pull request #514 from hecrj/feature/error-handling
Error propagation
2020-09-08 20:03:37 +02:00
Héctor Ramón Jiménez
c1f79b40cf Make Application and Sandbox return a Result 2020-09-08 00:44:59 +02:00
Héctor Ramón
faa12382d4
Merge pull request #513 from hecrj/fix/custom-radio-size
Fix `Radio` border radius when using custom size
2020-09-06 19:56:19 +02:00
Héctor Ramón Jiménez
f6dda3b2f5 Fix Radio border radius when using custom size 2020-09-06 15:02:55 +02:00
Héctor Ramón
ff15ebc547
Merge pull request #500 from hecrj/update-wgpu
Update `wgpu` to `0.6` in `iced_wgpu`
2020-08-31 15:11:34 +02:00
Héctor Ramón Jiménez
44118263b5 Add labels to iced_wgpu internals 2020-08-31 14:41:41 +02:00
Héctor Ramón Jiménez
07880c392c Turn consecutive if-lets into pattern match 2020-08-27 19:40:42 +02:00
Héctor Ramón Jiménez
7559e4fb30 Set offsets in buffer slices in iced_wgpu 2020-08-27 19:35:24 +02:00
Héctor Ramón Jiménez
8d605be4e3 Use wgpu::Color::TRANSPARENT 2020-08-27 19:30:56 +02:00
Héctor Ramón Jiménez
3eb63762c7 Remove unnecessary create_buffer_init for uniforms 2020-08-27 19:28:03 +02:00
Héctor Ramón Jiménez
b689778ed9 Remove redundant depth bias fields in iced_wgpu 2020-08-27 19:15:05 +02:00
Héctor Ramón Jiménez
bae0a3e46e Update wgpu in integration example 2020-08-27 14:55:41 +02:00
Héctor Ramón Jiménez
bb5f034e08 Fix offset calculation in image::Atlas 2020-08-27 14:45:08 +02:00
Héctor Ramón Jiménez
ecbee66bd6 Fix layers initialization in image::Atlas 2020-08-27 14:44:51 +02:00
Héctor Ramón Jiménez
83e037829c Update image pipeline in iced_wgpu 2020-08-27 13:41:00 +02:00
Héctor Ramón Jiménez
67d90e3946 Update wgpu to 0.6 in iced_wgpu 2020-08-27 13:03:42 +02:00
Héctor Ramón
fb015a85d2
Merge pull request #496 from hecrj/fix/cursor-position-on-leave
Fix cursor position after a `CursorLeft` event
2020-08-25 10:58:15 +02:00
Héctor Ramón
56273c5a3c
Merge pull request #487 from Kaiden42/background
Implement `From<Color>` for `Option<Background>`
2020-08-25 10:54:52 +02:00
Kaiden42
f025794985 Update styling example
Also run `cargo fmt`
2020-08-25 10:42:53 +02:00
Kaiden42
1b980bc6e8 Implement From<Color> for Option<Background> 2020-08-25 10:41:37 +02:00
Héctor Ramón Jiménez
72f89ba77f Fix cursor position after a CursorLeft event 2020-08-25 01:39:54 +02:00
Héctor Ramón Jiménez
2ce5df0844 Merge branch 'feature/rule-widget' into master 2020-08-22 21:25:06 +02:00
Billy Messenger
fed30ef775 added FillMode::fill() 2020-08-22 21:23:50 +02:00
Billy Messenger
32561bd85c added FillMode enum style for the Rule widget 2020-08-22 21:23:44 +02:00
Billy Messenger
8d68c8584e widget Rule added 2020-08-22 21:23:27 +02:00
Héctor Ramón Jiménez
bbc6e91429 Implement hash_layout for pane_grid::TitleBar 2020-08-19 02:03:21 +02:00
Héctor Ramón
2a46ed8753
Merge pull request #484 from atsuzaki/window-transparent-setting
Add 'transparent' in window setting
2020-08-18 20:30:35 +02:00
Katherine Philip
6de9a5e076 Remove debug println & accidentally added whitespace 2020-08-18 05:58:20 +07:00
Katherine Philip
fe75646f82 Add missing comment 2020-08-18 05:54:55 +07:00
Héctor Ramón
24297b11ee
Merge pull request #482 from bitshifter/glam-0.9
Upgrade glam to 0.9 & use glam's Mat4 ortho rh gl.
2020-08-17 21:53:59 +02:00
Héctor Ramón Jiménez
02ca90a22d Invert Y axis in Transformation::orthographic 2020-08-17 18:11:11 +02:00
Katherine Philip
a490fd54c9 Add 'transparent' in window setting 2020-08-17 15:42:50 +07:00
Cameron Hart
b90e5c4e05 Upgrade glam to 0.9 & use glam's Mat4 ortho rh gl. 2020-08-17 12:01:58 +12:00
Héctor Ramón Jiménez
00d66da0ce Add Keyboard variant to canvas::Event 2020-08-10 23:57:29 +02:00
Héctor Ramón Jiménez
9ba4cfd23f Add height method to Slider 2020-08-01 08:18:52 +02:00
Héctor Ramón
72cfe85f7f
Merge pull request #463 from mobile-bungalow/titlebar_options
Added `always_show_controls` method to TitleBar
2020-07-31 06:55:55 +02:00
Héctor Ramón Jiménez
ac74f35424 Clarify TitleBar::always_show_controls docs a bit 2020-07-31 06:43:51 +02:00
Héctor Ramón Jiménez
ab0da5dad0 Move always_show_controls after padding 2020-07-31 06:43:27 +02:00
Héctor Ramón Jiménez
174565715e Fix typo in TitleBar::new 2020-07-31 04:23:55 +02:00
Héctor Ramón
869fa6baa8
Merge pull request #462 from hecrj/improvement/update-glow
Update `glow` to `0.5` in `iced_glow`
2020-07-31 02:48:01 +02:00
Héctor Ramón Jiménez
4ab9992bf8 Unfocus TextInput when Escape key is pressed 2020-07-30 00:52:02 +02:00
Héctor Ramón Jiménez
51c22f2426 Fix Widget::layout for Checkbox 2020-07-28 08:23:44 +02:00
Héctor Ramón Jiménez
5fd239c488 Add custom font support to Checkbox 2020-07-28 08:21:33 +02:00
Héctor Ramón Jiménez
795da598e0 Update glow to 0.5 in iced_glow 2020-07-27 23:01:30 +02:00
mobile-bungalow
7977e970ca Added method to TitleBar, allowing controls to be show statically instead of only on mouseover 2020-07-27 01:17:02 -07:00
Héctor Ramón Jiménez
55d2c5886f Introduce state method to TextInput 2020-07-24 19:20:46 +02:00
Héctor Ramón Jiménez
a165eddd75 Avoid PaneGrid unfocus when cursor is unavailable 2020-07-23 04:44:35 +02:00
Héctor Ramón Jiménez
a225a218e0 Fix Default implementation for pick_list::State 2020-07-23 04:06:26 +02:00
Héctor Ramón Jiménez
aaf5986123 Improve Menu API to facilitate external control 2020-07-23 03:58:59 +02:00
Héctor Ramón Jiménez
bf5eaca2f2 Fix hash_layout implementation of Menu overlay 2020-07-23 03:28:22 +02:00
Héctor Ramón Jiménez
d4ef470b4f Add new method to menu::State 2020-07-23 03:27:21 +02:00
Héctor Ramón Jiménez
3d91926a74 Keep original focus state while a pane is dragged 2020-07-22 03:40:17 +02:00
Héctor Ramón Jiménez
35b1b8b0e7 Add focused method to pane_grid::State 2020-07-22 02:58:14 +02:00
Héctor Ramón Jiménez
021b173ef3 Add newline before Marker in pane_grid 2020-07-22 02:55:35 +02:00
Héctor Ramón Jiménez
9b778006ce Fix border rendering of transparent Container
Fixes #452
2020-07-18 03:05:14 +02:00
Héctor Ramón Jiménez
4030326a35 Handle ScaleFactorChanged in iced_winit 2020-07-16 18:18:36 +02:00
Héctor Ramón
da5da3958e
Merge pull request #444 from hecrj/feature/overlay
Overlay support and `PickList` widget
2020-07-16 05:00:37 +02:00
Héctor Ramón Jiménez
31c30fedd5 Remove unnecessary Rc in both Element::map 2020-07-16 04:40:36 +02:00
Héctor Ramón Jiménez
73d1353976 Update README of examples 2020-07-16 04:30:06 +02:00
Héctor Ramón
62ec03a0af
Merge pull request #445 from mtkennerly/bugfix/paste-panic
Fix panic on paste in TextInput after programmatic modification of contents
2020-07-11 00:25:47 +02:00
Héctor Ramón Jiménez
4314ce36f4 Remove redundant min checks in Editor 2020-07-11 00:11:45 +02:00
Héctor Ramón Jiménez
a1210c9dae Improve safety of Cursor::selection 2020-07-11 00:00:14 +02:00
mtkennerly
855c0faa59 Fix panic on paste in TextInput after programmatic modification of contents 2020-07-10 07:14:26 -04:00
Héctor Ramón Jiménez
26fbc9af00 Simplify pick_list example 2020-07-10 08:11:31 +02:00
Héctor Ramón Jiménez
94383d82a5 Style PickList in game_of_life example 2020-07-10 07:41:31 +02:00
Héctor Ramón Jiménez
b64e0ea5e3 Add Preset selector to game_of_life example 2020-07-10 04:14:21 +02:00
Héctor Ramón Jiménez
73b8ae8e5e Rename ComboBox to PickList 2020-07-10 02:52:00 +02:00
Héctor Ramón Jiménez
2118a726f8 Write documentation for the new overlay API 2020-07-10 02:39:12 +02:00
Héctor Ramón Jiménez
dc0e423142 Remove unnecessary lifetime in Widget trait 2020-07-10 02:01:30 +02:00
Héctor Ramón Jiménez
f24e03eae8 Implement Widget::overlay for PaneGrid 2020-07-10 01:35:58 +02:00
Héctor Ramón Jiménez
1070b61f34 Rename overlay::Content trait to Overlay
The `Overlay` struct is now `overlay::Element`.
2020-07-10 01:35:46 +02:00
Héctor Ramón Jiménez
ce8cb228ef Merge branch 'master' into feature/overlay 2020-07-10 01:25:49 +02:00
Héctor Ramón
46ce3a1f00
Merge pull request #442 from hecrj/feature/pane-grid-titlebar
Title bar support for `PaneGrid`
2020-07-10 00:35:15 +02:00
Héctor Ramón Jiménez
3c5921f30c Update pane_grid GIFs 2020-07-09 07:05:57 +02:00
Héctor Ramón Jiménez
6820eea9ce Simplify style of pane_grid example 2020-07-09 06:29:54 +02:00
Héctor Ramón Jiménez
67f4c9aea3 Add a TitleBar to pane_grid example 2020-07-09 06:27:38 +02:00
Héctor Ramón Jiménez
1319c25f20 Respect TitleBar text color style when drawing 2020-07-09 06:27:12 +02:00
Héctor Ramón Jiménez
ef553cd124 Stop drawing pane background when dragged 2020-07-09 05:44:48 +02:00
Héctor Ramón Jiménez
2f02ca3248 Fix layout of a TitleBar without controls 2020-07-09 05:42:28 +02:00
Héctor Ramón Jiménez
ad19c1628d Fix docs of modifiers_keys in PaneGrid 2020-07-09 05:33:44 +02:00
Héctor Ramón Jiménez
2334c7d1d5 Stop tracking pressed_modifiers in PaneGrid 2020-07-09 05:28:42 +02:00
Héctor Ramón Jiménez
e3cd947437 Write documentation for new PaneGrid API 2020-07-09 05:26:11 +02:00
Héctor Ramón Jiménez
733ec6b2ea Fix default text size in TitleBar 2020-07-08 11:48:16 +02:00
Héctor Ramón Jiménez
f3dfaa2c43 Merge branch 'master' into feature/pane-grid-titlebar 2020-07-08 11:44:40 +02:00
Héctor Ramón Jiménez
33e6682882 Avoid clipping antialiasing in Renderer::overlay 2020-07-08 11:40:07 +02:00
Héctor Ramón Jiménez
21b583c468 Avoid reopening Menu in ComboBox 2020-07-08 11:29:21 +02:00
Héctor Ramón Jiménez
105c0fe478 Propagate Font from ComboBox to Menu 2020-07-08 11:29:21 +02:00
Héctor Ramón Jiménez
aa0ec2821e Finish wiring overlays to UserInterface 2020-07-08 11:29:21 +02:00
Héctor Ramón Jiménez
69ac47f463 Implement font method for ComboBox 2020-07-08 11:29:21 +02:00
Héctor Ramón Jiménez
1c12bad866 Split Menu::new into multiple builder methods 2020-07-08 11:29:21 +02:00
Héctor Ramón Jiménez
7a105ade27 Use Borrow to avoid clone in ComboBox::overlay 2020-07-08 11:29:20 +02:00
Héctor Ramón Jiménez
9fa0b4da5d Complete hash_layout for menu::List 2020-07-08 11:29:20 +02:00
Héctor Ramón Jiménez
625979b665 Draft Widget::overlay idempotency 2020-07-08 11:29:19 +02:00
Héctor Ramón Jiménez
61f22b1db2 Add styling support for ComboBox and Menu 2020-07-08 11:19:56 +02:00
Héctor Ramón Jiménez
0ff5a02550 Rename Layer to overlay::Content 2020-07-08 11:12:47 +02:00
Héctor Ramón Jiménez
a264236624 Implement Widget::overlay for Row 2020-07-08 11:06:41 +02:00
Héctor Ramón Jiménez
f655d9b967 Position Menu layer based on available space 2020-07-08 11:06:39 +02:00
Héctor Ramón Jiménez
e29feef8ba Render arrow icon in ComboBox 2020-07-08 11:05:15 +02:00
Héctor Ramón Jiménez
ada8d7c77f Implement Widget::overlay for Scrollable 2020-07-08 10:59:57 +02:00
Héctor Ramón Jiménez
f7a370b6b9 Implement Overlay::translate 2020-07-08 10:59:57 +02:00
Héctor Ramón Jiménez
afd9274de2 Draft ComboBox and Menu layer 2020-07-08 10:59:56 +02:00
Héctor Ramón Jiménez
b1afadf1a2 Draft combo_box example to test overlay logic 2020-07-08 10:41:18 +02:00
Héctor Ramón Jiménez
f064f0482b Introduce Layer trait 2020-07-08 10:41:16 +02:00
Héctor Ramón Jiménez
c901f40fd6 Introduce Widget::overlay 🎉 2020-07-08 10:34:14 +02:00
Héctor Ramón Jiménez
5c4f5ae5ec Export Canvas if glow_canvas feature is enabled 2020-07-08 10:20:55 +02:00
Héctor Ramón Jiménez
dfeb3db003 Use default_font_size for TextInput widget 2020-07-06 23:58:15 +02:00
Héctor Ramón Jiménez
946bbd2683 Truncate Debug messages after 100 characters 2020-07-04 03:12:18 +02:00
Héctor Ramón
3f44d331d9
Merge pull request #432 from hecrj/improvement/update-dodrio
Update `dodrio` in `iced_web`
2020-07-01 22:44:48 +02:00
Héctor Ramón
99a50d6b2f
Merge pull request #431 from hecrj/feature/pane-grid-splits
Splits iterator for `PaneGrid` and minor improvements
2020-07-01 22:44:37 +02:00
Héctor Ramón
79aa225001
Merge pull request #430 from hecrj/feature/keyboard-modifiers-event
Add `ModifiersChanged` to `keyboard::Event`
2020-07-01 22:44:26 +02:00
Héctor Ramón
5190bcea80
Merge pull request #285 from frapa/add_support_for_window_icons
Add support for setting window icon
2020-07-01 22:44:11 +02:00
Héctor Ramón Jiménez
75464ad894 Use String::from_str_in in iced_web 2020-07-01 07:36:42 +02:00
Héctor Ramón Jiménez
d873c37e31 Update dodrio dependency in iced_web 2020-07-01 07:19:51 +02:00
Héctor Ramón
08e13e00f1
Merge pull request #292 from TomPridham/feature/accessibility-web
add some accessibility features to web widgets
2020-07-01 07:09:27 +02:00
Héctor Ramón Jiménez
ffd195cdb5 Fix empty id and name attributes in iced_web 2020-07-01 06:52:13 +02:00
Héctor Ramón Jiménez
a0cc7e4e43 Move Icon to iced crate and introduce Error 2020-07-01 06:10:31 +02:00
Francesco Pasa
9a037a23e9 Add support for setting window icon
This adds a new property from Settings:🪟:iconand a Icon struct which can be converted to winit:🪟:Icon.

It also adds code to display this icon in Application::run. Due to the fact that the Icon struct is non copyable, I also had to remove the Copy trait from all Settings, both in `iced` and `iced_winit`.
2020-07-01 05:37:28 +02:00
Héctor Ramón Jiménez
e8aeb86698 Use keyboard::ModifiersChanged in PaneGrid 2020-06-30 07:38:04 +02:00
Héctor Ramón Jiménez
78cb805fac Add ModifiersChanged to keyboard::Event 2020-06-30 07:36:13 +02:00
Héctor Ramón Jiménez
e50c61f7ff Add unfocus method to pane_grid::State 2020-06-30 02:53:15 +02:00
Héctor Ramón Jiménez
cee8400663 Unfocus Pane in pane_grid on click outbounds 2020-06-30 01:02:39 +02:00
Héctor Ramón Jiménez
23f753e599 Introduce splits method in pane_grid::Node 2020-06-30 01:02:28 +02:00
Héctor Ramón Jiménez
cb530ccf2f Rename regions and splits in pane_grid::Node 2020-06-30 01:02:26 +02:00
Héctor Ramón Jiménez
1bc69e7a8a Expose defaults module in iced_graphics
Fixes #429
2020-06-28 21:38:03 +02:00
Héctor Ramón Jiménez
b5d842f877 Show idle cursor when hovering a disabled Button 2020-06-27 03:40:04 +02:00
Héctor Ramón
754b8f819e
Merge pull request #424 from hecrj/feature/window-max-and-min-size
Add `min_size` and `max_size` to `window::Settings`
2020-06-25 17:03:35 +02:00
Héctor Ramón
038f75eef1
Merge pull request #421 from hecrj/fix/triangle-uniform-bindgroup
Recreate uniforms `BindGroup` when necessary
2020-06-25 02:06:38 +02:00
Héctor Ramón Jiménez
65a4dca0d9 Add min_size and max_size to window::Settings 2020-06-25 00:32:41 +02:00
Héctor Ramón Jiménez
ab53df8e9d Recreate uniforms BindGroup when necessary 2020-06-23 21:11:13 +02:00
Héctor Ramón Jiménez
f30a666dc8 Decouple cursor_position from Cache
Instead, we ask explicitly for it in the different `update` and `draw` methods.
This way, the runtime can derive the logical position of the cursor from
the source of truth.
2020-06-23 06:44:34 +02:00
Héctor Ramón Jiménez
bbdf558bd7 Relayout when Application::scale_factor changes 2020-06-23 06:12:06 +02:00
Héctor Ramón
eec65a055f
Merge pull request #415 from hecrj/feature/configurable-scale-factor
Add `scale_factor` to `Application` and `Sandbox`
2020-06-20 19:20:37 +02:00
Héctor Ramón
1432c82bdf
Merge pull request #413 from hecrj/feature/configurable-default-text-size
Make default text size configurable in `Settings`
2020-06-19 19:24:52 +02:00
Héctor Ramón Jiménez
c9696ca687 Add scale_factor to Application and Sandbox 2020-06-19 19:17:05 +02:00
Héctor Ramón Jiménez
b3c192a2e4 Make default text size configurable in Settings 2020-06-19 00:16:22 +02:00
Héctor Ramón
d19c02035f
Merge pull request #407 from hecrj/feature/generic-slider
Make `Slider` value type generic
2020-06-14 18:11:25 +02:00
Héctor Ramón
50c37ff3d7
Merge pull request #406 from hecrj/feature/background-color
Add `background_color` to `Application` and `Sandbox`
2020-06-14 18:10:14 +02:00
Héctor Ramón Jiménez
f5e16312bf Update Slider docs in iced_web 2020-06-13 15:04:49 +02:00
Héctor Ramón Jiménez
6b4a4655c1 Make Slider value generic in iced_web 2020-06-13 14:59:09 +02:00
Héctor Ramón Jiménez
d7d2e0a8aa Increase precision in color_palette example 2020-06-13 14:50:21 +02:00
Héctor Ramón Jiménez
3cc32abc7c Reduce slider step in progress_bar example 2020-06-13 14:39:48 +02:00
Héctor Ramón Jiménez
7bc7b60321 Mention generic range in Slider documentation 2020-06-13 14:36:10 +02:00
Héctor Ramón Jiménez
4aed3ede92 Use generic Slider in tour example 2020-06-13 14:34:39 +02:00
Héctor Ramón Jiménez
c71d83fe0e Remove unnecessary type annotations in Slider 2020-06-13 14:34:23 +02:00
Héctor Ramón Jiménez
0b819de3e2 Make Slider value type generic 2020-06-13 14:17:41 +02:00
Héctor Ramón
f131969c47
Merge pull request #381 from loewenheim/slider_step
Added `step` member to slider widgets
2020-06-13 13:21:49 +02:00
Héctor Ramón Jiménez
4c0286e8ac Add background_color to Application and Sandbox 2020-06-12 22:12:15 +02:00
Héctor Ramón
2a516dfc48
Merge pull request #401 from Vanille-N/master
Calculated sweep_angle in call to lyon::geom::Arc was actually end_angle
2020-06-11 16:46:47 +02:00
Vanille-N
7b6f1baa69
Calculated sweep_angle in call to lyon::geom::Arc was actually end_angle
Adresses `Arc end_angle should be renamed to span_angle #400`
2020-06-11 14:58:47 +02:00
Sebastian Zivota
c3643eaf6d Add step member to slider widgets
Both the native and the web slider now have a member `step` to control
the least possible change of the slider's value. It defaults to 1.0
for all sliders and can be adjusted with the step method.
2020-06-11 00:18:24 +02:00
Héctor Ramón Jiménez
072ec69d53 Expose Content and TitleBar in iced_glow 2020-06-10 16:29:23 +02:00
Héctor Ramón Jiménez
3cfe6e428b Lay out title text dynamically in TitleBar 2020-06-10 16:27:28 +02:00
Héctor Ramón
baa1389f71
Merge pull request #391 from bansheerubber/feature/move_cursor_to_end
Cursor Manipulation
2020-06-09 19:12:52 +02:00
Héctor Ramón Jiménez
49dbf2c146 Request a redraw only on relevant events 2020-06-09 15:45:57 +02:00
Héctor Ramón
c0a5dc980e
Merge pull request #397 from hecrj/intuitive-pane-grid-resize
Intuitive `PaneGrid` resize
2020-06-09 09:35:01 +02:00
Héctor Ramón Jiménez
8b93c9cb6a Clarify leeway meaning in PaneGrid 2020-06-08 19:41:33 +02:00
bansheerubber
5260b3072a implemented hecrj's suggestion 2020-06-08 10:00:25 -07:00
Héctor Ramón Jiménez
ac7816e8ca Merge branch 'intuitive-pane-grid-resize' into feature/pane-grid-titlebar 2020-06-08 18:35:03 +02:00
Héctor Ramón Jiménez
172bd78a91 Fix PaneGrid documentation example 2020-06-08 18:34:41 +02:00
Héctor Ramón Jiménez
8493ccec7f Merge branch 'intuitive-pane-grid-resize' into feature/pane-grid-titlebar 2020-06-08 18:33:36 +02:00
Héctor Ramón Jiménez
dcc4bb77e9 Remove unused split_cache in pane_grid 2020-06-08 18:25:46 +02:00
Héctor Ramón Jiménez
be0cc2c780 Add leeway support to PaneGrid::on_resize 2020-06-08 18:25:23 +02:00
Héctor Ramón Jiménez
041cab0fa4 Resize PaneGrid without modifier keys 2020-06-08 18:11:29 +02:00
Duncan Freeman
4960a8827e
Add on_release message to Slider (#378)
* Add on_finish callback to Slider

* Fix formatting

* Rename Slider's on_finish to on_release, make the message simply an event without data

* Satisfy Clone impl requirement on Message in integration test

* Only call on_release after dragging a slider
2020-06-08 11:07:45 +02:00
Richard
40750d9b36
Removed empty bind group from integration example (#390) 2020-06-08 11:03:34 +02:00
Voker57
9e01adc964
Replace leftover docs in progress bar module (#396)
* Replace leftover docs in progress bar module

* Fix consistency of `ProgressBar` docs

Co-authored-by: Héctor Ramón Jiménez <hector0193@gmail.com>
2020-06-08 10:14:40 +02:00
bansheerubber
19c07da86f fixed formatting 2020-06-05 09:57:18 -07:00
bansheerubber
98cf9c455a added move_cursor_to 2020-06-05 09:19:46 -07:00
bansheerubber
0d119aa731 added value to move_cursor_to_end 2020-06-05 09:13:49 -07:00
bansheerubber
6a2c73d0e0 sketch of move_cursor_to commands 2020-06-05 08:58:34 -07:00
Héctor Ramón
ca6ff874a1
Merge pull request #387 from hatoo/add-comment
Add a comment of how to clear the display to `integration` example
2020-06-05 17:36:18 +02:00
Héctor Ramón Jiménez
fd3801ed38 Clear frames explicitly in integration example 2020-06-05 15:05:30 +02:00
Héctor Ramón Jiménez
4dc5bffdfb Draft draggable and graphics logic for TitleBar 2020-06-05 14:02:29 +02:00
Héctor Ramón Jiménez
e8e656b330 Implement Layout::position 2020-06-05 14:00:31 +02:00
Héctor Ramón Jiménez
4e1e0e0890 Draft drawing logic for Content and TitleBar 2020-06-05 06:52:07 +02:00
Héctor Ramón Jiménez
a11bcf5af0 Draft first-class TitleBar in pane_grid 2020-06-04 07:13:38 +02:00
hatoo
969de1d31c Add a comment of how to clear the display to integration example 2020-06-03 22:01:28 +09:00
Héctor Ramón
4c494c7244
Merge pull request #383 from cedric-h/patch-1
Prevent gratuitous resizing in integration example
2020-06-02 23:10:46 +02:00
Cedric Hutchings
d5b9dee2fd
Attempt to appease rustfmt 2020-06-02 16:48:55 -04:00
Héctor Ramón
e7f0d3809b
Merge pull request #379 from hecrj/canvas-fill-rule
Introduce fill rule setting in `canvas`
2020-06-02 22:43:21 +02:00
Cedric Hutchings
99eda093d6
Prevent gratuitous resizing in integration example
If I didn't miss anything, that `resized` variable is never set back to `false`, meaning that swapchain recreation is retriggered every frame after the first resize.
2020-06-02 16:40:46 -04:00
Héctor Ramón Jiménez
94af348846 Rename Rectangle::round to snap
Also use `ceil` instead of `round`.
Closes #380.
2020-06-02 04:38:55 +02:00
Héctor Ramón Jiménez
ede4440e99 Introduce fill rule setting in canvas 2020-06-02 02:21:07 +02:00
Héctor Ramón Jiménez
b96d87ff69 Revert "Merge pull request #371 from myfreeweb/window-alpha"
This reverts commit 2ba9598f8022bf3035d97f1a30e53117b9619235, reversing
changes made to d34f8e06c8e3cdbba07a272f346163cfc0f920a6.
2020-06-01 22:07:29 +02:00
Héctor Ramón
2ba9598f80
Merge pull request #371 from myfreeweb/window-alpha
Add custom window background/clear color (incl. transparency) support, fixes #272
2020-06-01 22:01:28 +02:00
Héctor Ramón
d34f8e06c8
Merge pull request #370 from azriel91/improvement/58/feature-gate-font-kit
Improvement/58/feature gate font kit
2020-06-01 21:47:45 +02:00
Greg V
a65d6a11cb Add custom window background/clear color (incl. transparency) support, fixes #272
wgpu would currently ignore the alpha: https://github.com/gfx-rs/wgpu/issues/687

glow (and naively patched wgpu) requires premultiplied alpha, so if you don't
multiply the RGB by the A right now, the semi-transparent color would be wrong
(too bright).

winit with_transparent doesn't seem necessary.
2020-06-01 21:31:19 +03:00
Azriel Hoh
86f0e3d4e2 Update CHANGELOG.md. 2020-05-31 11:00:23 +12:00
Azriel Hoh
ae9521e500 Feature gate font-kit behind "default_system_font" feature. 2020-05-31 11:00:17 +12:00
Héctor Ramón Jiménez
05750bf186 Fix Backend link in iced_glow docs 2020-05-30 03:05:12 +02:00
Héctor Ramón Jiménez
6cb90570a3 Expose Backend in iced_glow 2020-05-30 03:04:16 +02:00
Héctor Ramón Jiménez
6d73b94e9a Fix documentation of Backend in iced_wgpu 2020-05-30 03:03:59 +02:00
Héctor Ramón
96b2afba31
Merge pull request #369 from hecrj/async-wgpu-compositor-creation
Implement async `Compositor::request` in `iced_wgpu`
2020-05-30 00:31:23 +02:00
Héctor Ramón
f8cb3acc48
Merge pull request #365 from Imberflur/text-input-font
Make `Font` an associated type of `text_input::Renderer`
2020-05-29 23:10:14 +02:00
Héctor Ramón Jiménez
3ef49cd51c Re-export Antialiasing in iced_wgpu 2020-05-29 23:09:15 +02:00
Héctor Ramón Jiménez
0691ec3195 Implement async Compositor::request in iced_wgpu 2020-05-29 23:08:34 +02:00
Imbris
490a437b2f Make Font an associated type of text_input::Renderer 2020-05-29 15:37:25 -04:00
Héctor Ramón Jiménez
ab0ee1a8d0 Expose pane_grid::{Node, Content} in iced_glow 2020-05-29 02:24:09 +02:00
Héctor Ramón
01a4d65404
Merge pull request #363 from Imberflur/text-clone
Make the Text widget Clone even if the Renderer isn't
2020-05-29 02:14:09 +02:00
Héctor Ramón
8a864fcce9
Merge pull request #359 from hecrj/improvement/update-wgpu_glyph
Update `wgpu_glyph` and `glyph_brush`
2020-05-29 02:13:26 +02:00
Héctor Ramón Jiménez
0cde20b355 Merge branch 'master' into improvement/update-wgpu_glyph 2020-05-29 02:00:28 +02:00
Héctor Ramón Jiménez
67b6f044e8 Use published version of wgpu_glyph 2020-05-29 01:55:51 +02:00
Héctor Ramón Jiménez
e11b5c614f Revert "Target physical pixels for quads in iced_glow"
This reverts commit 45511a442f707e93fe6e568d2100756b63af7362.
2020-05-28 22:57:30 +02:00
Héctor Ramón Jiménez
6de0a2c371 Use Sandbox in tour example 2020-05-28 22:50:40 +02:00
Héctor Ramón Jiménez
7f9813d4b3 Revert "Merge pull request #362 from hecrj/fix/target-quad-pixels"
This reverts commit 40501f630d8a5aa234ea23b7eaae37060e0e08a5, reversing
changes made to 5324eb10242a7dd33f5271dc6fc9eeb09eb2cb50.
2020-05-28 22:44:52 +02:00
Héctor Ramón
d3db055583
Merge pull request #354 from hecrj/feature/glow-renderer
OpenGL renderer and backend-agnostic graphics subcrate
2020-05-28 21:52:34 +02:00
Héctor Ramón Jiménez
709ed1f3f7 Fix iced_native mention of old window::Backend 2020-05-28 21:30:33 +02:00
Imbris
0a775191ab Loosen bounds on Text Clone impl 2020-05-27 22:12:38 -04:00
Héctor Ramón Jiménez
16c1261d82 Enable doc_cfg for docs.rs in iced_glow 2020-05-28 04:03:51 +02:00
Héctor Ramón
ead4186870
Merge pull request #361 from clarkmoody/pane-grid-spacing
Proper Pane Grid spacing
2020-05-28 03:45:22 +02:00
Héctor Ramón
40501f630d
Merge pull request #362 from hecrj/fix/target-quad-pixels
Align quads to physical pixels in `iced_wgpu`
2020-05-28 03:20:40 +02:00
Héctor Ramón Jiménez
4aa0d7a13a Write documentation for iced_glutin 2020-05-28 02:57:03 +02:00
Héctor Ramón Jiménez
ef28347f1c Write documentation for new iced_winit API 2020-05-28 02:49:32 +02:00
Héctor Ramón Jiménez
508128436c Write documentation for new iced_native API 2020-05-28 02:04:31 +02:00
Héctor Ramón Jiménez
b9d42a45a8 Write documentation for iced_glow 2020-05-28 01:46:17 +02:00
Héctor Ramón Jiménez
2ca7e3c4b0 Write documentation for iced_graphics 2020-05-28 01:40:30 +02:00
Cory Forsstrom
c7bb434113
remove re-export on viewer::State 2020-05-27 14:20:42 -07:00
Héctor Ramón Jiménez
45511a442f Target physical pixels for quads in iced_glow 2020-05-27 23:17:21 +02:00
Cory Forsstrom
5dd62bacd5
update docs 2020-05-27 14:16:38 -07:00
Héctor Ramón Jiménez
823ea15732 Update glyph_brush and glow_glyph 2020-05-27 23:09:27 +02:00
Cory Forsstrom
de176beb28
centered image and zoom to cursor 2020-05-27 13:39:26 -07:00
Clark Moody
858eafe22e Structured test cases 2020-05-27 14:24:33 -05:00
Héctor Ramón Jiménez
22ced3485e Introduce feature flags to enable iced_glow
Also keep `iced_wgpu` as the default renderer for the time being.
2020-05-27 05:05:13 +02:00
Cory Forsstrom
5d045c2e9a
rename to image::Viewer 2020-05-26 17:16:05 -07:00
Cory Forsstrom
431171f975
Rename and add to iced image module 2020-05-26 16:56:34 -07:00
Cory Forsstrom
6bf459e068
Rebase to master and update for api changes 2020-05-26 16:56:34 -07:00
Cory Forsstrom
7f7e803448
Show idle cursor if image can't be panned 2020-05-26 16:56:34 -07:00
Cory Forsstrom
0d8cefbf2d
Add ImagePane widget 2020-05-26 16:56:34 -07:00
Héctor Ramón Jiménez
fbe3aa3cf4 Align quads to physical pixels in iced_wgpu 2020-05-27 00:23:42 +02:00
Clark Moody
9079014974 Tests for axis split 2020-05-26 16:47:29 -05:00
Clark Moody
334dd09817 Pane Grid spacing applied prior to rounding
On low-DPI screens, the rounding order of operations made it impossible
to produce an odd-pixel spacing. Specifying 1, for instance, produced
zero space between panes.

This approach subtracts half the spacing from the first pane prior to
rounding and uses the whole spacing for the second pane size and
coordinate.
2020-05-26 16:24:18 -05:00
Héctor Ramón Jiménez
f5ee6d0e51 Update wgpu_glyph and glyph_brush 2020-05-25 21:49:16 +02:00
Héctor Ramón
5324eb1024
Merge pull request #358 from hecrj/improvement/pane-grid-ergonomics
Implement `State::layout` and `State::with_content` in `pane_grid`
2020-05-25 20:34:10 +02:00
Héctor Ramón Jiménez
230bd6f747 Write documentation for new pane_grid API 2020-05-23 01:51:34 +02:00
Héctor Ramón Jiménez
2ab7341fa5 Implement State::with_content in pane_grid 2020-05-22 21:56:50 +02:00
Héctor Ramón Jiménez
32b9c1fdbd Return new Split in pane_grid::State::split 2020-05-22 21:55:55 +02:00
Héctor Ramón Jiménez
c620e4dc4c Implement State::get in pane_grid 2020-05-22 21:55:45 +02:00
Héctor Ramón Jiménez
f3d54a0f33 Expose Node and State::layout for PaneGrid 2020-05-22 21:55:31 +02:00
Héctor Ramón Jiménez
d1f2a18439 Implement Clone for pane_grid::State 2020-05-22 21:55:18 +02:00
Héctor Ramón Jiménez
d6bf8955db Use published glow and glow_glyph versions 2020-05-22 19:17:07 +02:00
Héctor Ramón Jiménez
1dd79c4697 Use built-in OpenGL multisampling in iced_glow 2020-05-22 19:15:39 +02:00
Héctor Ramón Jiménez
6f71a8e3d5 Use get_uniform_location for wider compatibility 2020-05-22 05:55:28 +02:00
Héctor Ramón Jiménez
1b287cddaf Use git repository for glow_glyph 2020-05-22 05:35:36 +02:00
Héctor Ramón Jiménez
c5545c7a73 Implement MSAA for triangle meshes in iced_glow 2020-05-22 01:16:12 +02:00
Héctor Ramón Jiménez
bbfb1c040c Update to latest glow 2020-05-21 19:50:53 +02:00
Héctor Ramón Jiménez
2798d4935e Remove unused overlay_font in iced_glow 2020-05-21 19:09:16 +02:00
Héctor Ramón Jiménez
60dcfc354e Draft triangle pipeline in iced_glow 2020-05-21 19:07:33 +02:00
Héctor Ramón Jiménez
d54f17c6aa Simplify integration example with Program 2020-05-21 04:57:00 +02:00
Héctor Ramón Jiménez
ae5e2c6c73 Introduce Program and State 2020-05-21 04:27:31 +02:00
Héctor Ramón Jiménez
d77492c0c3 Avoid relying origin_upper_left
It seems to cause considerable glitches when resizing.
2020-05-21 01:01:47 +02:00
Héctor Ramón Jiménez
e0e4ee73fe Implement iced_glutin 🎉 2020-05-21 00:44:35 +02:00
Héctor Ramón Jiménez
a1a5fcfd46 Refactor Viewport and Compositor 2020-05-20 20:28:35 +02:00
Héctor Ramón Jiménez
720e7756f2 Move Layer to iced_graphics 2020-05-19 23:19:39 +02:00
Héctor Ramón Jiménez
e618091248 Merge unnecessary split widget modules 2020-05-19 21:00:40 +02:00
Héctor Ramón Jiménez
c2e0c52ce0 Move Antialiasing to iced_graphics 2020-05-19 20:34:17 +02:00
Héctor Ramón Jiménez
f0480854a9 Move built-in fonts to iced_graphics 2020-05-19 20:30:46 +02:00
Héctor Ramón Jiménez
e0c4f1a08e Move font::Source to iced_graphics 2020-05-19 20:20:51 +02:00
Héctor Ramón Jiménez
4aed0fa4b6 Rename window::Backend to Compositor 2020-05-19 20:01:55 +02:00
Héctor Ramón Jiménez
a0ac09122a Move Viewport to iced_graphics 2020-05-19 19:57:42 +02:00
Héctor Ramón Jiménez
750a441a8c Move Transformation to iced_graphics 2020-05-19 19:55:05 +02:00
Héctor Ramón Jiménez
05af8d00d4 Draft new iced_graphics crate 🎉 2020-05-19 17:15:44 +02:00
Héctor Ramón Jiménez
d4743183d4 Draft first working version of iced_glow 🎉 2020-05-19 14:23:28 +02:00
Héctor Ramón
33448508a5
Merge pull request #345 from AberrantWolf/master
Update `Radio` to have the same layout members and fns as `Checkbox`
2020-05-15 14:58:28 +02:00
Scott Harper
175f5d71f4 Merge remote-tracking branch 'upstream/master' 2020-05-15 11:38:08 +09:00
Scott Harper
863714602c Updated Radio layout/fns to match Checkbox 2020-05-15 11:27:24 +09:00
Héctor Ramón
e89e521e2b
Merge pull request #344 from DominosCinnaStix/master
fix(wgpu): Set adapter backend to PRIMARY
2020-05-14 18:17:25 +02:00
DominosCinnaStix
cd6064fd84
set wgpu's adapter backend to PRIMARY 2020-05-14 11:55:26 -04:00
Héctor Ramón Jiménez
7565d294af Fix PaneGrid not releasing split properly 2020-05-06 06:18:22 +02:00
Héctor Ramón Jiménez
4406494ff3 Pin gfx-memory until allocator issue is fixed
https://github.com/gfx-rs/wgpu-rs/issues/261
2020-05-06 00:18:15 +02:00
Héctor Ramón
26d93004a6
Merge pull request #334 from Veykril/master
Update iced_wgpu dependencies
2020-05-05 01:28:50 +02:00
Lukas Wirth
3a5a07d49d Update iced_wgpu dependencies
font-kit 0.4 -> 0.6
guillotiere 0.4 -> 0.5
image 0.22 -> 0.23
resvg 0.8 -> 0.9
2020-05-05 01:04:40 +02:00
Héctor Ramón
7dc02a5e16
Merge pull request #325 from hecrj/feature/canvas-interaction
Canvas interactivity and Game of Life example
2020-05-05 00:05:47 +02:00
Héctor Ramón Jiménez
93c6be5eef Update README of game_of_life example 2020-05-04 23:54:28 +02:00
Héctor Ramón Jiménez
80e2d1b08b Adapt color_palette to new canvas API 2020-05-04 23:46:15 +02:00
Héctor Ramón Jiménez
67b2ccb4d5 Merge branch 'master' into feature/canvas-interaction 2020-05-04 23:35:09 +02:00
Héctor Ramón
27aad74a32
Merge pull request #200 from clarkmoody/color-enhancements
Color Enhancements
2020-05-04 23:30:51 +02:00
Héctor Ramón Jiménez
c0fd5de8a0 Improve minor documentation details in Color 2020-05-04 23:04:02 +02:00
Héctor Ramón Jiménez
e3555174d7 Use only iced dependency for color_palette
`Point` and `Size` are now properly re-exported.
2020-05-04 22:55:10 +02:00
Héctor Ramón Jiménez
3d3e51a742 Add screenshot to README of color_palette 2020-05-04 22:53:07 +02:00
Héctor Ramón Jiménez
1a8d253611 Add screenshot of color_palette example 2020-05-04 22:51:20 +02:00
Héctor Ramón Jiménez
24574b355d Mention color_palette in examples README 2020-05-04 22:50:25 +02:00
Héctor Ramón Jiménez
2f41ccee1c Update GIF of game_of_life example 2020-05-03 02:49:04 +02:00
Héctor Ramón Jiménez
917199197f Allow erasing cells in game_of_life 2020-05-03 02:43:20 +02:00
Héctor Ramón Jiménez
4417a34edb Fix "1 cells" overlay in game_of_life 2020-05-03 02:15:11 +02:00
Héctor Ramón Jiménez
5aaaea7c88 Render stats as an overlay in game_of_life
Also allow toggling the grid lines
2020-05-03 01:53:45 +02:00
Héctor Ramón Jiménez
c3c5161386 Draw grid in game_of_life 2020-05-03 00:57:15 +02:00
Héctor Ramón Jiménez
a43fb42428 Reorganize view code in game_of_life 2020-05-03 00:08:41 +02:00
Héctor Ramón Jiménez
cc8f5b6fc8 Simplify logic and limit ticks in game_of_life 2020-05-02 10:48:42 +02:00
Héctor Ramón Jiménez
0025b8c3f8 Display some statistics in game_of_life 2020-05-02 09:27:49 +02:00
Héctor Ramón Jiménez
916a1bfc70 Run ticks in a background thread in game_of_life 2020-05-02 07:01:27 +02:00
Héctor Ramón Jiménez
8fa9e4c94e Rename visible_in to within in game_of_life 2020-05-02 03:37:20 +02:00
Héctor Ramón Jiménez
4fd8e47737 Use rustc_hash for hashing in game_of_life
This seems to produce a 2x speedup.
2020-05-02 03:33:03 +02:00
Héctor Ramón Jiménez
03ca7eea6c Reuse triangle path with transforms in color_palette 2020-05-01 22:45:47 +02:00
Héctor Ramón Jiménez
573929d5ec Use Path::rectangle directly in color_palette 2020-05-01 22:32:40 +02:00
Héctor Ramón Jiménez
555371f77e Move application implementation in color_palette 2020-05-01 22:27:14 +02:00
Héctor Ramón Jiménez
4d724a88e6 Introduce Theme type in color_palette example 2020-05-01 22:24:34 +02:00
Héctor Ramón Jiménez
0a011f9031 Improve generate_theme in color_palette 2020-05-01 21:51:08 +02:00
Héctor Ramón Jiménez
11e4039b56 Remove update_component in color_palette
We can use `ColorSpace::new` instead
2020-05-01 21:43:11 +02:00
Héctor Ramón Jiménez
e7e8e76c28 Change speed limit to 100 in game_of_life 2020-05-01 06:23:30 +02:00
Héctor Ramón Jiménez
1833c77312 Improve scrolling smoothness in game_of_life 2020-05-01 06:23:05 +02:00
Héctor Ramón Jiménez
ffbe59f812 Zoom to cursor in game_of_life example 2020-05-01 05:42:07 +02:00
Héctor Ramón Jiménez
0a5f1bb676 Improve zooming logic in game_of_life 2020-05-01 05:21:27 +02:00
Héctor Ramón Jiménez
c23995ecb4 Increase speed limit to 200 in game_of_life 2020-05-01 05:13:22 +02:00
Héctor Ramón Jiménez
f9227546ca Use fill_rectangle for cursor in game_of_life 2020-05-01 04:41:04 +02:00
Héctor Ramón Jiménez
404122e0b1 Implement zooming for game_of_life example 2020-05-01 04:35:59 +02:00
Héctor Ramón Jiménez
08b376c6d7 Implement Frame::fill_rectangle
This method greatly improves performance when drawing axis-aligned rectangles.
2020-05-01 04:34:09 +02:00
Héctor Ramón Jiménez
345f0e1336 Implement scalar multiplication for Vector 2020-05-01 04:32:56 +02:00
Héctor Ramón Jiménez
980ac6c2a4 Add UNIT constant to Size 2020-05-01 04:30:54 +02:00
Héctor Ramón Jiménez
377ead93d6 Improve tick performance in game_of_life 2020-05-01 01:24:31 +02:00
Héctor Ramón Jiménez
a6db1e1fb3 Introduce Life type in game_of_life 2020-05-01 01:08:39 +02:00
Héctor Ramón Jiménez
71323c51bb Simplify Interaction handling in game_of_life 2020-05-01 00:54:43 +02:00
Héctor Ramón Jiménez
ee97887409 Introduce Cell type in game_of_life 2020-05-01 00:50:40 +02:00
Héctor Ramón Jiménez
005ad6215a Update README of game_of_life example 2020-04-30 08:59:47 +02:00
Héctor Ramón Jiménez
98bc8cf2a7 Rename MouseCursor to mouse::Interaction 2020-04-30 08:16:38 +02:00
Héctor Ramón Jiménez
d4c4198f72 Write documentation for the new canvas API 2020-04-30 07:38:46 +02:00
Héctor Ramón Jiménez
1501a93915 Disable time module on Wasm for now 2020-04-30 05:51:41 +02:00
Héctor Ramón Jiménez
e2076612cb Implement time::every in iced_futures 2020-04-30 05:37:44 +02:00
Héctor Ramón Jiménez
bb9ccc4f62 Remove inconsistent input module in iced_native 2020-04-30 05:04:45 +02:00
Héctor Ramón Jiménez
137664ca88 Move keyboard::Event to iced_core 2020-04-30 04:59:07 +02:00
Héctor Ramón Jiménez
d8b9e03481 Remove ButtonState 2020-04-30 04:54:49 +02:00
Héctor Ramón Jiménez
e55cd9652e Split Input mouse event by ButtonState 2020-04-30 04:53:15 +02:00
Héctor Ramón Jiménez
e139aae143 Split Input keyboard event by ButtonState 2020-04-30 04:34:29 +02:00
Héctor Ramón Jiménez
af95d3972e Implement camera panning in game_of_life example 2020-04-30 04:12:13 +02:00
Héctor Ramón Jiménez
611d9e399c Clarify tick logic in game_of_life 2020-04-29 23:55:15 +02:00
Héctor Ramón Jiménez
5e014a70e8 Use sparse grid representation in game_of_life 2020-04-29 23:50:15 +02:00
Héctor Ramón Jiménez
38c4dd5fdb Reduce initial size of triangle buffers in iced_wgpu 2020-04-29 23:49:37 +02:00
Héctor Ramón Jiménez
5d12e194f4 Rename Cursor::*_position methods in canvas 2020-04-29 20:58:59 +02:00
Héctor Ramón Jiménez
70f86f998b Add game_of_life example
RIP John Conway
2020-04-29 08:25:42 +02:00
Héctor Ramón Jiménez
afa0bca4fd Implement Rectangle::position 2020-04-29 08:25:27 +02:00
Héctor Ramón Jiménez
61c707fe04 Merge branch 'master' into feature/canvas-interaction 2020-04-29 07:34:14 +02:00
Héctor Ramón Jiménez
dc51080328 Introduce Cursor type in canvas 2020-04-29 04:25:49 +02:00
Héctor Ramón Jiménez
5586034d66 Display crosshair cursor in bezier_tool example 2020-04-29 03:23:27 +02:00
Héctor Ramón Jiménez
475a2779a7 Implement Rectangle::with_size 2020-04-29 03:23:08 +02:00
Héctor Ramón Jiménez
ec712c8032 Move MouseCursor to iced_core 2020-04-29 03:23:02 +02:00
Héctor Ramón Jiménez
52719c7076 Let a canvas::Program control the mouse cursor 2020-04-29 03:16:03 +02:00
Héctor Ramón Jiménez
0509710cc5 Add Crosshair variant to MouseCursor 2020-04-29 03:14:59 +02:00
Héctor Ramón Jiménez
59403b6ca8 Remove OutOfBounds variant from MouseCursor 2020-04-29 03:11:15 +02:00
Héctor Ramón Jiménez
85dc07c3b0 Expose Rectangle in iced_web 2020-04-28 06:31:00 +02:00
Héctor Ramón Jiménez
2539042b71 Remove Drawable and rename State to Program 2020-04-28 06:24:12 +02:00
Héctor Ramón Jiménez
7f1e7aea07 Remove unnecessary Container in bezier_tool 2020-04-28 04:41:25 +02:00
Héctor Ramón Jiménez
e65585ae17 Clip and cull Mesh2D primitives in iced_wgpu 2020-04-28 04:41:09 +02:00
Héctor Ramón Jiménez
69c60d372c Implement std::ops::Add<Vector> for Rectangle 2020-04-28 04:40:23 +02:00
Héctor Ramón Jiménez
5d5e60a5cc Implement Rectangle::new 2020-04-28 04:39:59 +02:00
Héctor Ramón Jiménez
fd1ceac363 Port bezier_tool example to use Canvas 2020-04-28 03:57:33 +02:00
Héctor Ramón Jiménez
e4eb0553de Allow canvas::State to produce messages 2020-04-28 03:52:12 +02:00
Héctor Ramón Jiménez
2ca73036ab Implement Drawable for slices of drawables 2020-04-28 03:52:12 +02:00
Héctor Ramón Jiménez
59b1e90661 Introduce Translate primitive in iced_wgpu 2020-04-28 03:52:10 +02:00
Héctor Ramón Jiménez
2381a9310c Ask for a Size in Frame::new 2020-04-28 03:16:18 +02:00
Héctor Ramón Jiménez
b0825ce38b Add convenient builder methods to canvas::Stroke 2020-04-28 03:14:05 +02:00
Héctor Ramón Jiménez
56dbd68326 Move reusable mouse types to iced_core 2020-04-28 03:11:01 +02:00
Héctor Ramón Jiménez
20d79a43cc Implement Default for Point 2020-04-28 03:06:35 +02:00
Héctor Ramón Jiménez
6c2e28d20e Implement std::ops::Sub<Point> for Point 2020-04-28 01:12:27 +02:00
Héctor Ramón Jiménez
dc97d6f33e Remove interaction from solar_system example 2020-04-28 01:10:59 +02:00
Clark Moody
430f78a693 Abstract into ColorPicker and ColorSpace trait
Each color type implements ColorSpace to define its own representation
and update methods.

View sliders are implemented on the ColorPicker struct.
2020-04-27 16:25:13 -05:00
Héctor Ramón
e0aa89cee7
Merge pull request #324 from ethanpailes/document-image-format-guessing
document that img handle constructors guess fmt
2020-04-27 17:49:13 +02:00
Ethan Pailes
da2ab420ce document that img handle constructors guess fmt
This patch documents the fact that a couple of the image
handle constructors know how to guess the image format based
on the data that they are provided.

I had to dig through `iced` sources until I discovered that those
routines ultimately boil down to stuff like [image::load_from_memory][1]
from the `image` crate, so I thought I would save others the trouble
of doing the same reverse-engineering

[1]: https://docs.rs/image/0.23.4/image/fn.load_from_memory.html
2020-04-26 15:03:48 -04:00
Héctor Ramón Jiménez
3f4770fd28 Bump versions 🎉 2020-04-26 17:20:56 +02:00
Héctor Ramón Jiménez
e87f3acff4 Render meshes after quads in iced_wgpu 2020-04-26 17:09:03 +02:00
Héctor Ramón
f9bfa82ebc
Merge pull request #322 from AlisCode/aliscode/321/fix-async-examples
#321 Fix async examples by feature-gating Command implementations + A…
2020-04-25 02:39:10 +02:00
Héctor Ramón Jiménez
63f54edf0c Use Rc in Command::map for Wasm 2020-04-25 02:29:40 +02:00
Olivier Pinon
f1e18d0935 #321 cargo fmt 2020-04-25 02:05:17 +02:00
Olivier Pinon
ce2ed35a1a #321 Fix async examples by feature-gating Command implementations + Add pokedex example in CI so that at least one async example is runned on CI 2020-04-25 02:03:17 +02:00
Clark Moody
3e71eaee37 Use Path::rectangle and Size for drawing swatches 2020-04-24 15:40:28 -05:00
Clark Moody
758a444d7f Replace text input fields for simple text 2020-04-24 15:31:12 -05:00
Clark Moody
27fadad324 Do not re-export Palette from iced_core 2020-04-24 15:20:00 -05:00
Clark Moody
4b90241ea1 Hex label text alignment 2020-04-24 15:13:22 -05:00
Clark Moody
39fd8ad9e9 TextInput fields with color encodings. Draw shades. 2020-04-24 15:13:22 -05:00
Clark Moody
b1328f193c More theme colors and gradient of lightness 2020-04-24 15:13:22 -05:00
Clark Moody
6b18e78e53 Use canvas to draw color palette for example 2020-04-24 15:13:22 -05:00
Clark Moody
664a63a4b8 Add example program: color palette
Sliders for many color spaces update as any other sliders are moved
around. Color is space is clamped to sRGB, so Lab and Lch color spaces
cannot be fully expressed.

TODO:
- Real-time manipulation of base color to create a color scheme.
- Show slider value under each slider
- Show output values in text boxes for each color space
2020-04-24 15:13:22 -05:00
Clark Moody
71657b50dd Conditional re-export of palette from iced_core 2020-04-24 15:13:22 -05:00
Clark Moody
04be010fbd Conversion traits for palette::Srgb 2020-04-24 15:13:22 -05:00
Clark Moody
ea3b7b5282 Derive Default for Color 2020-04-24 15:13:22 -05:00
Clark Moody
56ce01e262 Simplify range declaration 2020-04-24 15:13:22 -05:00
Clark Moody
a95d494f70 Remove redundant from_srgba and into_srgba methods 2020-04-24 15:13:22 -05:00
Clark Moody
408e9e566f Add palette test for Color <-> Srgba & manipulation 2020-04-24 15:13:22 -05:00
Clark Moody
7b15e4b0e2 Feature name colors -> palette 2020-04-24 15:13:22 -05:00
Clark Moody
e926e43742 Add const from_rgba, for RGBA initialization 2020-04-24 15:13:22 -05:00
Clark Moody
9a4ad3d6a7 Use debug assertions instead of clamp 2020-04-24 15:13:22 -05:00
Clark Moody
fd484c7638 Fix docstring typo 2020-04-24 15:13:22 -05:00
Clark Moody
bb44398819 Revert from_rgb to const 2020-04-24 15:13:22 -05:00
Clark Moody
4009f0cf73 Remove HSLColor 2020-04-24 15:13:22 -05:00
Clark Moody
831a07f720 Conversion to palette's Srgba type 2020-04-24 15:13:22 -05:00
Clark Moody
63933e26d2 Add palette dependency behind "colors" feature flag 2020-04-24 15:13:22 -05:00
Clark Moody
0ff3cbf543 HSLColor struct, with conversions to/from RGB 2020-04-24 15:13:22 -05:00
Clark Moody
27a4cbccea Add inversion functions, rename check_rgba -> new 2020-04-24 15:13:22 -05:00
Clark Moody
62fddce2e6 Add check_rgba fn to clamp float values to [0,1] 2020-04-24 15:13:22 -05:00
Héctor Ramón
70081c9649
Merge pull request #318 from hecrj/font-associated-type
Make `Font` an associated type of `text::Renderer`
2020-04-24 19:45:48 +02:00
Héctor Ramón Jiménez
0300b649d7 Make Font an associated type of text::Renderer 2020-04-23 22:17:11 +02:00
Héctor Ramón Jiménez
6786b8a3aa Implement Default for Font 2020-04-23 22:17:00 +02:00
Héctor Ramón
3375824630
Merge pull request #314 from katktv/patch-1
Fix a typo in ROADMAP
2020-04-22 17:08:20 +02:00
kat
f30043ddc2
Fix a typo in ROADMAP 2020-04-22 15:07:01 +03:00
Tom Pridham
852d59752e add some accessibility features to web widgets 2020-04-21 22:35:32 -06:00
Héctor Ramón Jiménez
f59832e88e Fix alignment in triangle pipeline of iced_wgpu 2020-04-19 21:56:03 +02:00
Héctor Ramón Jiménez
592cc68506 Remove Layer trait and simplify Canvas 2020-04-19 21:55:23 +02:00
Héctor Ramón Jiménez
bb424e54c5 Add interactivity to solar_system example 2020-04-19 18:48:30 +02:00
Héctor Ramón Jiménez
a97acd8fa8 Use Borrow<T> when binding in layer::Cache<T> 2020-04-19 17:59:32 +02:00
Héctor Ramón
edd01159e0
Merge pull request #305 from hecrj/element-on-event
Implement and expose `Element::on_event`
2020-04-19 15:28:53 +02:00
Héctor Ramón Jiménez
8ade09a0f6 Simplify Canvas example in documentation 2020-04-19 14:41:25 +02:00
Héctor Ramón Jiménez
0b5028b1ab Draft Program interactivity for Canvas 2020-04-19 14:39:30 +02:00
Héctor Ramón Jiménez
462ba3b2c8 Implement and expose Element::on_event 2020-04-18 21:32:04 +02:00
ethanpailes
90c3a183d5
fix progress bar docs to no longer mention buttons (#301) 2020-04-18 21:12:44 +02:00
Héctor Ramón Jiménez
ae546a5b9d Revert "Merge pull request #289 from hecrj/fix/cursor-events"
`winit` seems to produce `CursorEntered` and `CursorLeft` events after
wheel scrolling for no apparent reason (?). This causes annoying flickering when hovering some widgets on a scrollable.

I should investigate this further. We are rolling back the fix for the
time being.
2020-04-17 23:27:50 +02:00
Héctor Ramón Jiménez
b44f14e186 Fix MSAA blit vertex shader to match wgpu NDC 2020-04-16 14:54:29 +02:00
Lain-dono
b23945c78a
Change &mut wgpu::Device to &wgpu::Device (#299)
* Change `&mut wgpu::Device` to `&wgpu::Device`

* Fix for rustfmt
2020-04-16 08:06:05 +02:00
Héctor Ramón
99e020c7b5
Merge pull request #269 from hecrj/update-wgpu
Update `wgpu` to `0.5` in `iced_wgpu`
2020-04-16 04:59:56 +02:00
Héctor Ramón Jiménez
4808fcbd7e Bump versions 🎉 2020-04-15 08:58:14 +02:00
Héctor Ramón Jiménez
f37a658962 Update CHANGELOG 2020-04-15 08:44:01 +02:00
Héctor Ramón Jiménez
5cb40dc095 Mention flags are not supported by Sandbox
Fixes #291
2020-04-15 07:56:25 +02:00
Héctor Ramón
99352f02fd
Merge pull request #293 from hecrj/improvement/canvas-ergonomics
Improve `Canvas` ergonomics
2020-04-15 05:43:40 +02:00
Héctor Ramón
d0ebcdb936
Merge pull request #294 from MrMonotone/patch-1
Fix tour example
2020-04-14 08:04:12 +02:00
Héctor Ramón Jiménez
88b7dd6601 Check Wasm compilation of tour example in CI 2020-04-14 07:44:04 +02:00
Héctor Ramón Jiménez
f7825fd936 Fix Checkbox and Radio API in iced_web 2020-04-14 07:41:35 +02:00
Héctor Ramón Jiménez
6d7f2b30cc Simplify drawing logic in clock example 2020-04-14 07:19:50 +02:00
Nicholas
67fd107746
Fix tour example 2020-04-13 22:19:47 -07:00
Héctor Ramón Jiménez
3df49bebd4 Implement canvas::Path::line helper method 2020-04-14 07:08:12 +02:00
Héctor Ramón Jiménez
46cd0891d2 Implement canvas::Path::circle helper method 2020-04-14 06:54:12 +02:00
Héctor Ramón Jiménez
c545af3577 Implement canvas::Path::rectangle helper method 2020-04-14 06:49:15 +02:00
Héctor Ramón Jiménez
5c923fce48 Implement From<&str> for canvas::Text 2020-04-14 06:43:58 +02:00
Héctor Ramón Jiménez
a2296b466b Implement From<String> for canvas::Text 2020-04-14 06:43:43 +02:00
Héctor Ramón Jiménez
6779fcf621 Make Frame::fill_text take a generic Into<Text> 2020-04-14 06:40:22 +02:00
Héctor Ramón Jiménez
dce1034699 Make Frame::stroke take a generic Into<Stroke> 2020-04-14 06:39:47 +02:00
Héctor Ramón Jiménez
81096ef454 Implement From<Color> for canvas::Fill 2020-04-14 06:38:06 +02:00
Héctor Ramón Jiménez
2a795faf4e Make Frame::fill take a generic Into<Fill>
This can be used to improve readability by using your own types.
2020-04-14 06:37:27 +02:00
Héctor Ramón Jiménez
2fce83b205 Use new release of wgpu_glyph 2020-04-13 05:02:07 +02:00
Héctor Ramón
ce65097834
Merge pull request #290 from AlisCode/aliscode/288/remove-unnecessary-static
Remove unnecessary 'static lifetimes on `Renderer` traits
2020-04-13 04:49:10 +02:00
Héctor Ramón Jiménez
5e47238489 Rename leftover TextInputWidget to Marker 2020-04-13 04:38:35 +02:00
Héctor Ramón
bc70ba12f1
Merge pull request #289 from hecrj/fix/cursor-events
Produce and handle `CursorEntered` and `CursorLeft`
2020-04-13 04:33:39 +02:00
Olivier Pinon
41f6a325e9 #288 Renamed XXXWidget to Marker 2020-04-12 01:20:40 +02:00
Olivier Pinon
f7d7ab1ba9 Remove unnecessary 'static lifetime on Renderer 2020-04-12 00:57:44 +02:00
Héctor Ramón Jiménez
f652e84187 Make cursor unavailable on leave in iced_winit
For now, we just set the cursor position to some negative coordinates.
This is a temporary hack until we are able to encode cursor
availability. Layers and/or multi-window support will make this
apparent.
2020-04-12 00:38:18 +02:00
Héctor Ramón Jiménez
4b0cc178dd Produce cursor events in iced_winit::conversion 2020-04-12 00:37:13 +02:00
Héctor Ramón
e941eab4ab
Merge pull request #281 from hecrj/fix/canvas-text-alignment
Align text in `iced_wgpu` on a case-by-case basis
2020-04-10 23:16:21 +02:00
Héctor Ramón Jiménez
47d44af348 Fix bezier_tool placeholder text alignment 2020-04-10 02:49:04 +02:00
Héctor Ramón Jiménez
b549b509c9 Align text in iced_wgpu on a case-by-case basis 2020-04-10 01:39:36 +02:00
Héctor Ramón
19f6a5e2fd
Merge pull request #279 from hecrj/fix/text-input-measure-value
Fix `text_input::Renderer` implementation in `iced_wgpu`
2020-04-10 01:18:29 +02:00
Héctor Ramón
867dad62fa
Merge pull request #278 from hecrj/fix/canvas-empty-mesh
Stop generating empty `Mesh2D` in `canvas::Frame`
2020-04-10 01:18:19 +02:00
Héctor Ramón Jiménez
d3dee849b7 Fix unnecessary clip of text input in iced_wgpu
It should only produce a `Clip` primitive when the contents overflow the
input now.
2020-04-09 05:17:06 +02:00
Héctor Ramón Jiménez
9afa31899f Fix measure_value for text input in iced_wgpu
It accounts for spaces at the start of text now.
2020-04-09 05:01:09 +02:00
Héctor Ramón Jiménez
10f5f95a80 Stop generating empty Mesh2D in canvas::Frame 2020-04-09 04:26:02 +02:00
Héctor Ramón
d51b501d2f
Merge pull request #267 from robjtede/improve/canvas-cache-default
impl default for canvas cache
2020-04-09 00:34:37 +02:00
Rob Ede
6e7769b65d
impl default for canvas cache 2020-04-08 23:07:42 +01:00
Héctor Ramón Jiménez
d65d838869 Fix angle sign in canvas::Frame::rotate 2020-04-08 22:56:52 +02:00
Héctor Ramón Jiménez
d807ef367e Update wgpu to 0.5 in iced_wgpu 🎉 2020-04-07 05:48:21 +02:00
Héctor Ramón
703beae05e
Merge pull request #268 from FabianLars/ctrl-del
implement ctrl + del on text-input
2020-04-07 04:39:16 +02:00
Héctor Ramón
6e386312bd
Merge pull request #266 from robjtede/improve/flags-init
add init method for settings with flags
2020-04-06 22:01:16 +02:00
Héctor Ramón
0f60253661
Merge pull request #260 from 0x7CFE/fix-checkbox-label
Checkbox label is now `Into<String>`
2020-04-06 20:31:39 +02:00
Héctor Ramón Jiménez
3c47e3e229 Simplify Language conversion in tour 2020-04-06 20:12:16 +02:00
FabianLars
6ca97788b2 implement ctrl + del on text-input 2020-04-06 15:22:52 +02:00
Rob Ede
0766da7509
add helper for settings flags init 2020-04-06 01:14:38 +01:00
Héctor Ramón
ad0a6c4c10
Merge pull request #259 from robjtede/docs/feature-flags
reference feature flags in docs
2020-04-05 18:32:51 +02:00
Dmitry Kashitsyn
1a9bfd9e73
Radiobutton label is now impl Into<String> 2020-04-05 12:43:18 +07:00
Dmitry Kashitsyn
15f5b93a0d
Checkbox label is now impl Into<String> 2020-04-05 11:48:44 +07:00
Héctor Ramón Jiménez
335ad1dd1d Enable feature flags in docs.rs 2020-04-05 04:52:03 +02:00
Héctor Ramón Jiménez
7479ba137f Document widget feature flags 2020-04-05 04:38:10 +02:00
Rob Ede
070e8e70e4
doc feature flags in futures 2020-04-04 02:25:40 +01:00
Rob Ede
5198f8e3e4
document wgpu feature flags 2020-04-04 02:14:02 +01:00
Héctor Ramón
fd064ff990
Merge pull request #253 from hecrj/0.1
Release `0.1` - Custom styling, event subscriptions, additional widgets, new examples, and more!
2020-04-02 18:47:15 +02:00
Héctor Ramón Jiménez
36bdc0be1a Remove redundant scroll_to in Scrollable 2020-03-19 12:23:31 +01:00
Héctor Ramón Jiménez
d3572e1b81 Turn Touch into a struct and add finger id 2020-03-19 12:17:16 +01:00
Sebastian Imlay
e19a07d400 Added initial touch events to support iOS 2020-03-18 11:26:53 -07:00
415 changed files with 21123 additions and 7388 deletions

View File

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

View File

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

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
/target
target/
pkg/
**/*.rs.bk
Cargo.lock

View File

@ -6,6 +6,154 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.3.0] - 2021-03-31
### Added
- Touch support. [#57] [#650] (thanks to @simlay and @discordance!)
- Clipboard write access for
- `TextInput` widget. [#770]
- `Application::update`. [#773]
- `image::Viewer` widget. It allows panning and scaling of an image. [#319] (thanks to @tarkah!)
- `Tooltip` widget. It annotates content with some text on mouse hover. [#465] (thanks to @yusdacra!)
- Support for the [`smol`] async runtime. [#699] (thanks to @JayceFayne!)
- Support for graceful exiting when using the `Application` trait. [#804]
- Image format features in [`iced_wgpu`] to reduce code bloat. [#392] (thanks to @unrelentingtech!)
- `Focused` and `Unfocused` variant to `window::Event`. [#701] (thanks to @cossonleo!)
- `WGPU_BACKEND` environment variable to configure the internal graphics backend of `iced_wgpu`. [#789] (thanks to @Cupnfish!)
### Changed
- The `TitleBar` of a `PaneGrid` now supports generic elements. [#657] (thanks to @clarkmoody!)
- The `Error` type now implements `Send` and `Sync`. [#719] (thanks to @taiki-e!)
- The `Style` types in `iced_style` now implement `Clone` and `Copy`. [#720] (thanks to @taiki-e!)
- The following dependencies have been updated:
- [`font-kit`] → `0.10` [#669]
- [`glutin`] → `0.26` [#658]
- [`resvg`] → `0.12` [#669]
- [`tokio`] → `1.0` [#672] (thanks to @yusdacra!)
- [`winit`] → `0.24` [#658]
- [`wgpu`] → `0.7` [#725] (thanks to @PolyMeilex)
- The following examples were improved:
- `download_progress` now showcases multiple file downloads at once. [#283] (thanks to @Folyd!)
- `solar_system` uses the new `rand` API. [#760] (thanks to @TriedAngle!)
### Fixed
- Button events not being propagated to contents. [#668]
- Incorrect overlay implementation for the `Button` widget. [#764]
- `Viewport::physical_width` returning the wrong value. [#700]
- Outdated documentation for the `Sandbox` trait. [#710]
[#57]: https://github.com/hecrj/iced/pull/57
[#283]: https://github.com/hecrj/iced/pull/283
[#319]: https://github.com/hecrj/iced/pull/319
[#392]: https://github.com/hecrj/iced/pull/392
[#465]: https://github.com/hecrj/iced/pull/465
[#650]: https://github.com/hecrj/iced/pull/650
[#657]: https://github.com/hecrj/iced/pull/657
[#658]: https://github.com/hecrj/iced/pull/658
[#668]: https://github.com/hecrj/iced/pull/668
[#669]: https://github.com/hecrj/iced/pull/669
[#672]: https://github.com/hecrj/iced/pull/672
[#699]: https://github.com/hecrj/iced/pull/699
[#700]: https://github.com/hecrj/iced/pull/700
[#701]: https://github.com/hecrj/iced/pull/701
[#710]: https://github.com/hecrj/iced/pull/710
[#719]: https://github.com/hecrj/iced/pull/719
[#720]: https://github.com/hecrj/iced/pull/720
[#725]: https://github.com/hecrj/iced/pull/725
[#760]: https://github.com/hecrj/iced/pull/760
[#764]: https://github.com/hecrj/iced/pull/764
[#770]: https://github.com/hecrj/iced/pull/770
[#773]: https://github.com/hecrj/iced/pull/773
[#789]: https://github.com/hecrj/iced/pull/789
[#804]: https://github.com/hecrj/iced/pull/804
[`smol`]: https://github.com/smol-rs/smol
[`winit`]: https://github.com/rust-windowing/winit
[`glutin`]: https://github.com/rust-windowing/glutin
[`font-kit`]: https://github.com/servo/font-kit
## [0.2.0] - 2020-11-26
### Added
- __[`Canvas` interactivity][canvas]__ (#325)
A trait-based approach to react to mouse and keyboard interactions in [the `Canvas` widget][#193].
- __[`iced_graphics` subcrate][opengl]__ (#354)
A backend-agnostic graphics subcrate that can be leveraged to build new renderers.
- __[OpenGL renderer][opengl]__ (#354)
An OpenGL renderer powered by [`iced_graphics`], [`glow`], and [`glutin`]. It is an alternative to the default [`wgpu`] renderer.
- __[Overlay support][pick_list]__ (#444)
Basic support for superpositioning interactive widgets on top of other widgets.
- __[Faster event loop][view]__ (#597)
The event loop now takes advantage of the data dependencies in [The Elm Architecture] and leverages the borrow checker to keep the widget tree alive between iterations, avoiding unnecessary rebuilds.
- __[Event capturing][event]__ (#614)
The runtime now can tell whether a widget has handled an event or not, easing [integration with existing applications].
- __[`PickList` widget][pick_list]__ (#444)
A drop-down selector widget built on top of the new overlay support.
- __[`QRCode` widget][qr_code]__ (#622)
A widget that displays a QR code, powered by [the `qrcode` crate].
[canvas]: https://github.com/hecrj/iced/pull/325
[opengl]: https://github.com/hecrj/iced/pull/354
[`iced_graphics`]: https://github.com/hecrj/iced/pull/354
[pane_grid]: https://github.com/hecrj/iced/pull/397
[pick_list]: https://github.com/hecrj/iced/pull/444
[error]: https://github.com/hecrj/iced/pull/514
[view]: https://github.com/hecrj/iced/pull/597
[event]: https://github.com/hecrj/iced/pull/614
[color]: https://github.com/hecrj/iced/pull/200
[qr_code]: https://github.com/hecrj/iced/pull/622
[#193]: https://github.com/hecrj/iced/pull/193
[`glutin`]: https://github.com/rust-windowing/glutin
[`wgpu`]: https://github.com/gfx-rs/wgpu-rs
[`glow`]: https://github.com/grovesNL/glow
[the `qrcode` crate]: https://docs.rs/qrcode/0.12.0/qrcode/
[integration with existing applications]: https://github.com/hecrj/iced/pull/183
[The Elm Architecture]: https://guide.elm-lang.org/architecture/
## [0.1.1] - 2020-04-15
### Added
- `Settings::with_flags` to easily initialize some default settings with flags. [#266]
- `Default` implementation for `canvas::layer::Cache`. [#267]
- `Ctrl + Del` support for `TextInput`. [#268]
- Helper methods in `canvas::Path` to easily draw lines, rectangles, and circles. [#293]
- `From<Color>` implementation for `canvas::Fill`. [#293]
- `From<String>` implementation for `canvas::Text`. [#293]
- `From<&str>` implementation for `canvas::Text`. [#293]
### Changed
- `new` method of `Radio` and `Checkbox` now take a generic `Into<String>` for the label. [#260]
- `Frame::fill` now takes a generic `Into<canvas::Fill>`. [#293]
- `Frame::stroke` now takes a generic `Into<canvas::Stroke>`. [#293]
- `Frame::fill_text` now takes a generic `Into<canvas::Text>`. [#293]
### Fixed
- Feature flags not being referenced in documentation. [#259]
- Crash in some graphics drivers when displaying an empty `Canvas`. [#278]
- Text measuring when spaces where present at the beginning of a `TextInput` value. [#279]
- `TextInput` producing a `Clip` primitive when unnecessary. [#279]
- Alignment of `Text` primitive in `iced_wgpu`. [#281]
- `CursorEntered` and `CursorLeft` not being generated. [#289]
### Removed
- Unnecessary `'static` lifetimes in `Renderer` bounds. [#290]
[#259]: https://github.com/hecrj/iced/pull/259
[#260]: https://github.com/hecrj/iced/pull/260
[#266]: https://github.com/hecrj/iced/pull/266
[#267]: https://github.com/hecrj/iced/pull/267
[#268]: https://github.com/hecrj/iced/pull/268
[#278]: https://github.com/hecrj/iced/pull/278
[#279]: https://github.com/hecrj/iced/pull/279
[#281]: https://github.com/hecrj/iced/pull/281
[#289]: https://github.com/hecrj/iced/pull/289
[#290]: https://github.com/hecrj/iced/pull/290
[#293]: https://github.com/hecrj/iced/pull/293
## [0.1.0] - 2020-04-02
### Added
@ -59,7 +207,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[`wasm-bindgen-futures`]: https://github.com/rustwasm/wasm-bindgen/tree/master/crates/futures
[`resvg`]: https://github.com/RazrFalcon/resvg
[`raqote`]: https://github.com/jrmuizel/raqote
[`iced_wgpu`]: https://github.com/hecrj/iced/tree/0.1/wgpu
[`iced_wgpu`]: https://github.com/hecrj/iced/tree/master/wgpu
## [0.1.0-beta] - 2019-11-25
@ -71,7 +219,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- First release! :tada:
[Unreleased]: https://github.com/hecrj/iced/compare/0.1.0...HEAD
[Unreleased]: https://github.com/hecrj/iced/compare/0.3.0...HEAD
[0.3.0]: https://github.com/hecrj/iced/compare/0.2.0...0.3.0
[0.2.0]: https://github.com/hecrj/iced/compare/0.1.1...0.2.0
[0.1.1]: https://github.com/hecrj/iced/compare/0.1.0...0.1.1
[0.1.0]: https://github.com/hecrj/iced/compare/0.1.0-beta...0.1.0
[0.1.0-beta]: https://github.com/hecrj/iced/compare/0.1.0-alpha...0.1.0-beta
[0.1.0-alpha]: https://github.com/hecrj/iced/releases/tag/0.1.0-alpha

View File

@ -1,6 +1,6 @@
[package]
name = "iced"
version = "0.1.0"
version = "0.3.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "A cross-platform GUI library inspired by Elm"
@ -12,18 +12,39 @@ keywords = ["gui", "ui", "graphics", "interface", "widgets"]
categories = ["gui"]
[features]
default = ["wgpu", "default_system_font"]
# Enables the `iced_wgpu` renderer
wgpu = ["iced_wgpu"]
# Enables the `Image` widget
image = ["iced_wgpu/image"]
# Enables the `Svg` widget
svg = ["iced_wgpu/svg"]
# Enables the `Canvas` widget
canvas = ["iced_wgpu/canvas"]
# Enables the `QRCode` widget
qr_code = ["iced_wgpu/qr_code"]
# Enables using system fonts
default_system_font = ["iced_wgpu/default_system_font"]
# Enables the `iced_glow` renderer. Overrides `iced_wgpu`
glow = ["iced_glow", "iced_glutin"]
# Enables the `Canvas` widget for `iced_glow`
glow_canvas = ["iced_glow/canvas"]
# Enables the `QRCode` widget for `iced_glow`
glow_qr_code = ["iced_glow/qr_code"]
# Enables using system fonts for `iced_glow`
glow_default_system_font = ["iced_glow/default_system_font"]
# Enables a debug view in native platforms (press F12)
debug = ["iced_winit/debug"]
# Enables `tokio` as the `executor::Default` on native platforms
tokio = ["iced_futures/tokio"]
# Enables old `tokio` (0.2) as the `executor::Default` on native platforms
tokio_old = ["iced_futures/tokio_old"]
# Enables `async-std` as the `executor::Default` on native platforms
async-std = ["iced_futures/async-std"]
# Enables `smol` as the `executor::Default` on native platforms
smol = ["iced_futures/smol"]
# Enables advanced color conversion via `palette`
palette = ["iced_core/palette"]
[badges]
maintenance = { status = "actively-developed" }
@ -32,6 +53,9 @@ maintenance = { status = "actively-developed" }
members = [
"core",
"futures",
"graphics",
"glow",
"glutin",
"native",
"style",
"web",
@ -39,29 +63,45 @@ members = [
"winit",
"examples/bezier_tool",
"examples/clock",
"examples/color_palette",
"examples/counter",
"examples/custom_widget",
"examples/download_progress",
"examples/events",
"examples/game_of_life",
"examples/geometry",
"examples/integration",
"examples/pane_grid",
"examples/pick_list",
"examples/pokedex",
"examples/progress_bar",
"examples/qr_code",
"examples/scrollable",
"examples/solar_system",
"examples/stopwatch",
"examples/styling",
"examples/svg",
"examples/todos",
"examples/tour",
"examples/tour_glow",
"examples/tooltip",
"examples/url_handler",
]
[dependencies]
iced_futures = { version = "0.1", path = "futures" }
iced_core = { version = "0.4", path = "core" }
iced_futures = { version = "0.3", path = "futures" }
thiserror = "1.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
iced_winit = { version = "0.1", path = "winit" }
iced_wgpu = { version = "0.2", path = "wgpu" }
iced_winit = { version = "0.3", path = "winit" }
iced_glutin = { version = "0.2", path = "glutin", optional = true }
iced_wgpu = { version = "0.4", path = "wgpu", optional = true }
iced_glow = { version = "0.2", path = "glow", optional = true}
[target.'cfg(target_arch = "wasm32")'.dependencies]
iced_web = { version = "0.2", path = "web" }
iced_web = { version = "0.4", path = "web" }
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
features = ["image", "svg", "canvas", "qr_code"]

View File

@ -1,10 +1,7 @@
# Ecosystem
This document describes the Iced ecosystem.
It quickly lists the different audiences of the library and explains how the different crates relate to each other.
## Users
This document describes the Iced ecosystem and explains how the different crates relate to each other.
## Overview
Iced is meant to be used by 2 different types of users:
- __End-users__. They should be able to:
@ -18,71 +15,81 @@ Iced is meant to be used by 2 different types of users:
- integrate existing runtimes in their own system (like game engines),
- and create their own custom renderers.
## Crates
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.
![Ecosystem graph](docs/graphs/ecosystem.png)
<p align="center">
<img alt="The Iced Ecosystem" src="docs/graphs/ecosystem.png" width="60%">
</p>
### [`iced_core`]
[`iced_core`] holds basic reusable types of the public API. For instance, basic data types like `Point`, `Rectangle`, `Length`, etc.
## The foundations
There are a bunch of concepts that permeate the whole ecosystem. These concepts are considered __the foundations__, and they are provided by three different crates:
This crate is meant to be a starting point for an Iced runtime.
- [`iced_core`] contains many lightweight, reusable primitives (e.g. `Point`, `Rectangle`, `Color`).
- [`iced_futures`] implements the concurrent concepts of [The Elm Architecture] on top of the [`futures`] ecosystem.
- [`iced_style`] defines the default styling capabilities of built-in widgets.
### [`iced_native`]
[`iced_native`] takes [`iced_core`] and builds a native runtime on top of it, featuring:
- A custom layout engine, greatly inspired by [`druid`]
- Event handling for all the built-in widgets
- A renderer-agnostic API
<p align="center">
<img alt="The foundations" src="docs/graphs/foundations.png" width="50%">
</p>
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 `Backend` trait, leveraging [`raw-window-handle`], which can be implemented by graphical renderers that target _windows_. Window-based shells (like [`iced_winit`]) can use this trait to stay renderer-agnostic.
## The native target
The native side of the ecosystem is split into two different groups: __renderers__ and __shells__.
[`druid`]: https://github.com/xi-editor/druid
[`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle
<p align="center">
<img alt="The native target" src="docs/graphs/native.png" width="80%">
</p>
### [`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.
### Renderers
The widgets of a _graphical_ user interface produce some primitives that eventually need to be drawn on screen. __Renderers__ take care of this task, potentially leveraging GPU acceleration.
The crate is currently a simple abstraction layer over [`dodrio`].
Currently, there are two different official renderers:
[`dodrio`]: https://github.com/fitzgen/dodrio
- [`iced_wgpu`] is powered by [`wgpu`] and supports Vulkan, DirectX 12, and Metal.
- [`iced_glow`] is powered by [`glow`] and supports OpenGL 3.3+.
### [`iced_wgpu`]
[`iced_wgpu`] is a [`wgpu`] renderer for [`iced_native`]. For now, it is the default renderer of Iced in native platforms.
Additionally, the [`iced_graphics`] subcrate contains a bunch of backend-agnostic types that can be leveraged to build renderers. Both of the renderers rely on the graphical foundations provided by this crate.
[`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].
### Shells
The widgets of a graphical user _interface_ are interactive. __Shells__ gather and process user interactions in an event loop.
Currently, [`iced_wgpu`] supports the following primitives:
- Text, which is rendered using [`wgpu_glyph`]. No shaping at all.
- Quads or rectangles, with rounded borders and a solid background color.
- Clip areas, useful to implement scrollables or hide overflowing content.
- Images and SVG, loaded from memory or the file system.
- Meshes of triangles, useful to draw geometry freely.
Normally, a shell will be responsible of creating a window and managing the lifecycle of a user interface, implementing a runtime of [The Elm Architecture].
[`wgpu`]: https://github.com/gfx-rs/wgpu-rs
[WebGPU API]: https://gpuweb.github.io/gpuweb/
[`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph
As of now, there are two official shells:
### [`iced_winit`]
[`iced_winit`] offers some convenient abstractions on top of [`iced_native`] to quickstart development when using [`winit`].
- [`iced_winit`] implements a shell runtime on top of [`winit`].
- [`iced_glutin`] is similar to [`iced_winit`], but it also deals with [OpenGL context creation].
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.
## The web target
The Web platform provides all the abstractions necessary to draw widgets and gather users interactions.
[`winit`]: https://github.com/rust-windowing/winit
Therefore, unlike the native path, the web side of the ecosystem does not need to split renderers and shells. Instead, [`iced_web`] leverages [`dodrio`] to both render widgets and implement a proper runtime.
### [`iced`]
## Iced
Finally, [`iced`] unifies everything into a simple abstraction to create cross-platform applications:
- On native, it uses [`iced_winit`] and [`iced_wgpu`].
- On native, it uses __[shells](#shells)__ and __[renderers](#renderers)__.
- On the web, it uses [`iced_web`].
This is the crate meant to be used by __end-users__.
<p align="center">
<img alt="Iced" src="docs/graphs/iced.png" width="80%">
</p>
[`iced_core`]: core
[`iced_futures`]: futures
[`iced_style`]: style
[`iced_native`]: native
[`iced_web`]: web
[`iced_graphics`]: graphics
[`iced_wgpu`]: wgpu
[`iced_glow`]: glow
[`iced_winit`]: winit
[`iced_glutin`]: glutin
[`iced`]: ..
[`futures`]: https://github.com/rust-lang/futures-rs
[`glow`]: https://github.com/grovesNL/glow
[`wgpu`]: https://github.com/gfx-rs/wgpu-rs
[`winit`]: https://github.com/rust-windowing/winit
[`glutin`]: https://github.com/rust-windowing/glutin
[`dodrio`]: https://github.com/fitzgen/dodrio
[OpenGL context creation]: https://www.khronos.org/opengl/wiki/Creating_an_OpenGL_Context
[The Elm Architecture]: https://guide.elm-lang.org/architecture/

View File

@ -55,7 +55,7 @@ __Iced is currently experimental software.__ [Take a look at the roadmap],
Add `iced` as a dependency in your `Cargo.toml`:
```toml
iced = "0.1"
iced = "0.3"
```
__Iced moves fast and the `master` branch can contain breaking changes!__ If
@ -168,26 +168,19 @@ Browse the [documentation] and the [examples] to learn more!
Iced was originally born as an attempt at bringing the simplicity of [Elm] and
[The Elm Architecture] into [Coffee], a 2D game engine I am working on.
The core of the library was implemented during May in [this pull request].
The core of the library was implemented during May 2019 in [this pull request].
[The first alpha version] was eventually released as
[a renderer-agnostic GUI library]. The library did not provide a renderer and
implemented the current [tour example] on top of [`ggez`], a game library.
Since then, the focus has shifted towards providing a batteries-included,
end-user-oriented GUI library, while keeping [the ecosystem] modular.
end-user-oriented GUI library, while keeping [the ecosystem] modular:
Currently, Iced is a cross-platform GUI library built on top of smaller crates:
- [`iced_core`], a bunch of basic types that can be reused in different runtimes.
- [`iced_native`], a renderer-agnostic native runtime implementing widget
logic and a layout engine inspired by [`druid`].
- [`iced_web`], an experimental web runtime that targets the DOM thanks to
[`dodrio`].
- [`iced_wgpu`], a renderer leveraging [`wgpu`], [`wgpu_glyph`], and
[`font-kit`].
- [`iced_winit`], a windowing shell on top of [`winit`].
[![Iced ecosystem](docs/graphs/ecosystem.png)](https://github.com/hecrj/iced/blob/master/ECOSYSTEM.md)
<p align="center">
<a href="https://github.com/hecrj/iced/blob/master/ECOSYSTEM.md">
<img alt="Iced Ecosystem" src="docs/graphs/ecosystem.png" width="80%">
</a>
</p>
[this pull request]: https://github.com/hecrj/coffee/pull/35
[The first alpha version]: https://github.com/hecrj/iced/tree/0.1.0-alpha
@ -195,15 +188,6 @@ Currently, Iced is a cross-platform GUI library built on top of smaller crates:
[tour example]: https://github.com/hecrj/iced/blob/master/examples/README.md#tour
[`ggez`]: https://github.com/ggez/ggez
[the ecosystem]: https://github.com/hecrj/iced/blob/master/ECOSYSTEM.md
[`iced_core`]: https://github.com/hecrj/iced/tree/master/core
[`iced_native`]: https://github.com/hecrj/iced/tree/master/native
[`iced_web`]: https://github.com/hecrj/iced/tree/master/web
[`iced_wgpu`]: https://github.com/hecrj/iced/tree/master/wgpu
[`iced_winit`]: https://github.com/hecrj/iced/tree/master/winit
[`druid`]: https://github.com/xi-editor/druid
[`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph
[`font-kit`]: https://github.com/servo/font-kit
[`winit`]: https://github.com/rust-windowing/winit
## Contributing / Feedback
Contributions are greatly appreciated! If you want to contribute, please

View File

@ -6,17 +6,19 @@ Before diving into the roadmap, check out [the ecosystem overview] to get an ide
[the ecosystem overview]: ECOSYSTEM.md
## Next steps
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.
Most of the work related to these features needs to happen in the __native__ path of the ecosystem, as the web already supports many of them.
Once a step is completed, it is collapsed and added to this list:
* [x] Scrollables / Clippables ([#24])
* [x] Text input widget ([#25])
* [x] TodoMVC example ([#26])
* [x] Async actions ([#27])
* [x] Async actions ([#28])
* [x] Custom layout engine ([#52])
* [x] Event subscriptions ([#122])
* [x] Custom styling ([#146])
* [x] Canvas for 2D graphics ([#193])
* [x] Basic overlay support ([#444])
[#24]: https://github.com/hecrj/iced/issues/24
[#25]: https://github.com/hecrj/iced/issues/25
@ -25,6 +27,8 @@ Once a step is completed, it is collapsed and added to this list:
[#52]: https://github.com/hecrj/iced/pull/52
[#122]: https://github.com/hecrj/iced/pull/122
[#146]: https://github.com/hecrj/iced/pull/146
[#193]: https://github.com/hecrj/iced/pull/193
[#444]: https://github.com/hecrj/iced/pull/444
### Multi-window support ([#27])
Open and control multiple windows at runtime.
@ -35,17 +39,6 @@ This approach should also allow us to perform custom optimizations for this part
[#27]: https://github.com/hecrj/iced/issues/27
### 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.
`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.
[#30]: https://github.com/hecrj/iced/issues/30
### Animations ([#31])
Allow widgets to request a redraw at a specific time.
@ -55,8 +48,8 @@ This is a necessary feature to render loading spinners, a blinking text cursor,
[#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.
### Canvas widget for 3D graphics ([#32])
A widget to draw freely in 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.

View File

@ -1,6 +1,6 @@
[package]
name = "iced_core"
version = "0.2.0"
version = "0.4.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
description = "The essential concepts of Iced"
@ -8,3 +8,7 @@ license = "MIT"
repository = "https://github.com/hecrj/iced"
[dependencies]
[dependencies.palette]
version = "0.5.0"
optional = true

View File

@ -8,7 +8,9 @@
This crate is meant to be a starting point for an Iced runtime.
![iced_core](../docs/graphs/core.png)
<p align="center">
<img alt="The foundations" src="../docs/graphs/foundations.png" width="50%">
</p>
[documentation]: https://docs.rs/iced_core
@ -16,7 +18,7 @@ This crate is meant to be a starting point for an Iced runtime.
Add `iced_core` as a dependency in your `Cargo.toml`:
```toml
iced_core = "0.2"
iced_core = "0.4"
```
__Iced moves fast and the `master` branch can contain breaking changes!__ If

View File

@ -13,3 +13,9 @@ impl From<Color> for Background {
Background::Color(color)
}
}
impl From<Color> for Option<Background> {
fn from(color: Color) -> Self {
Some(Background::from(color))
}
}

View File

@ -1,10 +1,16 @@
#[cfg(feature = "palette")]
use palette::rgb::{Srgb, Srgba};
/// A color in the sRGB color space.
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Color {
/// Red component, 0.0 - 1.0
pub r: f32,
/// Green component, 0.0 - 1.0
pub g: f32,
/// Blue component, 0.0 - 1.0
pub b: f32,
/// Transparency, 0.0 - 1.0
pub a: f32,
}
@ -33,23 +39,47 @@ impl Color {
a: 0.0,
};
/// Creates a [`Color`] from its RGB components.
/// Creates a new [`Color`].
///
/// [`Color`]: struct.Color.html
/// In debug mode, it will panic if the values are not in the correct
/// range: 0.0 - 1.0
pub fn new(r: f32, g: f32, b: f32, a: f32) -> Color {
debug_assert!(
(0.0..=1.0).contains(&r),
"Red component must be on [0, 1]"
);
debug_assert!(
(0.0..=1.0).contains(&g),
"Green component must be on [0, 1]"
);
debug_assert!(
(0.0..=1.0).contains(&b),
"Blue component must be on [0, 1]"
);
debug_assert!(
(0.0..=1.0).contains(&a),
"Alpha component must be on [0, 1]"
);
Color { r, g, b, a }
}
/// Creates a [`Color`] from its RGB components.
pub const fn from_rgb(r: f32, g: f32, b: f32) -> Color {
Color { r, g, b, a: 1.0 }
Color::from_rgba(r, g, b, 1.0f32)
}
/// Creates a [`Color`] from its RGBA components.
pub const fn from_rgba(r: f32, g: f32, b: f32, a: f32) -> Color {
Color { r, g, b, a }
}
/// Creates a [`Color`] from its RGB8 components.
///
/// [`Color`]: struct.Color.html
pub fn from_rgb8(r: u8, g: u8, b: u8) -> Color {
Color::from_rgba8(r, g, b, 1.0)
}
/// Creates a [`Color`] from its RGB8 components and an alpha value.
///
/// [`Color`]: struct.Color.html
pub fn from_rgba8(r: u8, g: u8, b: u8, a: f32) -> Color {
Color {
r: f32::from(r) / 255.0,
@ -60,8 +90,6 @@ impl Color {
}
/// Converts the [`Color`] into its linear values.
///
/// [`Color`]: struct.Color.html
pub fn into_linear(self) -> [f32; 4] {
// As described in:
// https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation
@ -80,16 +108,101 @@ impl Color {
self.a,
]
}
/// Inverts the [`Color`] in-place.
pub fn invert(&mut self) {
self.r = 1.0f32 - self.r;
self.b = 1.0f32 - self.g;
self.g = 1.0f32 - self.b;
}
/// Returns the inverted [`Color`].
pub fn inverse(self) -> Color {
Color::new(1.0f32 - self.r, 1.0f32 - self.g, 1.0f32 - self.b, self.a)
}
}
impl From<[f32; 3]> for Color {
fn from([r, g, b]: [f32; 3]) -> Self {
Color { r, g, b, a: 1.0 }
Color::new(r, g, b, 1.0)
}
}
impl From<[f32; 4]> for Color {
fn from([r, g, b, a]: [f32; 4]) -> Self {
Color { r, g, b, a }
Color::new(r, g, b, a)
}
}
#[cfg(feature = "palette")]
/// Converts from palette's `Srgba` type to a [`Color`].
impl From<Srgba> for Color {
fn from(srgba: Srgba) -> Self {
Color::new(srgba.red, srgba.green, srgba.blue, srgba.alpha)
}
}
#[cfg(feature = "palette")]
/// Converts from [`Color`] to palette's `Srgba` type.
impl From<Color> for Srgba {
fn from(c: Color) -> Self {
Srgba::new(c.r, c.g, c.b, c.a)
}
}
#[cfg(feature = "palette")]
/// Converts from palette's `Srgb` type to a [`Color`].
impl From<Srgb> for Color {
fn from(srgb: Srgb) -> Self {
Color::new(srgb.red, srgb.green, srgb.blue, 1.0)
}
}
#[cfg(feature = "palette")]
/// Converts from [`Color`] to palette's `Srgb` type.
impl From<Color> for Srgb {
fn from(c: Color) -> Self {
Srgb::new(c.r, c.g, c.b)
}
}
#[cfg(feature = "palette")]
#[cfg(test)]
mod tests {
use super::*;
use palette::Blend;
#[test]
fn srgba_traits() {
let c = Color::from_rgb(0.5, 0.4, 0.3);
// Round-trip conversion to the palette:Srgba type
let s: Srgba = c.into();
let r: Color = s.into();
assert_eq!(c, r);
}
#[test]
fn color_manipulation() {
let c1 = Color::from_rgb(0.5, 0.4, 0.3);
let c2 = Color::from_rgb(0.2, 0.5, 0.3);
// Convert to linear color for manipulation
let l1 = Srgba::from(c1).into_linear();
let l2 = Srgba::from(c2).into_linear();
// Take the lighter of each of the RGB components
let lighter = l1.lighten(l2);
// Convert back to our Color
let r: Color = Srgba::from_linear(lighter).into();
assert_eq!(
r,
Color {
r: 0.5,
g: 0.5,
b: 0.3,
a: 1.0
}
);
}
}

View File

@ -16,3 +16,9 @@ pub enum Font {
bytes: &'static [u8],
},
}
impl Default for Font {
fn default() -> Font {
Font::Default
}
}

View File

@ -1,6 +1,8 @@
//! Reuse basic keyboard types.
mod event;
mod key_code;
mod modifiers_state;
mod modifiers;
pub use event::Event;
pub use key_code::KeyCode;
pub use modifiers_state::ModifiersState;
pub use modifiers::Modifiers;

View File

@ -1,5 +1,4 @@
use super::{KeyCode, ModifiersState};
use crate::input::ButtonState;
use super::{KeyCode, Modifiers};
/// A keyboard event.
///
@ -9,18 +8,27 @@ use crate::input::ButtonState;
/// [open an issue]: https://github.com/hecrj/iced/issues
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Event {
/// A keyboard key was pressed or released.
Input {
/// The state of the key
state: ButtonState,
/// A keyboard key was pressed.
KeyPressed {
/// The key identifier
key_code: KeyCode,
/// The state of the modifier keys
modifiers: ModifiersState,
modifiers: Modifiers,
},
/// A keyboard key was released.
KeyReleased {
/// The key identifier
key_code: KeyCode,
/// The state of the modifier keys
modifiers: Modifiers,
},
/// A unicode character was received.
CharacterReceived(char),
/// The keyboard modifiers have changed.
ModifiersChanged(Modifiers),
}

View File

@ -55,7 +55,7 @@ pub enum KeyCode {
Y,
Z,
/// The Escape key, next to F1
/// The Escape key, next to F1.
Escape,
F1,
@ -83,14 +83,14 @@ pub enum KeyCode {
F23,
F24,
/// Print Screen/SysRq
/// Print Screen/SysRq.
Snapshot,
/// Scroll Lock
/// Scroll Lock.
Scroll,
/// Pause/Break key, next to Scroll lock
/// Pause/Break key, next to Scroll lock.
Pause,
/// `Insert`, next to Backspace
/// `Insert`, next to Backspace.
Insert,
Home,
Delete,
@ -103,11 +103,14 @@ pub enum KeyCode {
Right,
Down,
/// The Backspace key, right over Enter.
Backspace,
/// The Enter key.
Enter,
/// The space bar.
Space,
/// The "Compose" key on Linux
/// The "Compose" key on Linux.
Compose,
Caret,
@ -123,12 +126,20 @@ pub enum KeyCode {
Numpad7,
Numpad8,
Numpad9,
NumpadAdd,
NumpadDivide,
NumpadDecimal,
NumpadComma,
NumpadEnter,
NumpadEquals,
NumpadMultiply,
NumpadSubtract,
AbntC1,
AbntC2,
Add,
Apostrophe,
Apps,
Asterisk,
At,
Ax,
Backslash,
@ -137,8 +148,6 @@ pub enum KeyCode {
Colon,
Comma,
Convert,
Decimal,
Divide,
Equals,
Grave,
Kana,
@ -152,19 +161,16 @@ pub enum KeyCode {
MediaSelect,
MediaStop,
Minus,
Multiply,
Mute,
MyComputer,
NavigateForward, // also called "Prior"
NavigateBackward, // also called "Next"
NavigateForward, // also called "Next"
NavigateBackward, // also called "Prior"
NextTrack,
NoConvert,
NumpadComma,
NumpadEnter,
NumpadEquals,
OEM102,
Period,
PlayPause,
Plus,
Power,
PrevTrack,
RAlt,
@ -176,7 +182,6 @@ pub enum KeyCode {
Slash,
Sleep,
Stop,
Subtract,
Sysrq,
Tab,
Underline,

View File

@ -0,0 +1,45 @@
/// The current state of the keyboard modifiers.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Modifiers {
/// Whether a shift key is pressed
pub shift: bool,
/// Whether a control key is pressed
pub control: bool,
/// Whether an alt key is pressed
pub alt: bool,
/// Whether a logo key is pressed (e.g. windows key, command key...)
pub logo: bool,
}
impl Modifiers {
/// Returns true if a "command key" is pressed in the [`Modifiers`].
///
/// The "command key" is the main modifier key used to issue commands in the
/// current platform. Specifically:
///
/// - It is the `logo` or command key (⌘) on macOS
/// - It is the `control` key on other platforms
pub fn is_command_pressed(self) -> bool {
#[cfg(target_os = "macos")]
let is_pressed = self.logo;
#[cfg(not(target_os = "macos"))]
let is_pressed = self.control;
is_pressed
}
/// Returns true if the current [`Modifiers`] have at least the same
/// keys pressed as the provided ones, and false otherwise.
pub fn matches(&self, modifiers: Self) -> bool {
let shift = !modifiers.shift || self.shift;
let control = !modifiers.control || self.control;
let alt = !modifiers.alt || self.alt;
let logo = !modifiers.logo || self.logo;
shift && control && alt && logo
}
}

View File

@ -1,30 +0,0 @@
/// The current state of the keyboard modifiers.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct ModifiersState {
/// Whether a shift key is pressed
pub shift: bool,
/// Whether a control key is pressed
pub control: bool,
/// Whether an alt key is pressed
pub alt: bool,
/// Whether a logo key is pressed (e.g. windows key, command key...)
pub logo: bool,
}
impl ModifiersState {
/// Returns true if the current [`ModifiersState`] has at least the same
/// modifiers enabled as the given value, and false otherwise.
///
/// [`ModifiersState`]: struct.ModifiersState.html
pub fn matches(&self, modifiers: ModifiersState) -> bool {
let shift = !modifiers.shift || self.shift;
let control = !modifiers.control || self.control;
let alt = !modifiers.alt || self.alt;
let logo = !modifiers.logo || self.logo;
shift && control && alt && logo
}
}

View File

@ -26,8 +26,6 @@ impl Length {
/// The _fill factor_ is a relative unit describing how much of the
/// remaining space should be filled when compared to other elements. It
/// is only meant to be used by layout engines.
///
/// [`Length`]: enum.Length.html
pub fn fill_factor(&self) -> u16 {
match self {
Length::Fill => 1,

View File

@ -1,11 +1,11 @@
//! The core library of [Iced].
//!
//! ![`iced_core` crate graph](https://github.com/hecrj/iced/blob/cae26cb7bc627f4a5b3bcf1cd023a0c552e8c65e/docs/graphs/core.png?raw=true)
//!
//! This library holds basic types that can be reused and re-exported in
//! different runtime implementations. For instance, both [`iced_native`] and
//! [`iced_web`] are built on top of `iced_core`.
//!
//! ![The foundations of the Iced ecosystem](https://github.com/hecrj/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/foundations.png?raw=true)
//!
//! [Iced]: https://github.com/hecrj/iced
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
//! [`iced_web`]: https://github.com/hecrj/iced/tree/master/web
@ -15,12 +15,14 @@
#![forbid(unsafe_code)]
#![forbid(rust_2018_idioms)]
pub mod keyboard;
pub mod mouse;
mod align;
mod background;
mod color;
mod font;
mod length;
mod padding;
mod point;
mod rectangle;
mod size;
@ -31,6 +33,7 @@ pub use background::Background;
pub use color::Color;
pub use font::Font;
pub use length::Length;
pub use padding::Padding;
pub use point::Point;
pub use rectangle::Rectangle;
pub use size::Size;

View File

@ -1,9 +1,8 @@
//! Build mouse events.
//! Reuse basic mouse types.
mod button;
mod event;
pub mod click;
mod interaction;
pub use button::Button;
pub use click::Click;
pub use event::{Event, ScrollDelta};
pub use interaction::Interaction;

View File

@ -1,5 +1,6 @@
use crate::Point;
use super::Button;
use crate::input::ButtonState;
/// A mouse event.
///
@ -17,21 +18,15 @@ pub enum Event {
/// The mouse cursor was moved
CursorMoved {
/// The X coordinate of the mouse position
x: f32,
/// The Y coordinate of the mouse position
y: f32,
/// The new position of the mouse cursor
position: Point,
},
/// A mouse button was pressed or released.
Input {
/// The state of the button
state: ButtonState,
/// A mouse button was pressed.
ButtonPressed(Button),
/// The button identifier
button: Button,
},
/// A mouse button was released.
ButtonReleased(Button),
/// The mouse wheel was scrolled.
WheelScrolled {

View File

@ -0,0 +1,20 @@
/// The interaction of a mouse cursor.
#[derive(Debug, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
#[allow(missing_docs)]
pub enum Interaction {
Idle,
Pointer,
Grab,
Text,
Crosshair,
Working,
Grabbing,
ResizingHorizontally,
ResizingVertically,
}
impl Default for Interaction {
fn default() -> Interaction {
Interaction::Idle
}
}

107
core/src/padding.rs Normal file
View File

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

View File

@ -1,7 +1,7 @@
use crate::Vector;
/// A 2D point.
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Point {
/// The X coordinate.
pub x: f32,
@ -12,20 +12,14 @@ pub struct Point {
impl Point {
/// The origin (i.e. a [`Point`] at (0, 0)).
///
/// [`Point`]: struct.Point.html
pub const ORIGIN: Point = Point::new(0.0, 0.0);
/// Creates a new [`Point`] with the given coordinates.
///
/// [`Point`]: struct.Point.html
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
/// Computes the distance to another [`Point`].
///
/// [`Point`]: struct.Point.html
pub fn distance(&self, to: Point) -> f32 {
let a = self.x - to.x;
let b = self.y - to.y;
@ -46,6 +40,12 @@ impl From<[u16; 2]> for Point {
}
}
impl From<Point> for [f32; 2] {
fn from(point: Point) -> [f32; 2] {
[point.x, point.y]
}
}
impl std::ops::Add<Vector> for Point {
type Output = Self;
@ -67,3 +67,11 @@ impl std::ops::Sub<Vector> for Point {
}
}
}
impl std::ops::Sub<Point> for Point {
type Output = Vector;
fn sub(self, point: Point) -> Vector {
Vector::new(self.x - point.x, self.y - point.y)
}
}

View File

@ -1,4 +1,4 @@
use crate::Point;
use crate::{Point, Size, Vector};
/// A rectangle.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
@ -17,10 +17,56 @@ pub struct Rectangle<T = f32> {
}
impl Rectangle<f32> {
/// Creates a new [`Rectangle`] with its top-left corner in the given
/// [`Point`] and with the provided [`Size`].
pub fn new(top_left: Point, size: Size) -> Self {
Self {
x: top_left.x,
y: top_left.y,
width: size.width,
height: size.height,
}
}
/// Creates a new [`Rectangle`] with its top-left corner at the origin
/// and with the provided [`Size`].
pub fn with_size(size: Size) -> Self {
Self {
x: 0.0,
y: 0.0,
width: size.width,
height: size.height,
}
}
/// Returns the [`Point`] at the center of the [`Rectangle`].
pub fn center(&self) -> Point {
Point::new(self.center_x(), self.center_y())
}
/// Returns the X coordinate of the [`Point`] at the center of the
/// [`Rectangle`].
pub fn center_x(&self) -> f32 {
self.x + self.width / 2.0
}
/// Returns the Y coordinate of the [`Point`] at the center of the
/// [`Rectangle`].
pub fn center_y(&self) -> f32 {
self.y + self.height / 2.0
}
/// Returns the position of the top left corner of the [`Rectangle`].
pub fn position(&self) -> Point {
Point::new(self.x, self.y)
}
/// Returns the [`Size`] of the [`Rectangle`].
pub fn size(&self) -> Size {
Size::new(self.width, self.height)
}
/// Returns true if the given [`Point`] is contained in the [`Rectangle`].
///
/// [`Point`]: struct.Point.html
/// [`Rectangle`]: struct.Rectangle.html
pub fn contains(&self, point: Point) -> bool {
self.x <= point.x
&& point.x <= self.x + self.width
@ -29,8 +75,6 @@ impl Rectangle<f32> {
}
/// Computes the intersection with the given [`Rectangle`].
///
/// [`Rectangle`]: struct.Rectangle.html
pub fn intersection(
&self,
other: &Rectangle<f32>,
@ -55,17 +99,27 @@ impl Rectangle<f32> {
None
}
}
/// Snaps the [`Rectangle`] to __unsigned__ integer coordinates.
pub fn snap(self) -> Rectangle<u32> {
Rectangle {
x: self.x as u32,
y: self.y as u32,
width: self.width as u32,
height: self.height as u32,
}
}
}
impl std::ops::Mul<f32> for Rectangle<u32> {
impl std::ops::Mul<f32> for Rectangle<f32> {
type Output = Self;
fn mul(self, scale: f32) -> Self {
Self {
x: (self.x as f32 * scale).round() as u32,
y: (self.y as f32 * scale).round() as u32,
width: (self.width as f32 * scale).round() as u32,
height: (self.height as f32 * scale).round() as u32,
x: self.x as f32 * scale,
y: self.y as f32 * scale,
width: self.width * scale,
height: self.height * scale,
}
}
}
@ -81,13 +135,17 @@ impl From<Rectangle<u32>> for Rectangle<f32> {
}
}
impl From<Rectangle<f32>> for Rectangle<u32> {
fn from(rectangle: Rectangle<f32>) -> Rectangle<u32> {
impl<T> std::ops::Add<Vector<T>> for Rectangle<T>
where
T: std::ops::Add<Output = T>,
{
type Output = Rectangle<T>;
fn add(self, translation: Vector<T>) -> Self {
Rectangle {
x: rectangle.x as u32,
y: rectangle.y as u32,
width: rectangle.width.ceil() as u32,
height: rectangle.height.ceil() as u32,
x: self.x + translation.x,
y: self.y + translation.y,
..self
}
}
}

View File

@ -1,39 +1,37 @@
use crate::{Padding, Vector};
use std::f32;
/// An amount of space in 2 dimensions.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Size {
pub struct Size<T = f32> {
/// The width.
pub width: f32,
pub width: T,
/// The height.
pub height: f32,
pub height: T,
}
impl<T> Size<T> {
/// Creates a new [`Size`] with the given width and height.
pub const fn new(width: T, height: T) -> Self {
Size { width, height }
}
}
impl Size {
/// A [`Size`] with zero width and height.
///
/// [`Size`]: struct.Size.html
pub const ZERO: Size = Size::new(0., 0.);
/// A [`Size`] with a width and height of 1 unit.
pub const UNIT: Size = Size::new(1., 1.);
/// A [`Size`] with infinite width and height.
///
/// [`Size`]: struct.Size.html
pub const INFINITY: Size = Size::new(f32::INFINITY, f32::INFINITY);
/// Creates a new [`Size`] with the given width and height.
///
/// [`Size`]: struct.Size.html
pub const fn new(width: f32, height: f32) -> Self {
Size { width, height }
}
/// Increments the [`Size`] to account for the given padding.
///
/// [`Size`]: struct.Size.html
pub fn pad(&self, padding: f32) -> Self {
pub fn pad(&self, padding: Padding) -> Self {
Size {
width: self.width + padding * 2.0,
height: self.height + padding * 2.0,
width: self.width + padding.horizontal() as f32,
height: self.height + padding.vertical() as f32,
}
}
}
@ -49,3 +47,24 @@ impl From<[u16; 2]> for Size {
Size::new(width.into(), height.into())
}
}
impl From<Vector<f32>> for Size {
fn from(vector: Vector<f32>) -> Self {
Size {
width: vector.x,
height: vector.y,
}
}
}
impl From<Size> for [f32; 2] {
fn from(size: Size) -> [f32; 2] {
[size.width, size.height]
}
}
impl From<Size> for Vector<f32> {
fn from(size: Size) -> Self {
Vector::new(size.width, size.height)
}
}

View File

@ -2,20 +2,14 @@
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vector<T = f32> {
/// The X component of the [`Vector`]
///
/// [`Vector`]: struct.Vector.html
pub x: T,
/// The Y component of the [`Vector`]
///
/// [`Vector`]: struct.Vector.html
pub y: T,
}
impl<T> Vector<T> {
/// Creates a new [`Vector`] with the given components.
///
/// [`Vector`]: struct.Vector.html
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
@ -43,6 +37,17 @@ where
}
}
impl<T> std::ops::Mul<T> for Vector<T>
where
T: std::ops::Mul<Output = T> + Copy,
{
type Output = Self;
fn mul(self, scale: T) -> Self {
Self::new(self.x * scale, self.y * scale)
}
}
impl<T> Default for Vector<T>
where
T: Default,
@ -54,3 +59,18 @@ where
}
}
}
impl<T> From<[T; 2]> for Vector<T> {
fn from([x, y]: [T; 2]) -> Self {
Self::new(x, y)
}
}
impl<T> From<Vector<T>> for [T; 2]
where
T: Copy,
{
fn from(other: Vector<T>) -> Self {
[other.x, other.y]
}
}

View File

@ -1,13 +0,0 @@
digraph G {
fontname = "Roboto";
newrank=true;
node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"];
edge[color="#333333"];
{ rank = same; iced_native iced_web }
iced_core -> iced_native [style=dashed];
iced_core -> iced_web [style=dashed];
iced_core [style=dashed];
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,56 +0,0 @@
digraph G {
fontname = "Roboto";
newrank=true;
node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"];
edge[color="#333333"];
subgraph cluster_1 {
label = "renderers ";
labelloc = "b";
labeljust = "r";
fontcolor = "#0366d6";
color="#f6f8fa";
bgcolor="#f6f8fa";
style=rounded;
etc_1 [label="...", style=solid, shape=none];
iced_wgpu;
}
subgraph cluster_2 {
label = "shells ";
labelloc = "b";
labeljust = "r";
fontcolor = "#0366d6";
color="#f6f8fa";
bgcolor="#f6f8fa";
style=rounded;
etc_2 [label="...", style=solid, shape=none];
iced_winit;
}
subgraph cluster_3 {
style=invis;
margin=20;
iced;
}
{ rank = same; iced_native iced_web }
{ rank = same; iced_wgpu iced_winit etc_1 etc_2 }
iced_core -> iced_native [style=dashed];
iced_core -> iced_web [style=dashed];
iced_native -> iced_wgpu;
iced_native -> iced_winit;
iced_winit -> iced;
iced_wgpu -> iced;
iced_web -> iced;
iced -> "cross-platform application";
iced_core [style=dashed];
"cross-platform application" [shape=box, width=2.8, height=0.6];
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 124 KiB

BIN
docs/graphs/foundations.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,6 +0,0 @@
#!/usr/bin/env bash
for file in *.dot
do
dot -Tpng ${file} -o ${file%.*}.png
done

View File

@ -1,46 +0,0 @@
digraph G {
fontname = "Roboto";
newrank=true;
node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"];
edge[color="#333333"];
subgraph cluster_1 {
label = "renderers ";
labelloc = "b";
labeljust = "r";
fontcolor = "#0366d6";
color="#f6f8fa";
bgcolor="#f6f8fa";
style=rounded;
etc_1 [label="...", style=solid, shape=none];
iced_wgpu;
}
subgraph cluster_2 {
label = "shells ";
labelloc = "b";
labeljust = "r";
fontcolor = "#0366d6";
color="#f6f8fa";
bgcolor="#f6f8fa";
style=rounded;
etc_2 [label="...", style=solid, shape=none];
iced_winit;
}
subgraph cluster_3 {
style=invis;
margin=20;
iced;
}
{ rank = same; iced_wgpu iced_winit etc_1 etc_2 }
iced_winit -> iced;
iced_wgpu -> iced;
iced_web -> iced;
iced;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File

@ -1,41 +0,0 @@
digraph G {
fontname = "Roboto";
newrank=true;
node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"];
edge[color="#333333"];
subgraph cluster_1 {
label = "renderers ";
labelloc = "b";
labeljust = "r";
fontcolor = "#0366d6";
color="#f6f8fa";
bgcolor="#f6f8fa";
style=rounded;
etc_1 [label="...", style=solid, shape=none];
iced_wgpu;
}
subgraph cluster_2 {
label = "shells ";
labelloc = "b";
labeljust = "r";
fontcolor = "#0366d6";
color="#f6f8fa";
bgcolor="#f6f8fa";
style=rounded;
etc_2 [label="...", style=solid, shape=none];
iced_winit;
}
{ rank = same; iced_wgpu iced_winit etc_1 etc_2 }
iced_core -> iced_native [style=dashed];
iced_native -> iced_wgpu;
iced_native -> iced_winit;
iced_core [style=dashed];
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -1,12 +0,0 @@
digraph G {
fontname = "Roboto";
newrank=true;
node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"];
edge[color="#333333"];
iced_core -> iced_web [style=dashed];
iced_web -> iced;
iced_core [style=dashed];
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,31 +0,0 @@
digraph G {
fontname = "Roboto";
newrank=true;
node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"];
edge[color="#333333"];
subgraph cluster_1 {
label = "renderers ";
labelloc = "b";
labeljust = "r";
fontcolor = "#0366d6";
color="#f6f8fa";
bgcolor="#f6f8fa";
style=rounded;
etc_1 [label="...", style=solid, shape=none];
iced_wgpu;
}
subgraph cluster_3 {
style=invis;
margin=20;
iced;
}
{ rank = same; iced_wgpu etc_1 }
iced_native -> iced_wgpu;
iced_wgpu -> iced;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,31 +0,0 @@
digraph G {
fontname = "Roboto";
newrank=true;
node[fontname = "Roboto", style="filled", fontcolor="#333333", fillcolor=white, color="#333333"];
edge[color="#333333"];
subgraph cluster_2 {
label = "shells ";
labelloc = "b";
labeljust = "r";
fontcolor = "#0366d6";
color="#f6f8fa";
bgcolor="#f6f8fa";
style=rounded;
etc_2 [label="...", style=solid, shape=none];
iced_winit;
}
subgraph cluster_3 {
style=invis;
margin=20;
iced;
}
{ rank = same; iced_winit etc_2 }
iced_native -> iced_winit;
iced_winit -> iced;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -50,6 +50,27 @@ We have not yet implemented a `LocalStorage` version of the auto-save feature. T
[TodoMVC]: http://todomvc.com/
## [Game of Life](game_of_life)
An interactive version of the [Game of Life], invented by [John Horton Conway].
It runs a simulation in a background thread while allowing interaction with a `Canvas` that displays an infinite grid with zooming, panning, and drawing support.
The relevant code is located in the __[`main`](game_of_life/src/main.rs)__ file.
<div align="center">
<a href="https://gfycat.com/briefaccurateaardvark">
<img src="https://thumbs.gfycat.com/BriefAccurateAardvark-size_restricted.gif">
</a>
</div>
You can run it with `cargo run`:
```
cargo run --package game_of_life
```
[Game of Life]: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
[John Horton Conway]: https://en.wikipedia.org/wiki/John_Horton_Conway
## [Styling](styling)
An example showcasing custom styling with a light and dark theme.
@ -69,8 +90,9 @@ cargo run --package styling
## Extras
A bunch of simpler examples exist:
- [`bezier_tool`](bezier_tool), a Paint-like tool for drawing Bézier curves using [`lyon`].
- [`bezier_tool`](bezier_tool), a Paint-like tool for drawing Bézier curves using the `Canvas` widget.
- [`clock`](clock), an application that uses the `Canvas` widget to draw a clock and its hands to display the current time.
- [`color_palette`](color_palette), a color palette generator based on a user-defined root color.
- [`counter`](counter), the classic counter example explained in the [`README`](../README.md).
- [`custom_widget`](custom_widget), a demonstration of how to build a custom widget that draws a circle.
- [`download_progress`](download_progress), a basic application that asynchronously downloads a dummy file of 100 MB and tracks the download progress.
@ -78,8 +100,10 @@ A bunch of simpler examples exist:
- [`geometry`](geometry), a custom widget showcasing how to draw geometry with the `Mesh2D` primitive in [`iced_wgpu`](../wgpu).
- [`integration`](integration), a demonstration of how to integrate Iced in an existing graphical application.
- [`pane_grid`](pane_grid), a grid of panes that can be split, resized, and reorganized.
- [`pick_list`](pick_list), a dropdown list of selectable options.
- [`pokedex`](pokedex), an application that displays a random Pokédex entry (sprite included!) by using the [PokéAPI].
- [`progress_bar`](progress_bar), a simple progress bar that can be filled by using a slider.
- [`scrollable`](scrollable), a showcase of the various scrollbar width options.
- [`solar_system`](solar_system), an animated solar system drawn using the `Canvas` widget and showcasing how to compose different transforms.
- [`stopwatch`](stopwatch), a watch with start/stop and reset buttons showcasing how to listen to time.
- [`svg`](svg), an application that renders the [Ghostscript Tiger] by leveraging the `Svg` widget.
@ -94,7 +118,7 @@ cargo run --package <example>
[Ghostscript Tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg
## [Coffee]
Since [Iced was born in May], it has been powering the user interfaces in
Since [Iced was born in May 2019], it has been powering the user interfaces in
[Coffee], an experimental 2D game engine.
@ -104,6 +128,6 @@ Since [Iced was born in May], it has been powering the user interfaces in
</a>
</div>
[Iced was born in May]: https://github.com/hecrj/coffee/pull/35
[Iced was born in May 2019]: https://github.com/hecrj/coffee/pull/35
[`ui` module]: https://docs.rs/coffee/0.3.2/coffee/ui/index.html
[Coffee]: https://github.com/hecrj/coffee

View File

@ -6,7 +6,4 @@ edition = "2018"
publish = false
[dependencies]
iced = { path = "../.." }
iced_native = { path = "../../native" }
iced_wgpu = { path = "../../wgpu" }
lyon = "0.15"
iced = { path = "../..", features = ["canvas"] }

View File

@ -1,6 +1,6 @@
## Bézier tool
A Paint-like tool for drawing Bézier curves using [`lyon`].
A Paint-like tool for drawing Bézier curves using the `Canvas` widget.
The __[`main`]__ file contains all the code of the example.
@ -16,4 +16,3 @@ cargo run --package bezier_tool
```
[`main`]: src/main.rs
[`lyon`]: https://github.com/nical/lyon

View File

@ -1,294 +1,13 @@
//! This example showcases a simple native custom widget that renders arbitrary
//! path with `lyon`.
mod bezier {
// For now, to implement a custom native widget you will need to add
// `iced_native` and `iced_wgpu` to your dependencies.
//
// Then, you simply need to define your widget type and implement the
// `iced_native::Widget` trait with the `iced_wgpu::Renderer`.
//
// Of course, you can choose to make the implementation renderer-agnostic,
// if you wish to, by creating your own `Renderer` trait, which could be
// implemented by `iced_wgpu` and other renderers.
use iced_native::{
input, layout, Clipboard, Color, Element, Event, Font, Hasher,
HorizontalAlignment, Layout, Length, MouseCursor, Point, Size, Vector,
VerticalAlignment, Widget,
};
use iced_wgpu::{
triangle::{Mesh2D, Vertex2D},
Defaults, Primitive, Renderer,
};
use lyon::tessellation::{
basic_shapes, BuffersBuilder, StrokeAttributes, StrokeOptions,
StrokeTessellator, VertexBuffers,
};
pub struct Bezier<'a, Message> {
state: &'a mut State,
curves: &'a [Curve],
// [from, to, ctrl]
on_click: Box<dyn Fn(Curve) -> Message>,
}
#[derive(Debug, Clone, Copy)]
pub struct Curve {
from: Point,
to: Point,
control: Point,
}
#[derive(Default)]
pub struct State {
pending: Option<Pending>,
}
enum Pending {
One { from: Point },
Two { from: Point, to: Point },
}
impl<'a, Message> Bezier<'a, Message> {
pub fn new<F>(
state: &'a mut State,
curves: &'a [Curve],
on_click: F,
) -> Self
where
F: 'static + Fn(Curve) -> Message,
{
Self {
state,
curves,
on_click: Box::new(on_click),
}
}
}
impl<'a, Message> Widget<Message, Renderer> for Bezier<'a, Message> {
fn width(&self) -> Length {
Length::Fill
}
fn height(&self) -> Length {
Length::Fill
}
fn layout(
&self,
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
let size = limits
.height(Length::Fill)
.width(Length::Fill)
.resolve(Size::ZERO);
layout::Node::new(size)
}
fn draw(
&self,
_renderer: &mut Renderer,
defaults: &Defaults,
layout: Layout<'_>,
cursor_position: Point,
) -> (Primitive, MouseCursor) {
let mut buffer: VertexBuffers<Vertex2D, u32> = VertexBuffers::new();
let mut path_builder = lyon::path::Path::builder();
let bounds = layout.bounds();
// Draw rectangle border with lyon.
basic_shapes::stroke_rectangle(
&lyon::math::Rect::new(
lyon::math::Point::new(0.5, 0.5),
lyon::math::Size::new(
bounds.width - 1.0,
bounds.height - 1.0,
),
),
&StrokeOptions::default().with_line_width(1.0),
&mut BuffersBuilder::new(
&mut buffer,
|pos: lyon::math::Point, _: StrokeAttributes| Vertex2D {
position: pos.to_array(),
color: [0.0, 0.0, 0.0, 1.0],
},
),
)
.unwrap();
for curve in self.curves {
path_builder.move_to(lyon::math::Point::new(
curve.from.x,
curve.from.y,
));
path_builder.quadratic_bezier_to(
lyon::math::Point::new(curve.control.x, curve.control.y),
lyon::math::Point::new(curve.to.x, curve.to.y),
);
}
match self.state.pending {
None => {}
Some(Pending::One { from }) => {
path_builder
.move_to(lyon::math::Point::new(from.x, from.y));
path_builder.line_to(lyon::math::Point::new(
cursor_position.x - bounds.x,
cursor_position.y - bounds.y,
));
}
Some(Pending::Two { from, to }) => {
path_builder
.move_to(lyon::math::Point::new(from.x, from.y));
path_builder.quadratic_bezier_to(
lyon::math::Point::new(
cursor_position.x - bounds.x,
cursor_position.y - bounds.y,
),
lyon::math::Point::new(to.x, to.y),
);
}
}
let mut tessellator = StrokeTessellator::new();
// Draw strokes with lyon.
tessellator
.tessellate(
&path_builder.build(),
&StrokeOptions::default().with_line_width(3.0),
&mut BuffersBuilder::new(
&mut buffer,
|pos: lyon::math::Point, _: StrokeAttributes| {
Vertex2D {
position: pos.to_array(),
color: [0.0, 0.0, 0.0, 1.0],
}
},
),
)
.unwrap();
let mesh = Primitive::Mesh2D {
origin: Point::new(bounds.x, bounds.y),
buffers: Mesh2D {
vertices: buffer.vertices,
indices: buffer.indices,
},
};
(
Primitive::Clip {
bounds,
offset: Vector::new(0, 0),
content: Box::new(
if self.curves.is_empty()
&& self.state.pending.is_none()
{
let instructions = Primitive::Text {
bounds,
color: Color {
a: defaults.text.color.a * 0.7,
..defaults.text.color
},
content: String::from(
"Click to create bezier curves!",
),
font: Font::Default,
size: 30.0,
horizontal_alignment:
HorizontalAlignment::Center,
vertical_alignment: VerticalAlignment::Center,
};
Primitive::Group {
primitives: vec![mesh, instructions],
}
} else {
mesh
},
),
},
MouseCursor::OutOfBounds,
)
}
fn hash_layout(&self, _state: &mut Hasher) {}
fn on_event(
&mut self,
event: Event,
layout: Layout<'_>,
cursor_position: Point,
messages: &mut Vec<Message>,
_renderer: &Renderer,
_clipboard: Option<&dyn Clipboard>,
) {
let bounds = layout.bounds();
if bounds.contains(cursor_position) {
match event {
Event::Mouse(input::mouse::Event::Input {
state: input::ButtonState::Pressed,
..
}) => {
let new_point = Point::new(
cursor_position.x - bounds.x,
cursor_position.y - bounds.y,
);
match self.state.pending {
None => {
self.state.pending =
Some(Pending::One { from: new_point });
}
Some(Pending::One { from }) => {
self.state.pending = Some(Pending::Two {
from,
to: new_point,
});
}
Some(Pending::Two { from, to }) => {
self.state.pending = None;
messages.push((self.on_click)(Curve {
from,
to,
control: new_point,
}));
}
}
}
_ => {}
}
}
}
}
impl<'a, Message> Into<Element<'a, Message, Renderer>> for Bezier<'a, Message>
where
Message: 'static,
{
fn into(self) -> Element<'a, Message, Renderer> {
Element::new(self)
}
}
}
use bezier::Bezier;
//! This example showcases an interactive `Canvas` for drawing Bézier curves.
use iced::{
button, Align, Button, Column, Container, Element, Length, Sandbox,
Settings, Text,
button, Align, Button, Column, Element, Length, Sandbox, Settings, Text,
};
pub fn main() {
pub fn main() -> iced::Result {
Example::run(Settings {
antialiasing: true,
..Settings::default()
});
})
}
#[derive(Default)]
@ -319,6 +38,7 @@ impl Sandbox for Example {
match message {
Message::AddCurve(curve) => {
self.curves.push(curve);
self.bezier.request_redraw();
}
Message::Clear => {
self.bezier = bezier::State::default();
@ -328,7 +48,7 @@ impl Sandbox for Example {
}
fn view(&mut self) -> Element<Message> {
let content = Column::new()
Column::new()
.padding(20)
.spacing(20)
.align_items(Align::Center)
@ -337,22 +57,189 @@ impl Sandbox for Example {
.width(Length::Shrink)
.size(50),
)
.push(Bezier::new(
&mut self.bezier,
self.curves.as_slice(),
Message::AddCurve,
))
.push(self.bezier.view(&self.curves).map(Message::AddCurve))
.push(
Button::new(&mut self.button_state, Text::new("Clear"))
.padding(8)
.on_press(Message::Clear),
);
Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
)
.into()
}
}
mod bezier {
use iced::{
canvas::event::{self, Event},
canvas::{self, Canvas, Cursor, Frame, Geometry, Path, Stroke},
mouse, Element, Length, Point, Rectangle,
};
#[derive(Default)]
pub struct State {
pending: Option<Pending>,
cache: canvas::Cache,
}
impl State {
pub fn view<'a>(
&'a mut self,
curves: &'a [Curve],
) -> Element<'a, Curve> {
Canvas::new(Bezier {
state: self,
curves,
})
.width(Length::Fill)
.height(Length::Fill)
.into()
}
pub fn request_redraw(&mut self) {
self.cache.clear()
}
}
struct Bezier<'a> {
state: &'a mut State,
curves: &'a [Curve],
}
impl<'a> canvas::Program<Curve> for Bezier<'a> {
fn update(
&mut self,
event: Event,
bounds: Rectangle,
cursor: Cursor,
) -> (event::Status, Option<Curve>) {
let cursor_position =
if let Some(position) = cursor.position_in(&bounds) {
position
} else {
return (event::Status::Ignored, None);
};
match event {
Event::Mouse(mouse_event) => {
let message = match mouse_event {
mouse::Event::ButtonPressed(mouse::Button::Left) => {
match self.state.pending {
None => {
self.state.pending = Some(Pending::One {
from: cursor_position,
});
None
}
Some(Pending::One { from }) => {
self.state.pending = Some(Pending::Two {
from,
to: cursor_position,
});
None
}
Some(Pending::Two { from, to }) => {
self.state.pending = None;
Some(Curve {
from,
to,
control: cursor_position,
})
}
}
}
_ => None,
};
(event::Status::Captured, message)
}
_ => (event::Status::Ignored, None),
}
}
fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec<Geometry> {
let content =
self.state.cache.draw(bounds.size(), |frame: &mut Frame| {
Curve::draw_all(self.curves, frame);
frame.stroke(
&Path::rectangle(Point::ORIGIN, frame.size()),
Stroke::default(),
);
});
if let Some(pending) = &self.state.pending {
let pending_curve = pending.draw(bounds, cursor);
vec![content, pending_curve]
} else {
vec![content]
}
}
fn mouse_interaction(
&self,
bounds: Rectangle,
cursor: Cursor,
) -> mouse::Interaction {
if cursor.is_over(&bounds) {
mouse::Interaction::Crosshair
} else {
mouse::Interaction::default()
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Curve {
from: Point,
to: Point,
control: Point,
}
impl Curve {
fn draw_all(curves: &[Curve], frame: &mut Frame) {
let curves = Path::new(|p| {
for curve in curves {
p.move_to(curve.from);
p.quadratic_curve_to(curve.control, curve.to);
}
});
frame.stroke(&curves, Stroke::default().with_width(2.0));
}
}
#[derive(Debug, Clone, Copy)]
enum Pending {
One { from: Point },
Two { from: Point, to: Point },
}
impl Pending {
fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Geometry {
let mut frame = Frame::new(bounds.size());
if let Some(cursor_position) = cursor.position_in(&bounds) {
match *self {
Pending::One { from } => {
let line = Path::line(from, cursor_position);
frame.stroke(&line, Stroke::default().with_width(2.0));
}
Pending::Two { from, to } => {
let curve = Curve {
from,
to,
control: cursor_position,
};
Curve::draw_all(&[curve], &mut frame);
}
};
}
frame.into_geometry()
}
}
}

View File

@ -5,11 +5,6 @@ authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
publish = false
[features]
canvas = []
[dependencies]
iced = { path = "../..", features = ["canvas", "async-std", "debug"] }
iced_native = { path = "../../native" }
iced = { path = "../..", features = ["canvas", "tokio", "debug"] }
chrono = "0.4"
async-std = { version = "1.0", features = ["unstable"] }

View File

@ -1,9 +1,10 @@
use iced::{
canvas, executor, Application, Canvas, Color, Command, Container, Element,
Length, Point, Settings, Subscription, Vector,
canvas::{self, Cache, Canvas, Cursor, Geometry, LineCap, Path, Stroke},
executor, time, Application, Clipboard, Color, Command, Container, Element,
Length, Point, Rectangle, Settings, Subscription, Vector,
};
pub fn main() {
pub fn main() -> iced::Result {
Clock::run(Settings {
antialiasing: true,
..Settings::default()
@ -11,8 +12,8 @@ pub fn main() {
}
struct Clock {
now: LocalTime,
clock: canvas::layer::Cache<LocalTime>,
now: chrono::DateTime<chrono::Local>,
clock: Cache,
}
#[derive(Debug, Clone, Copy)]
@ -28,8 +29,8 @@ impl Application for Clock {
fn new(_flags: ()) -> (Self, Command<Message>) {
(
Clock {
now: chrono::Local::now().into(),
clock: canvas::layer::Cache::new(),
now: chrono::Local::now(),
clock: Default::default(),
},
Command::none(),
)
@ -39,10 +40,14 @@ impl Application for Clock {
String::from("Clock - Iced")
}
fn update(&mut self, message: Message) -> Command<Message> {
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
match message {
Message::Tick(local_time) => {
let now = local_time.into();
let now = local_time;
if now != self.now {
self.now = now;
@ -55,14 +60,14 @@ impl Application for Clock {
}
fn subscription(&self) -> Subscription<Message> {
time::every(std::time::Duration::from_millis(500)).map(Message::Tick)
time::every(std::time::Duration::from_millis(500))
.map(|_| Message::Tick(chrono::Local::now()))
}
fn view(&mut self) -> Element<Message> {
let canvas = Canvas::new()
let canvas = Canvas::new(self)
.width(Length::Units(400))
.height(Length::Units(400))
.push(self.clock.with(&self.now));
.height(Length::Units(400));
Container::new(canvas)
.width(Length::Fill)
@ -74,122 +79,59 @@ impl Application for Clock {
}
}
#[derive(Debug, PartialEq, Eq)]
struct LocalTime {
hour: u32,
minute: u32,
second: u32,
}
impl From<chrono::DateTime<chrono::Local>> for LocalTime {
fn from(date_time: chrono::DateTime<chrono::Local>) -> LocalTime {
impl canvas::Program<Message> for Clock {
fn draw(&self, bounds: Rectangle, _cursor: Cursor) -> Vec<Geometry> {
use chrono::Timelike;
LocalTime {
hour: date_time.hour(),
minute: date_time.minute(),
second: date_time.second(),
}
}
}
let clock = self.clock.draw(bounds.size(), |frame| {
let center = frame.center();
let radius = frame.width().min(frame.height()) / 2.0;
impl canvas::Drawable for LocalTime {
fn draw(&self, frame: &mut canvas::Frame) {
let center = frame.center();
let radius = frame.width().min(frame.height()) / 2.0;
let offset = Vector::new(center.x, center.y);
let background = Path::circle(center, radius);
frame.fill(&background, Color::from_rgb8(0x12, 0x93, 0xD8));
let clock = canvas::Path::new(|path| path.circle(center, radius));
let short_hand =
Path::line(Point::ORIGIN, Point::new(0.0, -0.5 * radius));
frame.fill(
&clock,
canvas::Fill::Color(Color::from_rgb8(0x12, 0x93, 0xD8)),
);
let long_hand =
Path::line(Point::ORIGIN, Point::new(0.0, -0.8 * radius));
fn draw_hand(
n: u32,
total: u32,
length: f32,
offset: Vector,
path: &mut canvas::path::Builder,
) {
let turns = n as f32 / total as f32;
let t = 2.0 * std::f32::consts::PI * (turns - 0.25);
let x = length * t.cos();
let y = length * t.sin();
path.line_to(Point::new(x, y) + offset);
}
let hour_and_minute_hands = canvas::Path::new(|path| {
path.move_to(center);
draw_hand(self.hour, 12, 0.5 * radius, offset, path);
path.move_to(center);
draw_hand(self.minute, 60, 0.8 * radius, offset, path)
});
frame.stroke(
&hour_and_minute_hands,
canvas::Stroke {
width: radius / 100.0 * 3.0,
color: Color::WHITE,
line_cap: canvas::LineCap::Round,
..canvas::Stroke::default()
},
);
let second_hand = canvas::Path::new(|path| {
path.move_to(center);
draw_hand(self.second, 60, 0.8 * radius, offset, path)
});
frame.stroke(
&second_hand,
canvas::Stroke {
let thin_stroke = Stroke {
width: radius / 100.0,
color: Color::WHITE,
line_cap: canvas::LineCap::Round,
..canvas::Stroke::default()
},
);
line_cap: LineCap::Round,
..Stroke::default()
};
let wide_stroke = Stroke {
width: thin_stroke.width * 3.0,
..thin_stroke
};
frame.translate(Vector::new(center.x, center.y));
frame.with_save(|frame| {
frame.rotate(hand_rotation(self.now.hour(), 12));
frame.stroke(&short_hand, wide_stroke);
});
frame.with_save(|frame| {
frame.rotate(hand_rotation(self.now.minute(), 60));
frame.stroke(&long_hand, wide_stroke);
});
frame.with_save(|frame| {
frame.rotate(hand_rotation(self.now.second(), 60));
frame.stroke(&long_hand, thin_stroke);
})
});
vec![clock]
}
}
mod time {
use iced::futures;
fn hand_rotation(n: u32, total: u32) -> f32 {
let turns = n as f32 / total as f32;
pub fn every(
duration: std::time::Duration,
) -> iced::Subscription<chrono::DateTime<chrono::Local>> {
iced::Subscription::from_recipe(Every(duration))
}
struct Every(std::time::Duration);
impl<H, I> iced_native::subscription::Recipe<H, I> for Every
where
H: std::hash::Hasher,
{
type Output = chrono::DateTime<chrono::Local>;
fn hash(&self, state: &mut H) {
use std::hash::Hash;
std::any::TypeId::of::<Self>().hash(state);
self.0.hash(state);
}
fn stream(
self: Box<Self>,
_input: futures::stream::BoxStream<'static, I>,
) -> futures::stream::BoxStream<'static, Self::Output> {
use futures::stream::StreamExt;
async_std::stream::interval(self.0)
.map(|_| chrono::Local::now())
.boxed()
}
}
2.0 * std::f32::consts::PI * turns
}

View File

@ -0,0 +1,10 @@
[package]
name = "color_palette"
version = "0.1.0"
authors = ["Clark Moody <clark@clarkmoody.com>"]
edition = "2018"
publish = false
[dependencies]
iced = { path = "../..", features = ["canvas", "palette"] }
palette = "0.5.0"

View File

@ -0,0 +1,15 @@
## Color palette
A color palette generator, based on a user-defined root color.
<div align="center">
<a href="https://gfycat.com/dirtylonebighornsheep">
<img src="https://github.com/hecrj/iced/raw/1a8d253611d3796b0a32b2f096bb54565a5292e0/examples/color_palette/screenshot.png">
</a>
</div>
You can run it with `cargo run`:
```
cargo run --package color_palette
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -0,0 +1,462 @@
use iced::canvas::{self, Cursor, Frame, Geometry, Path};
use iced::{
slider, Align, Canvas, Color, Column, Element, HorizontalAlignment, Length,
Point, Rectangle, Row, Sandbox, Settings, Size, Slider, Text, Vector,
VerticalAlignment,
};
use palette::{self, Hsl, Limited, Srgb};
use std::marker::PhantomData;
use std::ops::RangeInclusive;
pub fn main() -> iced::Result {
ColorPalette::run(Settings {
antialiasing: true,
..Settings::default()
})
}
#[derive(Default)]
pub struct ColorPalette {
theme: Theme,
rgb: ColorPicker<Color>,
hsl: ColorPicker<palette::Hsl>,
hsv: ColorPicker<palette::Hsv>,
hwb: ColorPicker<palette::Hwb>,
lab: ColorPicker<palette::Lab>,
lch: ColorPicker<palette::Lch>,
}
#[derive(Debug, Clone, Copy)]
pub enum Message {
RgbColorChanged(Color),
HslColorChanged(palette::Hsl),
HsvColorChanged(palette::Hsv),
HwbColorChanged(palette::Hwb),
LabColorChanged(palette::Lab),
LchColorChanged(palette::Lch),
}
impl Sandbox for ColorPalette {
type Message = Message;
fn new() -> Self {
Self::default()
}
fn title(&self) -> String {
String::from("Color palette - Iced")
}
fn update(&mut self, message: Message) {
let srgb = match message {
Message::RgbColorChanged(rgb) => palette::Srgb::from(rgb),
Message::HslColorChanged(hsl) => palette::Srgb::from(hsl),
Message::HsvColorChanged(hsv) => palette::Srgb::from(hsv),
Message::HwbColorChanged(hwb) => palette::Srgb::from(hwb),
Message::LabColorChanged(lab) => palette::Srgb::from(lab),
Message::LchColorChanged(lch) => palette::Srgb::from(lch),
};
self.theme = Theme::new(srgb.clamp());
}
fn view(&mut self) -> Element<Message> {
let base = self.theme.base;
let srgb = palette::Srgb::from(base);
let hsl = palette::Hsl::from(srgb);
let hsv = palette::Hsv::from(srgb);
let hwb = palette::Hwb::from(srgb);
let lab = palette::Lab::from(srgb);
let lch = palette::Lch::from(srgb);
Column::new()
.padding(10)
.spacing(10)
.push(self.rgb.view(base).map(Message::RgbColorChanged))
.push(self.hsl.view(hsl).map(Message::HslColorChanged))
.push(self.hsv.view(hsv).map(Message::HsvColorChanged))
.push(self.hwb.view(hwb).map(Message::HwbColorChanged))
.push(self.lab.view(lab).map(Message::LabColorChanged))
.push(self.lch.view(lch).map(Message::LchColorChanged))
.push(self.theme.view())
.into()
}
}
#[derive(Debug)]
pub struct Theme {
lower: Vec<Color>,
base: Color,
higher: Vec<Color>,
canvas_cache: canvas::Cache,
}
impl Theme {
pub fn new(base: impl Into<Color>) -> Theme {
use palette::{Hue, Shade};
let base = base.into();
// Convert to HSL color for manipulation
let hsl = Hsl::from(Srgb::from(base));
let lower = [
hsl.shift_hue(-135.0).lighten(0.075),
hsl.shift_hue(-120.0),
hsl.shift_hue(-105.0).darken(0.075),
hsl.darken(0.075),
];
let higher = [
hsl.lighten(0.075),
hsl.shift_hue(105.0).darken(0.075),
hsl.shift_hue(120.0),
hsl.shift_hue(135.0).lighten(0.075),
];
Theme {
lower: lower
.iter()
.map(|&color| Srgb::from(color).clamp().into())
.collect(),
base,
higher: higher
.iter()
.map(|&color| Srgb::from(color).clamp().into())
.collect(),
canvas_cache: canvas::Cache::default(),
}
}
pub fn len(&self) -> usize {
self.lower.len() + self.higher.len() + 1
}
pub fn colors(&self) -> impl Iterator<Item = &Color> {
self.lower
.iter()
.chain(std::iter::once(&self.base))
.chain(self.higher.iter())
}
pub fn view(&mut self) -> Element<Message> {
Canvas::new(self)
.width(Length::Fill)
.height(Length::Fill)
.into()
}
fn draw(&self, frame: &mut Frame) {
let pad = 20.0;
let box_size = Size {
width: frame.width() / self.len() as f32,
height: frame.height() / 2.0 - pad,
};
let triangle = Path::new(|path| {
path.move_to(Point { x: 0.0, y: -0.5 });
path.line_to(Point { x: -0.5, y: 0.0 });
path.line_to(Point { x: 0.5, y: 0.0 });
path.close();
});
let mut text = canvas::Text {
horizontal_alignment: HorizontalAlignment::Center,
vertical_alignment: VerticalAlignment::Top,
size: 15.0,
..canvas::Text::default()
};
for (i, &color) in self.colors().enumerate() {
let anchor = Point {
x: (i as f32) * box_size.width,
y: 0.0,
};
frame.fill_rectangle(anchor, box_size, color);
// We show a little indicator for the base color
if color == self.base {
let triangle_x = anchor.x + box_size.width / 2.0;
frame.with_save(|frame| {
frame.translate(Vector::new(triangle_x, 0.0));
frame.scale(10.0);
frame.rotate(std::f32::consts::PI);
frame.fill(&triangle, Color::WHITE);
});
frame.with_save(|frame| {
frame.translate(Vector::new(triangle_x, box_size.height));
frame.scale(10.0);
frame.fill(&triangle, Color::WHITE);
});
}
frame.fill_text(canvas::Text {
content: color_hex_string(&color),
position: Point {
x: anchor.x + box_size.width / 2.0,
y: box_size.height,
},
..text
});
}
text.vertical_alignment = VerticalAlignment::Bottom;
let hsl = Hsl::from(Srgb::from(self.base));
for i in 0..self.len() {
let pct = (i as f32 + 1.0) / (self.len() as f32 + 1.0);
let graded = Hsl {
lightness: 1.0 - pct,
..hsl
};
let color: Color = Srgb::from(graded.clamp()).into();
let anchor = Point {
x: (i as f32) * box_size.width,
y: box_size.height + 2.0 * pad,
};
frame.fill_rectangle(anchor, box_size, color);
frame.fill_text(canvas::Text {
content: color_hex_string(&color),
position: Point {
x: anchor.x + box_size.width / 2.0,
y: box_size.height + 2.0 * pad,
},
..text
});
}
}
}
impl canvas::Program<Message> for Theme {
fn draw(&self, bounds: Rectangle, _cursor: Cursor) -> Vec<Geometry> {
let theme = self.canvas_cache.draw(bounds.size(), |frame| {
self.draw(frame);
});
vec![theme]
}
}
impl Default for Theme {
fn default() -> Self {
Theme::new(Color::from_rgb8(75, 128, 190))
}
}
fn color_hex_string(color: &Color) -> String {
format!(
"#{:x}{:x}{:x}",
(255.0 * color.r).round() as u8,
(255.0 * color.g).round() as u8,
(255.0 * color.b).round() as u8
)
}
#[derive(Default)]
struct ColorPicker<C: ColorSpace> {
sliders: [slider::State; 3],
color_space: PhantomData<C>,
}
trait ColorSpace: Sized {
const LABEL: &'static str;
const COMPONENT_RANGES: [RangeInclusive<f64>; 3];
fn new(a: f32, b: f32, c: f32) -> Self;
fn components(&self) -> [f32; 3];
fn to_string(&self) -> String;
}
impl<C: 'static + ColorSpace + Copy> ColorPicker<C> {
fn view(&mut self, color: C) -> Element<C> {
let [c1, c2, c3] = color.components();
let [s1, s2, s3] = &mut self.sliders;
let [cr1, cr2, cr3] = C::COMPONENT_RANGES;
fn slider<C: Clone>(
state: &mut slider::State,
range: RangeInclusive<f64>,
component: f32,
update: impl Fn(f32) -> C + 'static,
) -> Slider<f64, C> {
Slider::new(state, range, f64::from(component), move |v| {
update(v as f32)
})
.step(0.01)
}
Row::new()
.spacing(10)
.align_items(Align::Center)
.push(Text::new(C::LABEL).width(Length::Units(50)))
.push(slider(s1, cr1, c1, move |v| C::new(v, c2, c3)))
.push(slider(s2, cr2, c2, move |v| C::new(c1, v, c3)))
.push(slider(s3, cr3, c3, move |v| C::new(c1, c2, v)))
.push(
Text::new(color.to_string())
.width(Length::Units(185))
.size(14),
)
.into()
}
}
impl ColorSpace for Color {
const LABEL: &'static str = "RGB";
const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=1.0, 0.0..=1.0, 0.0..=1.0];
fn new(r: f32, g: f32, b: f32) -> Self {
Color::from_rgb(r, g, b)
}
fn components(&self) -> [f32; 3] {
[self.r, self.g, self.b]
}
fn to_string(&self) -> String {
format!(
"rgb({:.0}, {:.0}, {:.0})",
255.0 * self.r,
255.0 * self.g,
255.0 * self.b
)
}
}
impl ColorSpace for palette::Hsl {
const LABEL: &'static str = "HSL";
const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
fn new(hue: f32, saturation: f32, lightness: f32) -> Self {
palette::Hsl::new(
palette::RgbHue::from_degrees(hue),
saturation,
lightness,
)
}
fn components(&self) -> [f32; 3] {
[
self.hue.to_positive_degrees(),
self.saturation,
self.lightness,
]
}
fn to_string(&self) -> String {
format!(
"hsl({:.1}, {:.1}%, {:.1}%)",
self.hue.to_positive_degrees(),
100.0 * self.saturation,
100.0 * self.lightness
)
}
}
impl ColorSpace for palette::Hsv {
const LABEL: &'static str = "HSV";
const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
fn new(hue: f32, saturation: f32, value: f32) -> Self {
palette::Hsv::new(palette::RgbHue::from_degrees(hue), saturation, value)
}
fn components(&self) -> [f32; 3] {
[self.hue.to_positive_degrees(), self.saturation, self.value]
}
fn to_string(&self) -> String {
format!(
"hsv({:.1}, {:.1}%, {:.1}%)",
self.hue.to_positive_degrees(),
100.0 * self.saturation,
100.0 * self.value
)
}
}
impl ColorSpace for palette::Hwb {
const LABEL: &'static str = "HWB";
const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
fn new(hue: f32, whiteness: f32, blackness: f32) -> Self {
palette::Hwb::new(
palette::RgbHue::from_degrees(hue),
whiteness,
blackness,
)
}
fn components(&self) -> [f32; 3] {
[
self.hue.to_positive_degrees(),
self.whiteness,
self.blackness,
]
}
fn to_string(&self) -> String {
format!(
"hwb({:.1}, {:.1}%, {:.1}%)",
self.hue.to_positive_degrees(),
100.0 * self.whiteness,
100.0 * self.blackness
)
}
}
impl ColorSpace for palette::Lab {
const LABEL: &'static str = "Lab";
const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=100.0, -128.0..=127.0, -128.0..=127.0];
fn new(l: f32, a: f32, b: f32) -> Self {
palette::Lab::new(l, a, b)
}
fn components(&self) -> [f32; 3] {
[self.l, self.a, self.b]
}
fn to_string(&self) -> String {
format!("Lab({:.1}, {:.1}, {:.1})", self.l, self.a, self.b)
}
}
impl ColorSpace for palette::Lch {
const LABEL: &'static str = "Lch";
const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=100.0, 0.0..=128.0, 0.0..=360.0];
fn new(l: f32, chroma: f32, hue: f32) -> Self {
palette::Lch::new(l, chroma, palette::LabHue::from_degrees(hue))
}
fn components(&self) -> [f32; 3] {
[self.l, self.chroma, self.hue.to_positive_degrees()]
}
fn to_string(&self) -> String {
format!(
"Lch({:.1}, {:.1}, {:.1})",
self.l,
self.chroma,
self.hue.to_positive_degrees()
)
}
}

View File

@ -1,6 +1,6 @@
use iced::{button, Align, Button, Column, Element, Sandbox, Settings, Text};
pub fn main() {
pub fn main() -> iced::Result {
Counter::run(Settings::default())
}

View File

@ -8,4 +8,4 @@ publish = false
[dependencies]
iced = { path = "../.." }
iced_native = { path = "../../native" }
iced_wgpu = { path = "../../wgpu" }
iced_graphics = { path = "../../graphics" }

View File

@ -9,23 +9,26 @@ mod circle {
// Of course, you can choose to make the implementation renderer-agnostic,
// if you wish to, by creating your own `Renderer` trait, which could be
// implemented by `iced_wgpu` and other renderers.
use iced_graphics::{Backend, Defaults, Primitive, Renderer};
use iced_native::{
layout, Background, Color, Element, Hasher, Layout, Length,
MouseCursor, Point, Size, Widget,
layout, mouse, Background, Color, Element, Hasher, Layout, Length,
Point, Rectangle, Size, Widget,
};
use iced_wgpu::{Defaults, Primitive, Renderer};
pub struct Circle {
radius: u16,
radius: f32,
}
impl Circle {
pub fn new(radius: u16) -> Self {
pub fn new(radius: f32) -> Self {
Self { radius }
}
}
impl<Message> Widget<Message, Renderer> for Circle {
impl<Message, B> Widget<Message, Renderer<B>> for Circle
where
B: Backend,
{
fn width(&self) -> Length {
Length::Shrink
}
@ -36,43 +39,44 @@ mod circle {
fn layout(
&self,
_renderer: &Renderer,
_renderer: &Renderer<B>,
_limits: &layout::Limits,
) -> layout::Node {
layout::Node::new(Size::new(
f32::from(self.radius) * 2.0,
f32::from(self.radius) * 2.0,
))
layout::Node::new(Size::new(self.radius * 2.0, self.radius * 2.0))
}
fn hash_layout(&self, state: &mut Hasher) {
use std::hash::Hash;
self.radius.hash(state);
self.radius.to_bits().hash(state);
}
fn draw(
&self,
_renderer: &mut Renderer,
_renderer: &mut Renderer<B>,
_defaults: &Defaults,
layout: Layout<'_>,
_cursor_position: Point,
) -> (Primitive, MouseCursor) {
_viewport: &Rectangle,
) -> (Primitive, mouse::Interaction) {
(
Primitive::Quad {
bounds: layout.bounds(),
background: Background::Color(Color::BLACK),
border_radius: self.radius,
border_width: 0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
MouseCursor::OutOfBounds,
mouse::Interaction::default(),
)
}
}
impl<'a, Message> Into<Element<'a, Message, Renderer>> for Circle {
fn into(self) -> Element<'a, Message, Renderer> {
impl<'a, Message, B> Into<Element<'a, Message, Renderer<B>>> for Circle
where
B: Backend,
{
fn into(self) -> Element<'a, Message, Renderer<B>> {
Element::new(self)
}
}
@ -84,12 +88,12 @@ use iced::{
Slider, Text,
};
pub fn main() {
pub fn main() -> iced::Result {
Example::run(Settings::default())
}
struct Example {
radius: u16,
radius: f32,
slider: slider::State,
}
@ -103,7 +107,7 @@ impl Sandbox for Example {
fn new() -> Self {
Example {
radius: 50,
radius: 50.0,
slider: slider::State::new(),
}
}
@ -115,7 +119,7 @@ impl Sandbox for Example {
fn update(&mut self, message: Message) {
match message {
Message::RadiusChanged(radius) => {
self.radius = radius.round() as u16;
self.radius = radius;
}
}
}
@ -127,13 +131,16 @@ impl Sandbox for Example {
.max_width(500)
.align_items(Align::Center)
.push(Circle::new(self.radius))
.push(Text::new(format!("Radius: {}", self.radius.to_string())))
.push(Slider::new(
&mut self.slider,
1.0..=100.0,
f32::from(self.radius),
Message::RadiusChanged,
));
.push(Text::new(format!("Radius: {:.2}", self.radius)))
.push(
Slider::new(
&mut self.slider,
1.0..=100.0,
self.radius,
Message::RadiusChanged,
)
.step(0.01),
);
Container::new(content)
.width(Length::Fill)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,12 @@
[package]
name = "game_of_life"
version = "0.1.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
publish = false
[dependencies]
iced = { path = "../..", features = ["canvas", "tokio", "debug"] }
tokio = { version = "1.0", features = ["sync"] }
itertools = "0.9"
rustc-hash = "1.1"

View File

@ -0,0 +1,22 @@
## Game of Life
An interactive version of the [Game of Life], invented by [John Horton Conway].
It runs a simulation in a background thread while allowing interaction with a `Canvas` that displays an infinite grid with zooming, panning, and drawing support.
The __[`main`]__ file contains the relevant code of the example.
<div align="center">
<a href="https://gfycat.com/WhichPaltryChick">
<img src="https://thumbs.gfycat.com/WhichPaltryChick-size_restricted.gif">
</a>
</div>
You can run it with `cargo run`:
```
cargo run --package game_of_life
```
[`main`]: src/main.rs
[Game of Life]: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
[John Horton Conway]: https://en.wikipedia.org/wiki/John_Horton_Conway

View File

@ -0,0 +1,889 @@
//! This example showcases an interactive version of the Game of Life, invented
//! by John Conway. It leverages a `Canvas` together with other widgets.
mod preset;
mod style;
use grid::Grid;
use iced::button::{self, Button};
use iced::executor;
use iced::pick_list::{self, PickList};
use iced::slider::{self, Slider};
use iced::time;
use iced::{
Align, Application, Checkbox, Clipboard, Column, Command, Container,
Element, Length, Row, Settings, Subscription, Text,
};
use preset::Preset;
use std::time::{Duration, Instant};
pub fn main() -> iced::Result {
GameOfLife::run(Settings {
antialiasing: true,
..Settings::default()
})
}
#[derive(Default)]
struct GameOfLife {
grid: Grid,
controls: Controls,
is_playing: bool,
queued_ticks: usize,
speed: usize,
next_speed: Option<usize>,
version: usize,
}
#[derive(Debug, Clone)]
enum Message {
Grid(grid::Message, usize),
Tick(Instant),
TogglePlayback,
ToggleGrid(bool),
Next,
Clear,
SpeedChanged(f32),
PresetPicked(Preset),
}
impl Application for GameOfLife {
type Message = Message;
type Executor = executor::Default;
type Flags = ();
fn new(_flags: ()) -> (Self, Command<Message>) {
(
Self {
speed: 5,
..Self::default()
},
Command::none(),
)
}
fn title(&self) -> String {
String::from("Game of Life - Iced")
}
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
match message {
Message::Grid(message, version) => {
if version == self.version {
self.grid.update(message);
}
}
Message::Tick(_) | Message::Next => {
self.queued_ticks = (self.queued_ticks + 1).min(self.speed);
if let Some(task) = self.grid.tick(self.queued_ticks) {
if let Some(speed) = self.next_speed.take() {
self.speed = speed;
}
self.queued_ticks = 0;
let version = self.version;
return Command::perform(task, move |message| {
Message::Grid(message, version)
});
}
}
Message::TogglePlayback => {
self.is_playing = !self.is_playing;
}
Message::ToggleGrid(show_grid_lines) => {
self.grid.toggle_lines(show_grid_lines);
}
Message::Clear => {
self.grid.clear();
self.version += 1;
}
Message::SpeedChanged(speed) => {
if self.is_playing {
self.next_speed = Some(speed.round() as usize);
} else {
self.speed = speed.round() as usize;
}
}
Message::PresetPicked(new_preset) => {
self.grid = Grid::from_preset(new_preset);
self.version += 1;
}
}
Command::none()
}
fn subscription(&self) -> Subscription<Message> {
if self.is_playing {
time::every(Duration::from_millis(1000 / self.speed as u64))
.map(Message::Tick)
} else {
Subscription::none()
}
}
fn view(&mut self) -> Element<Message> {
let version = self.version;
let selected_speed = self.next_speed.unwrap_or(self.speed);
let controls = self.controls.view(
self.is_playing,
self.grid.are_lines_visible(),
selected_speed,
self.grid.preset(),
);
let content = Column::new()
.push(
self.grid
.view()
.map(move |message| Message::Grid(message, version)),
)
.push(controls);
Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.style(style::Container)
.into()
}
}
mod grid {
use crate::Preset;
use iced::{
canvas::event::{self, Event},
canvas::{self, Cache, Canvas, Cursor, Frame, Geometry, Path, Text},
mouse, Color, Element, HorizontalAlignment, Length, Point, Rectangle,
Size, Vector, VerticalAlignment,
};
use rustc_hash::{FxHashMap, FxHashSet};
use std::future::Future;
use std::ops::RangeInclusive;
use std::time::{Duration, Instant};
pub struct Grid {
state: State,
preset: Preset,
interaction: Interaction,
life_cache: Cache,
grid_cache: Cache,
translation: Vector,
scaling: f32,
show_lines: bool,
last_tick_duration: Duration,
last_queued_ticks: usize,
}
#[derive(Debug, Clone)]
pub enum Message {
Populate(Cell),
Unpopulate(Cell),
Ticked {
result: Result<Life, TickError>,
tick_duration: Duration,
},
}
#[derive(Debug, Clone)]
pub enum TickError {
JoinFailed,
}
impl Default for Grid {
fn default() -> Self {
Self::from_preset(Preset::default())
}
}
impl Grid {
const MIN_SCALING: f32 = 0.1;
const MAX_SCALING: f32 = 2.0;
pub fn from_preset(preset: Preset) -> Self {
Self {
state: State::with_life(
preset
.life()
.into_iter()
.map(|(i, j)| Cell { i, j })
.collect(),
),
preset,
interaction: Interaction::None,
life_cache: Cache::default(),
grid_cache: Cache::default(),
translation: Vector::default(),
scaling: 1.0,
show_lines: true,
last_tick_duration: Duration::default(),
last_queued_ticks: 0,
}
}
pub fn tick(
&mut self,
amount: usize,
) -> Option<impl Future<Output = Message>> {
let tick = self.state.tick(amount)?;
self.last_queued_ticks = amount;
Some(async move {
let start = Instant::now();
let result = tick.await;
let tick_duration = start.elapsed() / amount as u32;
Message::Ticked {
result,
tick_duration,
}
})
}
pub fn update(&mut self, message: Message) {
match message {
Message::Populate(cell) => {
self.state.populate(cell);
self.life_cache.clear();
self.preset = Preset::Custom;
}
Message::Unpopulate(cell) => {
self.state.unpopulate(&cell);
self.life_cache.clear();
self.preset = Preset::Custom;
}
Message::Ticked {
result: Ok(life),
tick_duration,
} => {
self.state.update(life);
self.life_cache.clear();
self.last_tick_duration = tick_duration;
}
Message::Ticked {
result: Err(error), ..
} => {
dbg!(error);
}
}
}
pub fn view<'a>(&'a mut self) -> Element<'a, Message> {
Canvas::new(self)
.width(Length::Fill)
.height(Length::Fill)
.into()
}
pub fn clear(&mut self) {
self.state = State::default();
self.preset = Preset::Custom;
self.life_cache.clear();
}
pub fn preset(&self) -> Preset {
self.preset
}
pub fn toggle_lines(&mut self, enabled: bool) {
self.show_lines = enabled;
}
pub fn are_lines_visible(&self) -> bool {
self.show_lines
}
fn visible_region(&self, size: Size) -> Region {
let width = size.width / self.scaling;
let height = size.height / self.scaling;
Region {
x: -self.translation.x - width / 2.0,
y: -self.translation.y - height / 2.0,
width,
height,
}
}
fn project(&self, position: Point, size: Size) -> Point {
let region = self.visible_region(size);
Point::new(
position.x / self.scaling + region.x,
position.y / self.scaling + region.y,
)
}
}
impl<'a> canvas::Program<Message> for Grid {
fn update(
&mut self,
event: Event,
bounds: Rectangle,
cursor: Cursor,
) -> (event::Status, Option<Message>) {
if let Event::Mouse(mouse::Event::ButtonReleased(_)) = event {
self.interaction = Interaction::None;
}
let cursor_position =
if let Some(position) = cursor.position_in(&bounds) {
position
} else {
return (event::Status::Ignored, None);
};
let cell = Cell::at(self.project(cursor_position, bounds.size()));
let is_populated = self.state.contains(&cell);
let (populate, unpopulate) = if is_populated {
(None, Some(Message::Unpopulate(cell)))
} else {
(Some(Message::Populate(cell)), None)
};
match event {
Event::Mouse(mouse_event) => match mouse_event {
mouse::Event::ButtonPressed(button) => {
let message = match button {
mouse::Button::Left => {
self.interaction = if is_populated {
Interaction::Erasing
} else {
Interaction::Drawing
};
populate.or(unpopulate)
}
mouse::Button::Right => {
self.interaction = Interaction::Panning {
translation: self.translation,
start: cursor_position,
};
None
}
_ => None,
};
(event::Status::Captured, message)
}
mouse::Event::CursorMoved { .. } => {
let message = match self.interaction {
Interaction::Drawing => populate,
Interaction::Erasing => unpopulate,
Interaction::Panning { translation, start } => {
self.translation = translation
+ (cursor_position - start)
* (1.0 / self.scaling);
self.life_cache.clear();
self.grid_cache.clear();
None
}
_ => None,
};
let event_status = match self.interaction {
Interaction::None => event::Status::Ignored,
_ => event::Status::Captured,
};
(event_status, message)
}
mouse::Event::WheelScrolled { delta } => match delta {
mouse::ScrollDelta::Lines { y, .. }
| mouse::ScrollDelta::Pixels { y, .. } => {
if y < 0.0 && self.scaling > Self::MIN_SCALING
|| y > 0.0 && self.scaling < Self::MAX_SCALING
{
let old_scaling = self.scaling;
self.scaling = (self.scaling
* (1.0 + y / 30.0))
.max(Self::MIN_SCALING)
.min(Self::MAX_SCALING);
if let Some(cursor_to_center) =
cursor.position_from(bounds.center())
{
let factor = self.scaling - old_scaling;
self.translation = self.translation
- Vector::new(
cursor_to_center.x * factor
/ (old_scaling * old_scaling),
cursor_to_center.y * factor
/ (old_scaling * old_scaling),
);
}
self.life_cache.clear();
self.grid_cache.clear();
}
(event::Status::Captured, None)
}
},
_ => (event::Status::Ignored, None),
},
_ => (event::Status::Ignored, None),
}
}
fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec<Geometry> {
let center = Vector::new(bounds.width / 2.0, bounds.height / 2.0);
let life = self.life_cache.draw(bounds.size(), |frame| {
let background = Path::rectangle(Point::ORIGIN, frame.size());
frame.fill(&background, Color::from_rgb8(0x40, 0x44, 0x4B));
frame.with_save(|frame| {
frame.translate(center);
frame.scale(self.scaling);
frame.translate(self.translation);
frame.scale(Cell::SIZE as f32);
let region = self.visible_region(frame.size());
for cell in region.cull(self.state.cells()) {
frame.fill_rectangle(
Point::new(cell.j as f32, cell.i as f32),
Size::UNIT,
Color::WHITE,
);
}
});
});
let overlay = {
let mut frame = Frame::new(bounds.size());
let hovered_cell =
cursor.position_in(&bounds).map(|position| {
Cell::at(self.project(position, frame.size()))
});
if let Some(cell) = hovered_cell {
frame.with_save(|frame| {
frame.translate(center);
frame.scale(self.scaling);
frame.translate(self.translation);
frame.scale(Cell::SIZE as f32);
frame.fill_rectangle(
Point::new(cell.j as f32, cell.i as f32),
Size::UNIT,
Color {
a: 0.5,
..Color::BLACK
},
);
});
}
let text = Text {
color: Color::WHITE,
size: 14.0,
position: Point::new(frame.width(), frame.height()),
horizontal_alignment: HorizontalAlignment::Right,
vertical_alignment: VerticalAlignment::Bottom,
..Text::default()
};
if let Some(cell) = hovered_cell {
frame.fill_text(Text {
content: format!("({}, {})", cell.j, cell.i),
position: text.position - Vector::new(0.0, 16.0),
..text
});
}
let cell_count = self.state.cell_count();
frame.fill_text(Text {
content: format!(
"{} cell{} @ {:?} ({})",
cell_count,
if cell_count == 1 { "" } else { "s" },
self.last_tick_duration,
self.last_queued_ticks
),
..text
});
frame.into_geometry()
};
if self.scaling < 0.2 || !self.show_lines {
vec![life, overlay]
} else {
let grid = self.grid_cache.draw(bounds.size(), |frame| {
frame.translate(center);
frame.scale(self.scaling);
frame.translate(self.translation);
frame.scale(Cell::SIZE as f32);
let region = self.visible_region(frame.size());
let rows = region.rows();
let columns = region.columns();
let (total_rows, total_columns) =
(rows.clone().count(), columns.clone().count());
let width = 2.0 / Cell::SIZE as f32;
let color = Color::from_rgb8(70, 74, 83);
frame.translate(Vector::new(-width / 2.0, -width / 2.0));
for row in region.rows() {
frame.fill_rectangle(
Point::new(*columns.start() as f32, row as f32),
Size::new(total_columns as f32, width),
color,
);
}
for column in region.columns() {
frame.fill_rectangle(
Point::new(column as f32, *rows.start() as f32),
Size::new(width, total_rows as f32),
color,
);
}
});
vec![life, grid, overlay]
}
}
fn mouse_interaction(
&self,
bounds: Rectangle,
cursor: Cursor,
) -> mouse::Interaction {
match self.interaction {
Interaction::Drawing => mouse::Interaction::Crosshair,
Interaction::Erasing => mouse::Interaction::Crosshair,
Interaction::Panning { .. } => mouse::Interaction::Grabbing,
Interaction::None if cursor.is_over(&bounds) => {
mouse::Interaction::Crosshair
}
_ => mouse::Interaction::default(),
}
}
}
#[derive(Default)]
struct State {
life: Life,
births: FxHashSet<Cell>,
is_ticking: bool,
}
impl State {
pub fn with_life(life: Life) -> Self {
Self {
life,
..Self::default()
}
}
fn cell_count(&self) -> usize {
self.life.len() + self.births.len()
}
fn contains(&self, cell: &Cell) -> bool {
self.life.contains(cell) || self.births.contains(cell)
}
fn cells(&self) -> impl Iterator<Item = &Cell> {
self.life.iter().chain(self.births.iter())
}
fn populate(&mut self, cell: Cell) {
if self.is_ticking {
self.births.insert(cell);
} else {
self.life.populate(cell);
}
}
fn unpopulate(&mut self, cell: &Cell) {
if self.is_ticking {
let _ = self.births.remove(cell);
} else {
self.life.unpopulate(cell);
}
}
fn update(&mut self, mut life: Life) {
self.births.drain().for_each(|cell| life.populate(cell));
self.life = life;
self.is_ticking = false;
}
fn tick(
&mut self,
amount: usize,
) -> Option<impl Future<Output = Result<Life, TickError>>> {
if self.is_ticking {
return None;
}
self.is_ticking = true;
let mut life = self.life.clone();
Some(async move {
tokio::task::spawn_blocking(move || {
for _ in 0..amount {
life.tick();
}
life
})
.await
.map_err(|_| TickError::JoinFailed)
})
}
}
#[derive(Clone, Default)]
pub struct Life {
cells: FxHashSet<Cell>,
}
impl Life {
fn len(&self) -> usize {
self.cells.len()
}
fn contains(&self, cell: &Cell) -> bool {
self.cells.contains(cell)
}
fn populate(&mut self, cell: Cell) {
self.cells.insert(cell);
}
fn unpopulate(&mut self, cell: &Cell) {
let _ = self.cells.remove(cell);
}
fn tick(&mut self) {
let mut adjacent_life = FxHashMap::default();
for cell in &self.cells {
let _ = adjacent_life.entry(*cell).or_insert(0);
for neighbor in Cell::neighbors(*cell) {
let amount = adjacent_life.entry(neighbor).or_insert(0);
*amount += 1;
}
}
for (cell, amount) in adjacent_life.iter() {
match amount {
2 => {}
3 => {
let _ = self.cells.insert(*cell);
}
_ => {
let _ = self.cells.remove(cell);
}
}
}
}
pub fn iter(&self) -> impl Iterator<Item = &Cell> {
self.cells.iter()
}
}
impl std::iter::FromIterator<Cell> for Life {
fn from_iter<I: IntoIterator<Item = Cell>>(iter: I) -> Self {
Life {
cells: iter.into_iter().collect(),
}
}
}
impl std::fmt::Debug for Life {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Life")
.field("cells", &self.cells.len())
.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Cell {
i: isize,
j: isize,
}
impl Cell {
const SIZE: usize = 20;
fn at(position: Point) -> Cell {
let i = (position.y / Cell::SIZE as f32).ceil() as isize;
let j = (position.x / Cell::SIZE as f32).ceil() as isize;
Cell {
i: i.saturating_sub(1),
j: j.saturating_sub(1),
}
}
fn cluster(cell: Cell) -> impl Iterator<Item = Cell> {
use itertools::Itertools;
let rows = cell.i.saturating_sub(1)..=cell.i.saturating_add(1);
let columns = cell.j.saturating_sub(1)..=cell.j.saturating_add(1);
rows.cartesian_product(columns).map(|(i, j)| Cell { i, j })
}
fn neighbors(cell: Cell) -> impl Iterator<Item = Cell> {
Cell::cluster(cell).filter(move |candidate| *candidate != cell)
}
}
pub struct Region {
x: f32,
y: f32,
width: f32,
height: f32,
}
impl Region {
fn rows(&self) -> RangeInclusive<isize> {
let first_row = (self.y / Cell::SIZE as f32).floor() as isize;
let visible_rows =
(self.height / Cell::SIZE as f32).ceil() as isize;
first_row..=first_row + visible_rows
}
fn columns(&self) -> RangeInclusive<isize> {
let first_column = (self.x / Cell::SIZE as f32).floor() as isize;
let visible_columns =
(self.width / Cell::SIZE as f32).ceil() as isize;
first_column..=first_column + visible_columns
}
fn cull<'a>(
&self,
cells: impl Iterator<Item = &'a Cell>,
) -> impl Iterator<Item = &'a Cell> {
let rows = self.rows();
let columns = self.columns();
cells.filter(move |cell| {
rows.contains(&cell.i) && columns.contains(&cell.j)
})
}
}
enum Interaction {
None,
Drawing,
Erasing,
Panning { translation: Vector, start: Point },
}
}
#[derive(Default)]
struct Controls {
toggle_button: button::State,
next_button: button::State,
clear_button: button::State,
speed_slider: slider::State,
preset_list: pick_list::State<Preset>,
}
impl Controls {
fn view<'a>(
&'a mut self,
is_playing: bool,
is_grid_enabled: bool,
speed: usize,
preset: Preset,
) -> Element<'a, Message> {
let playback_controls = Row::new()
.spacing(10)
.push(
Button::new(
&mut self.toggle_button,
Text::new(if is_playing { "Pause" } else { "Play" }),
)
.on_press(Message::TogglePlayback)
.style(style::Button),
)
.push(
Button::new(&mut self.next_button, Text::new("Next"))
.on_press(Message::Next)
.style(style::Button),
);
let speed_controls = Row::new()
.width(Length::Fill)
.align_items(Align::Center)
.spacing(10)
.push(
Slider::new(
&mut self.speed_slider,
1.0..=1000.0,
speed as f32,
Message::SpeedChanged,
)
.style(style::Slider),
)
.push(Text::new(format!("x{}", speed)).size(16));
Row::new()
.padding(10)
.spacing(20)
.align_items(Align::Center)
.push(playback_controls)
.push(speed_controls)
.push(
Checkbox::new(is_grid_enabled, "Grid", Message::ToggleGrid)
.size(16)
.spacing(5)
.text_size(16),
)
.push(
PickList::new(
&mut self.preset_list,
preset::ALL,
Some(preset),
Message::PresetPicked,
)
.padding(8)
.text_size(16)
.style(style::PickList),
)
.push(
Button::new(&mut self.clear_button, Text::new("Clear"))
.on_press(Message::Clear)
.style(style::Clear),
)
.into()
}
}

View File

@ -0,0 +1,142 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Preset {
Custom,
XKCD,
Glider,
SmallExploder,
Exploder,
TenCellRow,
LightweightSpaceship,
Tumbler,
GliderGun,
Acorn,
}
pub static ALL: &[Preset] = &[
Preset::Custom,
Preset::XKCD,
Preset::Glider,
Preset::SmallExploder,
Preset::Exploder,
Preset::TenCellRow,
Preset::LightweightSpaceship,
Preset::Tumbler,
Preset::GliderGun,
Preset::Acorn,
];
impl Preset {
pub fn life(self) -> Vec<(isize, isize)> {
#[rustfmt::skip]
let cells = match self {
Preset::Custom => vec![],
Preset::XKCD => vec![
" xxx ",
" x x ",
" x x ",
" x ",
"x xxx ",
" x x x ",
" x x",
" x x ",
" x x ",
],
Preset::Glider => vec![
" x ",
" x",
"xxx"
],
Preset::SmallExploder => vec![
" x ",
"xxx",
"x x",
" x ",
],
Preset::Exploder => vec![
"x x x",
"x x",
"x x",
"x x",
"x x x",
],
Preset::TenCellRow => vec![
"xxxxxxxxxx",
],
Preset::LightweightSpaceship => vec![
" xxxxx",
"x x",
" x",
"x x ",
],
Preset::Tumbler => vec![
" xx xx ",
" xx xx ",
" x x ",
"x x x x",
"x x x x",
"xx xx",
],
Preset::GliderGun => vec![
" x ",
" x x ",
" xx xx xx",
" x x xx xx",
"xx x x xx ",
"xx x x xx x x ",
" x x x ",
" x x ",
" xx ",
],
Preset::Acorn => vec![
" x ",
" x ",
"xx xxx",
],
};
let start_row = -(cells.len() as isize / 2);
cells
.into_iter()
.enumerate()
.flat_map(|(i, cells)| {
let start_column = -(cells.len() as isize / 2);
cells
.chars()
.enumerate()
.filter(|(_, c)| !c.is_whitespace())
.map(move |(j, _)| {
(start_row + i as isize, start_column + j as isize)
})
})
.collect()
}
}
impl Default for Preset {
fn default() -> Preset {
Preset::XKCD
}
}
impl std::fmt::Display for Preset {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Preset::Custom => "Custom",
Preset::XKCD => "xkcd #2293",
Preset::Glider => "Glider",
Preset::SmallExploder => "Small Exploder",
Preset::Exploder => "Exploder",
Preset::TenCellRow => "10 Cell Row",
Preset::LightweightSpaceship => "Lightweight spaceship",
Preset::Tumbler => "Tumbler",
Preset::GliderGun => "Gosper Glider Gun",
Preset::Acorn => "Acorn",
}
)
}
}

View File

@ -0,0 +1,188 @@
use iced::{button, container, pick_list, slider, Background, Color};
const ACTIVE: Color = Color::from_rgb(
0x72 as f32 / 255.0,
0x89 as f32 / 255.0,
0xDA as f32 / 255.0,
);
const DESTRUCTIVE: Color = Color::from_rgb(
0xC0 as f32 / 255.0,
0x47 as f32 / 255.0,
0x47 as f32 / 255.0,
);
const HOVERED: Color = Color::from_rgb(
0x67 as f32 / 255.0,
0x7B as f32 / 255.0,
0xC4 as f32 / 255.0,
);
const BACKGROUND: Color = Color::from_rgb(
0x2F as f32 / 255.0,
0x31 as f32 / 255.0,
0x36 as f32 / 255.0,
);
pub struct Container;
impl container::StyleSheet for Container {
fn style(&self) -> container::Style {
container::Style {
background: Some(Background::Color(Color::from_rgb8(
0x36, 0x39, 0x3F,
))),
text_color: Some(Color::WHITE),
..container::Style::default()
}
}
}
pub struct Button;
impl button::StyleSheet for Button {
fn active(&self) -> button::Style {
button::Style {
background: Some(Background::Color(ACTIVE)),
border_radius: 3.0,
text_color: Color::WHITE,
..button::Style::default()
}
}
fn hovered(&self) -> button::Style {
button::Style {
background: Some(Background::Color(HOVERED)),
text_color: Color::WHITE,
..self.active()
}
}
fn pressed(&self) -> button::Style {
button::Style {
border_width: 1.0,
border_color: Color::WHITE,
..self.hovered()
}
}
}
pub struct Clear;
impl button::StyleSheet for Clear {
fn active(&self) -> button::Style {
button::Style {
background: Some(Background::Color(DESTRUCTIVE)),
border_radius: 3.0,
text_color: Color::WHITE,
..button::Style::default()
}
}
fn hovered(&self) -> button::Style {
button::Style {
background: Some(Background::Color(Color {
a: 0.5,
..DESTRUCTIVE
})),
text_color: Color::WHITE,
..self.active()
}
}
fn pressed(&self) -> button::Style {
button::Style {
border_width: 1.0,
border_color: Color::WHITE,
..self.hovered()
}
}
}
pub struct Slider;
impl slider::StyleSheet for Slider {
fn active(&self) -> slider::Style {
slider::Style {
rail_colors: (ACTIVE, Color { a: 0.1, ..ACTIVE }),
handle: slider::Handle {
shape: slider::HandleShape::Circle { radius: 9.0 },
color: ACTIVE,
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
}
}
fn hovered(&self) -> slider::Style {
let active = self.active();
slider::Style {
handle: slider::Handle {
color: HOVERED,
..active.handle
},
..active
}
}
fn dragging(&self) -> slider::Style {
let active = self.active();
slider::Style {
handle: slider::Handle {
color: Color::from_rgb(0.85, 0.85, 0.85),
..active.handle
},
..active
}
}
}
pub struct PickList;
impl pick_list::StyleSheet for PickList {
fn menu(&self) -> pick_list::Menu {
pick_list::Menu {
text_color: Color::WHITE,
background: BACKGROUND.into(),
border_width: 1.0,
border_color: Color {
a: 0.7,
..Color::BLACK
},
selected_background: Color {
a: 0.5,
..Color::BLACK
}
.into(),
selected_text_color: Color::WHITE,
}
}
fn active(&self) -> pick_list::Style {
pick_list::Style {
text_color: Color::WHITE,
background: BACKGROUND.into(),
border_width: 1.0,
border_color: Color {
a: 0.6,
..Color::BLACK
},
border_radius: 2.0,
icon_size: 0.5,
}
}
fn hovered(&self) -> pick_list::Style {
let active = self.active();
pick_list::Style {
border_color: Color {
a: 0.9,
..Color::BLACK
},
..active
}
}
}

View File

@ -8,4 +8,4 @@ publish = false
[dependencies]
iced = { path = "../.." }
iced_native = { path = "../../native" }
iced_wgpu = { path = "../../wgpu" }
iced_graphics = { path = "../../graphics" }

View File

@ -10,13 +10,13 @@ mod rainbow {
// Of course, you can choose to make the implementation renderer-agnostic,
// if you wish to, by creating your own `Renderer` trait, which could be
// implemented by `iced_wgpu` and other renderers.
use iced_native::{
layout, Element, Hasher, Layout, Length, MouseCursor, Point, Size,
Widget,
};
use iced_wgpu::{
use iced_graphics::{
triangle::{Mesh2D, Vertex2D},
Defaults, Primitive, Renderer,
Backend, Defaults, Primitive, Renderer,
};
use iced_native::{
layout, mouse, Element, Hasher, Layout, Length, Point, Rectangle, Size,
Vector, Widget,
};
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 {
Length::Fill
}
@ -38,7 +41,7 @@ mod rainbow {
fn layout(
&self,
_renderer: &Renderer,
_renderer: &Renderer<B>,
limits: &layout::Limits,
) -> layout::Node {
let size = limits.width(Length::Fill).resolve(Size::ZERO);
@ -50,11 +53,12 @@ mod rainbow {
fn draw(
&self,
_renderer: &mut Renderer,
_renderer: &mut Renderer<B>,
_defaults: &Defaults,
layout: Layout<'_>,
cursor_position: Point,
) -> (Primitive, MouseCursor) {
_viewport: &Rectangle,
) -> (Primitive, mouse::Interaction) {
let b = layout.bounds();
// R O Y G B I V
@ -85,66 +89,72 @@ mod rainbow {
let posn_l = [0.0, b.height / 2.0];
(
Primitive::Mesh2D {
origin: Point::new(b.x, b.y),
buffers: Mesh2D {
vertices: vec![
Vertex2D {
position: posn_center,
color: [1.0, 1.0, 1.0, 1.0],
},
Vertex2D {
position: posn_tl,
color: color_r,
},
Vertex2D {
position: posn_t,
color: color_o,
},
Vertex2D {
position: posn_tr,
color: color_y,
},
Vertex2D {
position: posn_r,
color: color_g,
},
Vertex2D {
position: posn_br,
color: color_gb,
},
Vertex2D {
position: posn_b,
color: color_b,
},
Vertex2D {
position: posn_bl,
color: color_i,
},
Vertex2D {
position: posn_l,
color: color_v,
},
],
indices: vec![
0, 1, 2, // TL
0, 2, 3, // T
0, 3, 4, // TR
0, 4, 5, // R
0, 5, 6, // BR
0, 6, 7, // B
0, 7, 8, // BL
0, 8, 1, // L
],
},
Primitive::Translate {
translation: Vector::new(b.x, b.y),
content: Box::new(Primitive::Mesh2D {
size: b.size(),
buffers: Mesh2D {
vertices: vec![
Vertex2D {
position: posn_center,
color: [1.0, 1.0, 1.0, 1.0],
},
Vertex2D {
position: posn_tl,
color: color_r,
},
Vertex2D {
position: posn_t,
color: color_o,
},
Vertex2D {
position: posn_tr,
color: color_y,
},
Vertex2D {
position: posn_r,
color: color_g,
},
Vertex2D {
position: posn_br,
color: color_gb,
},
Vertex2D {
position: posn_b,
color: color_b,
},
Vertex2D {
position: posn_bl,
color: color_i,
},
Vertex2D {
position: posn_l,
color: color_v,
},
],
indices: vec![
0, 1, 2, // TL
0, 2, 3, // T
0, 3, 4, // TR
0, 4, 5, // R
0, 5, 6, // BR
0, 6, 7, // B
0, 7, 8, // BL
0, 8, 1, // L
],
},
}),
},
MouseCursor::OutOfBounds,
mouse::Interaction::default(),
)
}
}
impl<'a, Message> Into<Element<'a, Message, Renderer>> for Rainbow {
fn into(self) -> Element<'a, Message, Renderer> {
impl<'a, Message, B> Into<Element<'a, Message, Renderer<B>>> for Rainbow
where
B: Backend,
{
fn into(self) -> Element<'a, Message, Renderer<B>> {
Element::new(self)
}
}
@ -156,7 +166,7 @@ use iced::{
};
use rainbow::Rainbow;
pub fn main() {
pub fn main() -> iced::Result {
Example::run(Settings::default())
}

View File

@ -8,4 +8,4 @@ publish = false
[dependencies]
iced_winit = { path = "../../winit" }
iced_wgpu = { path = "../../wgpu" }
env_logger = "0.7"
env_logger = "0.8"

View File

@ -1,15 +1,15 @@
use crate::Scene;
use iced_wgpu::Renderer;
use iced_winit::{
slider, Align, Color, Column, Element, Length, Row, Slider, Text,
slider, Align, Clipboard, Color, Column, Command, Element, Length, Program,
Row, Slider, Text,
};
pub struct Controls {
background_color: Color,
sliders: [slider::State; 3],
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Message {
BackgroundColorChanged(Color),
}
@ -17,58 +17,69 @@ pub enum Message {
impl Controls {
pub fn new() -> Controls {
Controls {
background_color: Color::BLACK,
sliders: Default::default(),
}
}
pub fn update(&self, message: Message, scene: &mut Scene) {
pub fn background_color(&self) -> Color {
self.background_color
}
}
impl Program for Controls {
type Renderer = Renderer;
type Message = Message;
type Clipboard = Clipboard;
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
match message {
Message::BackgroundColorChanged(color) => {
scene.background_color = color;
self.background_color = color;
}
}
Command::none()
}
pub fn view(&mut self, scene: &Scene) -> Element<Message, Renderer> {
fn view(&mut self) -> Element<Message, Renderer> {
let [r, g, b] = &mut self.sliders;
let background_color = scene.background_color;
let background_color = self.background_color;
let sliders = Row::new()
.width(Length::Units(500))
.spacing(20)
.push(Slider::new(
r,
0.0..=1.0,
scene.background_color.r,
move |r| {
.push(
Slider::new(r, 0.0..=1.0, background_color.r, move |r| {
Message::BackgroundColorChanged(Color {
r,
..background_color
})
},
))
.push(Slider::new(
g,
0.0..=1.0,
scene.background_color.g,
move |g| {
})
.step(0.01),
)
.push(
Slider::new(g, 0.0..=1.0, background_color.g, move |g| {
Message::BackgroundColorChanged(Color {
g,
..background_color
})
},
))
.push(Slider::new(
b,
0.0..=1.0,
scene.background_color.b,
move |b| {
})
.step(0.01),
)
.push(
Slider::new(b, 0.0..=1.0, background_color.b, move |b| {
Message::BackgroundColorChanged(Color {
b,
..background_color
})
},
));
})
.step(0.01),
);
Row::new()
.width(Length::Fill)

View File

@ -4,12 +4,12 @@ mod scene;
use controls::Controls;
use scene::Scene;
use iced_wgpu::{
wgpu, window::SwapChain, Primitive, Renderer, Settings, Target,
};
use iced_winit::{winit, Cache, Clipboard, MouseCursor, Size, UserInterface};
use iced_wgpu::{wgpu, Backend, Renderer, Settings, Viewport};
use iced_winit::{conversion, futures, program, winit, Clipboard, Debug, Size};
use futures::task::SpawnExt;
use winit::{
dpi::PhysicalPosition,
event::{Event, ModifiersState, WindowEvent},
event_loop::{ControlFlow, EventLoop},
};
@ -20,45 +20,80 @@ pub fn main() {
// Initialize winit
let event_loop = EventLoop::new();
let window = winit::window::Window::new(&event_loop).unwrap();
let mut logical_size =
window.inner_size().to_logical(window.scale_factor());
let physical_size = window.inner_size();
let mut viewport = Viewport::with_physical_size(
Size::new(physical_size.width, physical_size.height),
window.scale_factor(),
);
let mut cursor_position = PhysicalPosition::new(-1.0, -1.0);
let mut modifiers = ModifiersState::default();
let mut clipboard = Clipboard::connect(&window);
// Initialize WGPU
let adapter = wgpu::Adapter::request(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::Default,
backends: wgpu::BackendBit::PRIMARY,
})
.expect("Request adapter");
// Initialize wgpu
let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY);
let surface = unsafe { instance.create_surface(&window) };
let (mut device, mut queue) =
adapter.request_device(&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions {
anisotropic_filtering: false,
},
limits: wgpu::Limits::default(),
});
let (mut device, queue) = futures::executor::block_on(async {
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
compatible_surface: Some(&surface),
})
.await
.expect("Request adapter");
adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
features: wgpu::Features::empty(),
limits: wgpu::Limits::default(),
},
None,
)
.await
.expect("Request device")
});
let surface = wgpu::Surface::create(&window);
let format = wgpu::TextureFormat::Bgra8UnormSrgb;
let mut swap_chain = {
let size = window.inner_size();
SwapChain::new(&device, &surface, format, size.width, size.height)
device.create_swap_chain(
&surface,
&wgpu::SwapChainDescriptor {
usage: wgpu::TextureUsage::RENDER_ATTACHMENT,
format: format,
width: size.width,
height: size.height,
present_mode: wgpu::PresentMode::Mailbox,
},
)
};
let mut resized = false;
// Initialize iced
let mut events = Vec::new();
let mut cache = Some(Cache::default());
let mut renderer = Renderer::new(&mut device, Settings::default());
let mut output = (Primitive::None, MouseCursor::OutOfBounds);
let clipboard = Clipboard::new(&window);
// Initialize staging belt and local pool
let mut staging_belt = wgpu::util::StagingBelt::new(5 * 1024);
let mut local_pool = futures::executor::LocalPool::new();
// Initialize scene and GUI controls
let mut scene = Scene::new(&device);
let mut controls = Controls::new();
let scene = Scene::new(&mut device);
let controls = Controls::new();
// Initialize iced
let mut debug = Debug::new();
let mut renderer =
Renderer::new(Backend::new(&mut device, Settings::default()));
let mut state = program::State::new(
controls,
viewport.logical_size(),
conversion::cursor_position(cursor_position, viewport.scale_factor()),
&mut renderer,
&mut debug,
);
// Run event loop
event_loop.run(move |event, _, control_flow| {
@ -68,18 +103,23 @@ pub fn main() {
match event {
Event::WindowEvent { event, .. } => {
match event {
WindowEvent::CursorMoved { position, .. } => {
cursor_position = position;
}
WindowEvent::ModifiersChanged(new_modifiers) => {
modifiers = new_modifiers;
}
WindowEvent::Resized(new_size) => {
logical_size =
new_size.to_logical(window.scale_factor());
viewport = Viewport::with_physical_size(
Size::new(new_size.width, new_size.height),
window.scale_factor(),
);
resized = true;
}
WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
_ => {}
}
@ -89,114 +129,95 @@ pub fn main() {
window.scale_factor(),
modifiers,
) {
events.push(event);
state.queue_event(event);
}
}
Event::MainEventsCleared => {
// If no relevant events happened, we can simply skip this
if events.is_empty() {
return;
}
// We need to:
// 1. Process events of our user interface.
// 2. Update state as a result of any interaction.
// 3. Generate a new output for our renderer.
// First, we build our user interface.
let mut user_interface = UserInterface::build(
controls.view(&scene),
Size::new(logical_size.width, logical_size.height),
cache.take().unwrap(),
&mut renderer,
);
// Then, we process the events, obtaining messages in return.
let messages = user_interface.update(
events.drain(..),
clipboard.as_ref().map(|c| c as _),
&renderer,
);
let user_interface = if messages.is_empty() {
// If there are no messages, no interactions we care about have
// happened. We can simply leave our user interface as it is.
user_interface
} else {
// If there are messages, we need to update our state
// accordingly and rebuild our user interface.
// We can only do this if we drop our user interface first
// by turning it into its cache.
cache = Some(user_interface.into_cache());
// In this example, `Controls` is the only part that cares
// about messages, so updating our state is pretty
// straightforward.
for message in messages {
controls.update(message, &mut scene);
}
// Once the state has been changed, we rebuild our updated
// user interface.
UserInterface::build(
controls.view(&scene),
Size::new(logical_size.width, logical_size.height),
cache.take().unwrap(),
// If there are events pending
if !state.is_queue_empty() {
// We update iced
let _ = state.update(
viewport.logical_size(),
conversion::cursor_position(
cursor_position,
viewport.scale_factor(),
),
&mut renderer,
)
};
&mut clipboard,
&mut debug,
);
// Finally, we just need to draw a new output for our renderer,
output = user_interface.draw(&mut renderer);
// update our cache,
cache = Some(user_interface.into_cache());
// and request a redraw
window.request_redraw();
// and request a redraw
window.request_redraw();
}
}
Event::RedrawRequested(_) => {
if resized {
let size = window.inner_size();
swap_chain = SwapChain::new(
&device,
swap_chain = device.create_swap_chain(
&surface,
format,
size.width,
size.height,
&wgpu::SwapChainDescriptor {
usage: wgpu::TextureUsage::RENDER_ATTACHMENT,
format: format,
width: size.width,
height: size.height,
present_mode: wgpu::PresentMode::Mailbox,
},
);
resized = false;
}
let (frame, viewport) = swap_chain.next_frame();
let frame = swap_chain.get_current_frame().expect("Next frame");
let mut encoder = device.create_command_encoder(
&wgpu::CommandEncoderDescriptor { todo: 0 },
&wgpu::CommandEncoderDescriptor { label: None },
);
// We draw the scene first
scene.draw(&mut encoder, &frame.view);
let program = state.program();
{
// We clear the frame
let mut render_pass = scene.clear(
&frame.output.view,
&mut encoder,
program.background_color(),
);
// Draw the scene
scene.draw(&mut render_pass);
}
// And then iced on top
let mouse_cursor = renderer.draw(
let mouse_interaction = renderer.backend_mut().draw(
&mut device,
&mut staging_belt,
&mut encoder,
Target {
texture: &frame.view,
viewport,
},
&output,
window.scale_factor(),
&["Some debug information!"],
&frame.output.view,
&viewport,
state.primitive(),
&debug.overlay(),
);
// Then we submit the work
queue.submit(&[encoder.finish()]);
staging_belt.finish();
queue.submit(Some(encoder.finish()));
// And update the mouse cursor
window.set_cursor_icon(iced_winit::conversion::mouse_cursor(
mouse_cursor,
));
// Update the mouse cursor
window.set_cursor_icon(
iced_winit::conversion::mouse_interaction(
mouse_interaction,
),
);
// And recall staging buffers
local_pool
.spawner()
.spawn(staging_belt.recall())
.expect("Recall staging buffers");
local_pool.run_until_stalled();
}
_ => {}
}

View File

@ -2,118 +2,98 @@ use iced_wgpu::wgpu;
use iced_winit::Color;
pub struct Scene {
pub background_color: Color,
pipeline: wgpu::RenderPipeline,
bind_group: wgpu::BindGroup,
}
impl Scene {
pub fn new(device: &wgpu::Device) -> Scene {
let (pipeline, bind_group) = build_pipeline(device);
let pipeline = build_pipeline(device);
Scene {
background_color: Color::BLACK,
pipeline,
bind_group,
}
Scene { pipeline }
}
pub fn draw(
pub fn clear<'a>(
&self,
encoder: &mut wgpu::CommandEncoder,
target: &wgpu::TextureView,
) {
let mut rpass =
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[
wgpu::RenderPassColorAttachmentDescriptor {
attachment: target,
resolve_target: None,
load_op: wgpu::LoadOp::Clear,
store_op: wgpu::StoreOp::Store,
clear_color: {
let [r, g, b, a] =
self.background_color.into_linear();
target: &'a wgpu::TextureView,
encoder: &'a mut wgpu::CommandEncoder,
background_color: Color,
) -> wgpu::RenderPass<'a> {
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
view: target,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear({
let [r, g, b, a] = background_color.into_linear();
wgpu::Color {
r: r as f64,
g: g as f64,
b: b as f64,
a: a as f64,
}
},
},
],
depth_stencil_attachment: None,
});
wgpu::Color {
r: r as f64,
g: g as f64,
b: b as f64,
a: a as f64,
}
}),
store: true,
},
}],
depth_stencil_attachment: None,
})
}
rpass.set_pipeline(&self.pipeline);
rpass.set_bind_group(0, &self.bind_group, &[]);
rpass.draw(0..3, 0..1);
pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
render_pass.set_pipeline(&self.pipeline);
render_pass.draw(0..3, 0..1);
}
}
fn build_pipeline(
device: &wgpu::Device,
) -> (wgpu::RenderPipeline, wgpu::BindGroup) {
let vs = include_bytes!("shader/vert.spv");
let fs = include_bytes!("shader/frag.spv");
fn build_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline {
let vs_module =
device.create_shader_module(&wgpu::include_spirv!("shader/vert.spv"));
let vs_module = device.create_shader_module(
&wgpu::read_spirv(std::io::Cursor::new(&vs[..])).unwrap(),
);
let fs_module = device.create_shader_module(
&wgpu::read_spirv(std::io::Cursor::new(&fs[..])).unwrap(),
);
let bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[],
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout,
bindings: &[],
});
let fs_module =
device.create_shader_module(&wgpu::include_spirv!("shader/frag.spv"));
let pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[&bind_group_layout],
label: None,
push_constant_ranges: &[],
bind_group_layouts: &[],
});
let pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
layout: &pipeline_layout,
vertex_stage: wgpu::ProgrammableStageDescriptor {
label: None,
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &vs_module,
entry_point: "main",
buffers: &[],
},
fragment_stage: Some(wgpu::ProgrammableStageDescriptor {
fragment: Some(wgpu::FragmentState {
module: &fs_module,
entry_point: "main",
targets: &[wgpu::ColorTargetState {
format: wgpu::TextureFormat::Bgra8UnormSrgb,
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent::REPLACE,
alpha: wgpu::BlendComponent::REPLACE,
}),
write_mask: wgpu::ColorWrite::ALL,
}],
}),
rasterization_state: Some(wgpu::RasterizationStateDescriptor {
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
front_face: wgpu::FrontFace::Ccw,
cull_mode: wgpu::CullMode::None,
depth_bias: 0,
depth_bias_slope_scale: 0.0,
depth_bias_clamp: 0.0,
}),
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
color_states: &[wgpu::ColorStateDescriptor {
format: wgpu::TextureFormat::Bgra8UnormSrgb,
color_blend: wgpu::BlendDescriptor::REPLACE,
alpha_blend: wgpu::BlendDescriptor::REPLACE,
write_mask: wgpu::ColorWrite::ALL,
}],
depth_stencil_state: None,
index_format: wgpu::IndexFormat::Uint16,
vertex_buffers: &[],
sample_count: 1,
sample_mask: !0,
alpha_to_coverage_enabled: false,
..Default::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
});
(pipeline, bind_group)
pipeline
}

View File

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

View File

@ -15,8 +15,8 @@ This example showcases the `PaneGrid` widget, which features:
The __[`main`]__ file contains all the code of the example.
<div align="center">
<a href="https://gfycat.com/mixedflatjellyfish">
<img src="https://thumbs.gfycat.com/MixedFlatJellyfish-small.gif">
<a href="https://gfycat.com/frailfreshairedaleterrier">
<img src="https://thumbs.gfycat.com/FrailFreshAiredaleterrier-small.gif">
</a>
</div>

View File

@ -1,16 +1,19 @@
use iced::{
button, keyboard, pane_grid, scrollable, Align, Button, Column, Container,
Element, HorizontalAlignment, Length, PaneGrid, Sandbox, Scrollable,
Settings, Text,
button, executor, keyboard, pane_grid, scrollable, Align, Application,
Button, Clipboard, Color, Column, Command, Container, Element,
HorizontalAlignment, Length, PaneGrid, Row, Scrollable, Settings,
Subscription, Text,
};
use iced_native::{event, subscription, Event};
pub fn main() {
pub fn main() -> iced::Result {
Example::run(Settings::default())
}
struct Example {
panes: pane_grid::State<Content>,
panes: pane_grid::State<Pane>,
panes_created: usize,
focus: Option<pane_grid::Pane>,
}
#[derive(Debug, Clone, Copy)]
@ -18,59 +21,82 @@ enum Message {
Split(pane_grid::Axis, pane_grid::Pane),
SplitFocused(pane_grid::Axis),
FocusAdjacent(pane_grid::Direction),
Clicked(pane_grid::Pane),
Dragged(pane_grid::DragEvent),
Resized(pane_grid::ResizeEvent),
TogglePin(pane_grid::Pane),
Close(pane_grid::Pane),
CloseFocused,
}
impl Sandbox for Example {
impl Application for Example {
type Message = Message;
type Executor = executor::Default;
type Flags = ();
fn new() -> Self {
let (panes, _) = pane_grid::State::new(Content::new(0));
fn new(_flags: ()) -> (Self, Command<Message>) {
let (panes, _) = pane_grid::State::new(Pane::new(0));
Example {
panes,
panes_created: 1,
}
(
Example {
panes,
panes_created: 1,
focus: None,
},
Command::none(),
)
}
fn title(&self) -> String {
String::from("Pane grid - Iced")
}
fn update(&mut self, message: Message) {
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
match message {
Message::Split(axis, pane) => {
let _ = self.panes.split(
let result = self.panes.split(
axis,
&pane,
Content::new(self.panes_created),
Pane::new(self.panes_created),
);
if let Some((pane, _)) = result {
self.focus = Some(pane);
}
self.panes_created += 1;
}
Message::SplitFocused(axis) => {
if let Some(pane) = self.panes.active() {
let _ = self.panes.split(
if let Some(pane) = self.focus {
let result = self.panes.split(
axis,
&pane,
Content::new(self.panes_created),
Pane::new(self.panes_created),
);
if let Some((pane, _)) = result {
self.focus = Some(pane);
}
self.panes_created += 1;
}
}
Message::FocusAdjacent(direction) => {
if let Some(pane) = self.panes.active() {
if let Some(pane) = self.focus {
if let Some(adjacent) =
self.panes.adjacent(&pane, direction)
{
self.panes.focus(&adjacent);
self.focus = Some(adjacent);
}
}
}
Message::Clicked(pane) => {
self.focus = Some(pane);
}
Message::Resized(pane_grid::ResizeEvent { split, ratio }) => {
self.panes.resize(&split, ratio);
}
@ -81,30 +107,97 @@ impl Sandbox for Example {
self.panes.swap(&pane, &target);
}
Message::Dragged(_) => {}
Message::TogglePin(pane) => {
if let Some(Pane { is_pinned, .. }) = self.panes.get_mut(&pane)
{
*is_pinned = !*is_pinned;
}
}
Message::Close(pane) => {
let _ = self.panes.close(&pane);
if let Some((_, sibling)) = self.panes.close(&pane) {
self.focus = Some(sibling);
}
}
Message::CloseFocused => {
if let Some(pane) = self.panes.active() {
let _ = self.panes.close(&pane);
if let Some(pane) = self.focus {
if let Some(Pane { is_pinned, .. }) = self.panes.get(&pane)
{
if !is_pinned {
if let Some((_, sibling)) = self.panes.close(&pane)
{
self.focus = Some(sibling);
}
}
}
}
}
}
Command::none()
}
fn subscription(&self) -> Subscription<Message> {
subscription::events_with(|event, status| {
if let event::Status::Captured = status {
return None;
}
match event {
Event::Keyboard(keyboard::Event::KeyPressed {
modifiers,
key_code,
}) if modifiers.is_command_pressed() => handle_hotkey(key_code),
_ => None,
}
})
}
fn view(&mut self) -> Element<Message> {
let focus = self.focus;
let total_panes = self.panes.len();
let pane_grid =
PaneGrid::new(&mut self.panes, |pane, content, focus| {
content.view(pane, focus, total_panes)
})
.width(Length::Fill)
.height(Length::Fill)
.spacing(10)
.on_drag(Message::Dragged)
.on_resize(Message::Resized)
.on_key_press(handle_hotkey);
let pane_grid = PaneGrid::new(&mut self.panes, |id, pane| {
let is_focused = focus == Some(id);
let text = if pane.is_pinned { "Unpin" } else { "Pin" };
let pin_button =
Button::new(&mut pane.pin_button, Text::new(text).size(14))
.on_press(Message::TogglePin(id))
.style(style::Button::Pin)
.padding(3);
let title = Row::with_children(vec![
pin_button.into(),
Text::new("Pane").into(),
Text::new(pane.content.id.to_string())
.color(if is_focused {
PANE_ID_COLOR_FOCUSED
} else {
PANE_ID_COLOR_UNFOCUSED
})
.into(),
])
.spacing(5);
let title_bar = pane_grid::TitleBar::new(title)
.controls(pane.controls.view(id, total_panes, pane.is_pinned))
.padding(10)
.style(style::TitleBar { is_focused });
pane_grid::Content::new(pane.content.view(
id,
total_panes,
pane.is_pinned,
))
.title_bar(title_bar)
.style(style::Pane { is_focused })
})
.width(Length::Fill)
.height(Length::Fill)
.spacing(10)
.on_click(Message::Clicked)
.on_drag(Message::Dragged)
.on_resize(10, Message::Resized);
Container::new(pane_grid)
.width(Length::Fill)
@ -114,11 +207,22 @@ impl Sandbox for Example {
}
}
fn handle_hotkey(event: pane_grid::KeyPressEvent) -> Option<Message> {
const PANE_ID_COLOR_UNFOCUSED: Color = Color::from_rgb(
0xFF as f32 / 255.0,
0xC7 as f32 / 255.0,
0xC7 as f32 / 255.0,
);
const PANE_ID_COLOR_FOCUSED: Color = Color::from_rgb(
0xFF as f32 / 255.0,
0x47 as f32 / 255.0,
0x47 as f32 / 255.0,
);
fn handle_hotkey(key_code: keyboard::KeyCode) -> Option<Message> {
use keyboard::KeyCode;
use pane_grid::{Axis, Direction};
let direction = match event.key_code {
let direction = match key_code {
KeyCode::Up => Some(Direction::Up),
KeyCode::Down => Some(Direction::Down),
KeyCode::Left => Some(Direction::Left),
@ -126,7 +230,7 @@ fn handle_hotkey(event: pane_grid::KeyPressEvent) -> Option<Message> {
_ => None,
};
match event.key_code {
match key_code {
KeyCode::V => Some(Message::SplitFocused(Axis::Vertical)),
KeyCode::H => Some(Message::SplitFocused(Axis::Horizontal)),
KeyCode::W => Some(Message::CloseFocused),
@ -134,6 +238,13 @@ fn handle_hotkey(event: pane_grid::KeyPressEvent) -> Option<Message> {
}
}
struct Pane {
pub is_pinned: bool,
pub pin_button: button::State,
pub content: Content,
pub controls: Controls,
}
struct Content {
id: usize,
scroll: scrollable::State,
@ -142,6 +253,21 @@ struct Content {
close: button::State,
}
struct Controls {
close: button::State,
}
impl Pane {
fn new(id: usize) -> Self {
Self {
is_pinned: false,
pin_button: button::State::new(),
content: Content::new(id),
controls: Controls::new(),
}
}
}
impl Content {
fn new(id: usize) -> Self {
Content {
@ -155,15 +281,15 @@ impl Content {
fn view(
&mut self,
pane: pane_grid::Pane,
focus: Option<pane_grid::Focus>,
total_panes: usize,
is_pinned: bool,
) -> Element<Message> {
let Content {
id,
scroll,
split_horizontally,
split_vertically,
close,
..
} = self;
let button = |state, label, message, style| {
@ -196,7 +322,7 @@ impl Content {
style::Button::Primary,
));
if total_panes > 1 {
if total_panes > 1 && !is_pinned {
controls = controls.push(button(
close,
"Close",
@ -209,7 +335,6 @@ impl Content {
.width(Length::Fill)
.spacing(10)
.align_items(Align::Center)
.push(Text::new(format!("Pane {}", id)).size(30))
.push(controls);
Container::new(content)
@ -217,14 +342,36 @@ impl Content {
.height(Length::Fill)
.padding(5)
.center_y()
.style(style::Pane {
is_focused: focus.is_some(),
})
.into()
}
}
impl Controls {
fn new() -> Self {
Self {
close: button::State::new(),
}
}
pub fn view(
&mut self,
pane: pane_grid::Pane,
total_panes: usize,
is_pinned: bool,
) -> Element<Message> {
let mut button =
Button::new(&mut self.close, Text::new("Close").size(14))
.style(style::Button::Control)
.padding(3);
if total_panes > 1 && !is_pinned {
button = button.on_press(Message::Close(pane));
}
button.into()
}
}
mod style {
use crate::PANE_ID_COLOR_FOCUSED;
use iced::{button, container, Background, Color, Vector};
const SURFACE: Color = Color::from_rgb(
@ -245,6 +392,25 @@ mod style {
0xC4 as f32 / 255.0,
);
pub struct TitleBar {
pub is_focused: bool,
}
impl container::StyleSheet for TitleBar {
fn style(&self) -> container::Style {
let pane = Pane {
is_focused: self.is_focused,
}
.style();
container::Style {
text_color: Some(Color::WHITE),
background: Some(pane.border_color.into()),
..Default::default()
}
}
}
pub struct Pane {
pub is_focused: bool,
}
@ -253,10 +419,11 @@ mod style {
fn style(&self) -> container::Style {
container::Style {
background: Some(Background::Color(SURFACE)),
border_width: 2,
border_color: Color {
a: if self.is_focused { 1.0 } else { 0.3 },
..Color::BLACK
border_width: 2.0,
border_color: if self.is_focused {
Color::BLACK
} else {
Color::from_rgb(0.7, 0.7, 0.7)
},
..Default::default()
}
@ -266,6 +433,8 @@ mod style {
pub enum Button {
Primary,
Destructive,
Control,
Pin,
}
impl button::StyleSheet for Button {
@ -275,12 +444,14 @@ mod style {
Button::Destructive => {
(None, Color::from_rgb8(0xFF, 0x47, 0x47))
}
Button::Control => (Some(PANE_ID_COLOR_FOCUSED), Color::WHITE),
Button::Pin => (Some(ACTIVE), Color::WHITE),
};
button::Style {
text_color,
background: background.map(Background::Color),
border_radius: 5,
border_radius: 5.0,
shadow_offset: Vector::new(0.0, 0.0),
..button::Style::default()
}
@ -295,6 +466,8 @@ mod style {
a: 0.2,
..active.text_color
}),
Button::Control => Some(PANE_ID_COLOR_FOCUSED),
Button::Pin => Some(HOVERED),
};
button::Style {

View File

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

View File

@ -0,0 +1,18 @@
## Pick-list
A dropdown list of selectable options.
It displays and positions an overlay based on the window position of the widget.
The __[`main`]__ file contains all the code of the example.
<div align="center">
<img src="https://user-images.githubusercontent.com/518289/87125075-2c232e80-c28a-11ea-95c2-769c610b8843.gif">
</div>
You can run it with `cargo run`:
```
cargo run --package pick_list
```
[`main`]: src/main.rs

View File

@ -0,0 +1,113 @@
use iced::{
pick_list, scrollable, Align, Container, Element, Length, PickList,
Sandbox, Scrollable, Settings, Space, Text,
};
pub fn main() -> iced::Result {
Example::run(Settings::default())
}
#[derive(Default)]
struct Example {
scroll: scrollable::State,
pick_list: pick_list::State<Language>,
selected_language: Language,
}
#[derive(Debug, Clone, Copy)]
enum Message {
LanguageSelected(Language),
}
impl Sandbox for Example {
type Message = Message;
fn new() -> Self {
Self::default()
}
fn title(&self) -> String {
String::from("Pick list - Iced")
}
fn update(&mut self, message: Message) {
match message {
Message::LanguageSelected(language) => {
self.selected_language = language;
}
}
}
fn view(&mut self) -> Element<Message> {
let pick_list = PickList::new(
&mut self.pick_list,
&Language::ALL[..],
Some(self.selected_language),
Message::LanguageSelected,
);
let mut content = Scrollable::new(&mut self.scroll)
.width(Length::Fill)
.align_items(Align::Center)
.spacing(10)
.push(Space::with_height(Length::Units(600)))
.push(Text::new("Which is your favorite language?"))
.push(pick_list);
content = content.push(Space::with_height(Length::Units(600)));
Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Language {
Rust,
Elm,
Ruby,
Haskell,
C,
Javascript,
Other,
}
impl Language {
const ALL: [Language; 7] = [
Language::C,
Language::Elm,
Language::Ruby,
Language::Haskell,
Language::Rust,
Language::Javascript,
Language::Other,
];
}
impl Default for Language {
fn default() -> Language {
Language::Rust
}
}
impl std::fmt::Display for Language {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Language::Rust => "Rust",
Language::Elm => "Elm",
Language::Ruby => "Ruby",
Language::Haskell => "Haskell",
Language::C => "C",
Language::Javascript => "Javascript",
Language::Other => "Some other language",
}
)
}
}

View File

@ -6,7 +6,7 @@ edition = "2018"
publish = false
[dependencies]
iced = { path = "../..", features = ["image", "debug", "tokio"] }
iced = { path = "../..", features = ["image", "debug", "tokio_old"] }
serde_json = "1.0"
[dependencies.serde]

View File

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

View File

@ -1,6 +1,6 @@
use iced::{slider, Column, Element, ProgressBar, Sandbox, Settings, Slider};
pub fn main() {
pub fn main() -> iced::Result {
Progress::run(Settings::default())
}
@ -36,12 +36,15 @@ impl Sandbox for Progress {
Column::new()
.padding(20)
.push(ProgressBar::new(0.0..=100.0, self.value))
.push(Slider::new(
&mut self.progress_bar_slider,
0.0..=100.0,
self.value,
Message::SliderChanged,
))
.push(
Slider::new(
&mut self.progress_bar_slider,
0.0..=100.0,
self.value,
Message::SliderChanged,
)
.step(0.01),
)
.into()
}
}

View File

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

View File

@ -0,0 +1,18 @@
## QR Code Generator
A basic QR code generator that showcases the `QRCode` widget.
The __[`main`]__ file contains all the code of the example.
<div align="center">
<a href="https://gfycat.com/heavyexhaustedaracari">
<img src="https://thumbs.gfycat.com/HeavyExhaustedAracari-size_restricted.gif">
</a>
</div>
You can run it with `cargo run`:
```
cargo run --package qr_code
```
[`main`]: src/main.rs

View File

@ -0,0 +1,81 @@
use iced::qr_code::{self, QRCode};
use iced::text_input::{self, TextInput};
use iced::{
Align, Column, Container, Element, Length, Sandbox, Settings, Text,
};
pub fn main() -> iced::Result {
QRGenerator::run(Settings::default())
}
#[derive(Default)]
struct QRGenerator {
data: String,
input: text_input::State,
qr_code: Option<qr_code::State>,
}
#[derive(Debug, Clone)]
enum Message {
DataChanged(String),
}
impl Sandbox for QRGenerator {
type Message = Message;
fn new() -> Self {
QRGenerator {
qr_code: qr_code::State::new("").ok(),
..Self::default()
}
}
fn title(&self) -> String {
String::from("QR Code Generator - Iced")
}
fn update(&mut self, message: Message) {
match message {
Message::DataChanged(mut data) => {
data.truncate(100);
self.qr_code = qr_code::State::new(&data).ok();
self.data = data;
}
}
}
fn view(&mut self) -> Element<Message> {
let title = Text::new("QR Code Generator")
.size(70)
.color([0.5, 0.5, 0.5]);
let input = TextInput::new(
&mut self.input,
"Type the data of your QR code here...",
&self.data,
Message::DataChanged,
)
.size(30)
.padding(15);
let mut content = Column::new()
.width(Length::Units(700))
.spacing(20)
.align_items(Align::Center)
.push(title)
.push(input);
if let Some(qr_code) = self.qr_code.as_mut() {
content = content.push(QRCode::new(qr_code).cell_size(10));
}
Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.padding(20)
.center_x()
.center_y()
.into()
}
}

View File

@ -0,0 +1,9 @@
[package]
name = "scrollable"
version = "0.1.0"
authors = ["Clark Moody <clark@clarkmoody.com>"]
edition = "2018"
publish = false
[dependencies]
iced = { path = "../..", features = ["debug"] }

View File

@ -0,0 +1,15 @@
# Scrollable
An example showcasing the various size and style options for the Scrollable.
All the example code is located in the __[`main`](src/main.rs)__ file.
<div align="center">
<a href="./screenshot.png">
<img src="./screenshot.png" height="640px">
</a>
</div>
You can run it with `cargo run`:
```
cargo run --package scrollable
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

View File

@ -0,0 +1,255 @@
mod style;
use iced::{
button, scrollable, Button, Column, Container, Element, Length,
ProgressBar, Radio, Row, Rule, Sandbox, Scrollable, Settings, Space, Text,
};
pub fn main() -> iced::Result {
ScrollableDemo::run(Settings::default())
}
struct ScrollableDemo {
theme: style::Theme,
variants: Vec<Variant>,
}
#[derive(Debug, Clone)]
enum Message {
ThemeChanged(style::Theme),
ScrollToTop(usize),
ScrollToBottom(usize),
Scrolled(usize, f32),
}
impl Sandbox for ScrollableDemo {
type Message = Message;
fn new() -> Self {
ScrollableDemo {
theme: Default::default(),
variants: Variant::all(),
}
}
fn title(&self) -> String {
String::from("Scrollable - Iced")
}
fn update(&mut self, message: Message) {
match message {
Message::ThemeChanged(theme) => self.theme = theme,
Message::ScrollToTop(i) => {
if let Some(variant) = self.variants.get_mut(i) {
variant.scrollable.snap_to(0.0);
variant.latest_offset = 0.0;
}
}
Message::ScrollToBottom(i) => {
if let Some(variant) = self.variants.get_mut(i) {
variant.scrollable.snap_to(1.0);
variant.latest_offset = 1.0;
}
}
Message::Scrolled(i, offset) => {
if let Some(variant) = self.variants.get_mut(i) {
variant.latest_offset = offset;
}
}
}
}
fn view(&mut self) -> Element<Message> {
let ScrollableDemo {
theme, variants, ..
} = self;
let choose_theme = style::Theme::ALL.iter().fold(
Column::new().spacing(10).push(Text::new("Choose a theme:")),
|column, option| {
column.push(
Radio::new(
*option,
&format!("{:?}", option),
Some(*theme),
Message::ThemeChanged,
)
.style(*theme),
)
},
);
let scrollable_row = Row::with_children(
variants
.iter_mut()
.enumerate()
.map(|(i, variant)| {
let mut scrollable =
Scrollable::new(&mut variant.scrollable)
.padding(10)
.spacing(10)
.width(Length::Fill)
.height(Length::Fill)
.on_scroll(move |offset| {
Message::Scrolled(i, offset)
})
.style(*theme)
.push(Text::new(variant.title))
.push(
Button::new(
&mut variant.scroll_to_bottom,
Text::new("Scroll to bottom"),
)
.width(Length::Fill)
.padding(10)
.on_press(Message::ScrollToBottom(i)),
);
if let Some(scrollbar_width) = variant.scrollbar_width {
scrollable = scrollable
.scrollbar_width(scrollbar_width)
.push(Text::new(format!(
"scrollbar_width: {:?}",
scrollbar_width
)));
}
if let Some(scrollbar_margin) = variant.scrollbar_margin {
scrollable = scrollable
.scrollbar_margin(scrollbar_margin)
.push(Text::new(format!(
"scrollbar_margin: {:?}",
scrollbar_margin
)));
}
if let Some(scroller_width) = variant.scroller_width {
scrollable = scrollable
.scroller_width(scroller_width)
.push(Text::new(format!(
"scroller_width: {:?}",
scroller_width
)));
}
scrollable = scrollable
.push(Space::with_height(Length::Units(100)))
.push(Text::new(
"Some content that should wrap within the \
scrollable. Let's output a lot of short words, so \
that we'll make sure to see how wrapping works \
with these scrollbars.",
))
.push(Space::with_height(Length::Units(1200)))
.push(Text::new("Middle"))
.push(Space::with_height(Length::Units(1200)))
.push(Text::new("The End."))
.push(
Button::new(
&mut variant.scroll_to_top,
Text::new("Scroll to top"),
)
.width(Length::Fill)
.padding(10)
.on_press(Message::ScrollToTop(i)),
);
Column::new()
.width(Length::Fill)
.height(Length::Fill)
.spacing(10)
.push(
Container::new(scrollable)
.width(Length::Fill)
.height(Length::Fill)
.style(*theme),
)
.push(ProgressBar::new(
0.0..=1.0,
variant.latest_offset,
))
.into()
})
.collect(),
)
.spacing(20)
.width(Length::Fill)
.height(Length::Fill);
let content = Column::new()
.spacing(20)
.padding(20)
.push(choose_theme)
.push(Rule::horizontal(20).style(self.theme))
.push(scrollable_row);
Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.style(self.theme)
.into()
}
}
/// A version of a scrollable
struct Variant {
title: &'static str,
scrollable: scrollable::State,
scroll_to_top: button::State,
scroll_to_bottom: button::State,
scrollbar_width: Option<u16>,
scrollbar_margin: Option<u16>,
scroller_width: Option<u16>,
latest_offset: f32,
}
impl Variant {
pub fn all() -> Vec<Self> {
vec![
Self {
title: "Default Scrollbar",
scrollable: scrollable::State::new(),
scroll_to_top: button::State::new(),
scroll_to_bottom: button::State::new(),
scrollbar_width: None,
scrollbar_margin: None,
scroller_width: None,
latest_offset: 0.0,
},
Self {
title: "Slimmed & Margin",
scrollable: scrollable::State::new(),
scroll_to_top: button::State::new(),
scroll_to_bottom: button::State::new(),
scrollbar_width: Some(4),
scrollbar_margin: Some(3),
scroller_width: Some(4),
latest_offset: 0.0,
},
Self {
title: "Wide Scroller",
scrollable: scrollable::State::new(),
scroll_to_top: button::State::new(),
scroll_to_bottom: button::State::new(),
scrollbar_width: Some(4),
scrollbar_margin: None,
scroller_width: Some(10),
latest_offset: 0.0,
},
Self {
title: "Narrow Scroller",
scrollable: scrollable::State::new(),
scroll_to_top: button::State::new(),
scroll_to_bottom: button::State::new(),
scrollbar_width: Some(10),
scrollbar_margin: None,
scroller_width: Some(4),
latest_offset: 0.0,
},
]
}
}

View File

@ -0,0 +1,190 @@
use iced::{container, radio, rule, scrollable};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Theme {
Light,
Dark,
}
impl Theme {
pub const ALL: [Theme; 2] = [Theme::Light, Theme::Dark];
}
impl Default for Theme {
fn default() -> Theme {
Theme::Light
}
}
impl From<Theme> for Box<dyn container::StyleSheet> {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
Theme::Dark => dark::Container.into(),
}
}
}
impl From<Theme> for Box<dyn radio::StyleSheet> {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
Theme::Dark => dark::Radio.into(),
}
}
}
impl From<Theme> for Box<dyn scrollable::StyleSheet> {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
Theme::Dark => dark::Scrollable.into(),
}
}
}
impl From<Theme> for Box<dyn rule::StyleSheet> {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
Theme::Dark => dark::Rule.into(),
}
}
}
mod dark {
use iced::{container, radio, rule, scrollable, Color};
const BACKGROUND: Color = Color::from_rgb(
0x36 as f32 / 255.0,
0x39 as f32 / 255.0,
0x3F as f32 / 255.0,
);
const SURFACE: Color = Color::from_rgb(
0x40 as f32 / 255.0,
0x44 as f32 / 255.0,
0x4B as f32 / 255.0,
);
const ACCENT: Color = Color::from_rgb(
0x6F as f32 / 255.0,
0xFF as f32 / 255.0,
0xE9 as f32 / 255.0,
);
const ACTIVE: Color = Color::from_rgb(
0x72 as f32 / 255.0,
0x89 as f32 / 255.0,
0xDA as f32 / 255.0,
);
const SCROLLBAR: Color = Color::from_rgb(
0x2E as f32 / 255.0,
0x33 as f32 / 255.0,
0x38 as f32 / 255.0,
);
const SCROLLER: Color = Color::from_rgb(
0x20 as f32 / 255.0,
0x22 as f32 / 255.0,
0x25 as f32 / 255.0,
);
pub struct Container;
impl container::StyleSheet for Container {
fn style(&self) -> container::Style {
container::Style {
background: Color {
a: 0.99,
..BACKGROUND
}
.into(),
text_color: Color::WHITE.into(),
..container::Style::default()
}
}
}
pub struct Radio;
impl radio::StyleSheet for Radio {
fn active(&self) -> radio::Style {
radio::Style {
background: SURFACE.into(),
dot_color: ACTIVE,
border_width: 1.0,
border_color: ACTIVE,
}
}
fn hovered(&self) -> radio::Style {
radio::Style {
background: Color { a: 0.5, ..SURFACE }.into(),
..self.active()
}
}
}
pub struct Scrollable;
impl scrollable::StyleSheet for Scrollable {
fn active(&self) -> scrollable::Scrollbar {
scrollable::Scrollbar {
background: Color {
a: 0.8,
..SCROLLBAR
}
.into(),
border_radius: 2.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
scroller: scrollable::Scroller {
color: Color { a: 0.7, ..SCROLLER },
border_radius: 2.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
}
}
fn hovered(&self) -> scrollable::Scrollbar {
let active = self.active();
scrollable::Scrollbar {
background: SCROLLBAR.into(),
scroller: scrollable::Scroller {
color: SCROLLER,
..active.scroller
},
..active
}
}
fn dragging(&self) -> scrollable::Scrollbar {
let hovered = self.hovered();
scrollable::Scrollbar {
scroller: scrollable::Scroller {
color: ACCENT,
..hovered.scroller
},
..hovered
}
}
}
pub struct Rule;
impl rule::StyleSheet for Rule {
fn style(&self) -> rule::Style {
rule::Style {
color: SURFACE,
width: 2,
radius: 1.0,
fill_mode: rule::FillMode::Percent(30.0),
}
}
}
}

View File

@ -5,11 +5,6 @@ authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2018"
publish = false
[features]
canvas = []
[dependencies]
iced = { path = "../..", features = ["canvas", "async-std", "debug"] }
iced_native = { path = "../../native" }
async-std = { version = "1.0", features = ["unstable"] }
rand = "0.7"
iced = { path = "../..", features = ["canvas", "tokio", "debug"] }
rand = "0.8.3"

View File

@ -7,13 +7,14 @@
//!
//! [1]: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations#An_animated_solar_system
use iced::{
canvas, executor, window, Application, Canvas, Color, Command, Container,
Element, Length, Point, Settings, Size, Subscription, Vector,
canvas::{self, Cursor, Path, Stroke},
executor, time, window, Application, Canvas, Clipboard, Color, Command,
Element, Length, Point, Rectangle, Settings, Size, Subscription, Vector,
};
use std::time::Instant;
pub fn main() {
pub fn main() -> iced::Result {
SolarSystem::run(Settings {
antialiasing: true,
..Settings::default()
@ -22,7 +23,6 @@ pub fn main() {
struct SolarSystem {
state: State,
solar_system: canvas::layer::Cache<State>,
}
#[derive(Debug, Clone, Copy)]
@ -39,7 +39,6 @@ impl Application for SolarSystem {
(
SolarSystem {
state: State::new(),
solar_system: canvas::layer::Cache::new(),
},
Command::none(),
)
@ -49,11 +48,14 @@ impl Application for SolarSystem {
String::from("Solar system - Iced")
}
fn update(&mut self, message: Message) -> Command<Message> {
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
match message {
Message::Tick(instant) => {
self.state.update(instant);
self.solar_system.clear();
}
}
@ -66,24 +68,20 @@ impl Application for SolarSystem {
}
fn view(&mut self) -> Element<Message> {
let canvas = Canvas::new()
Canvas::new(&mut self.state)
.width(Length::Fill)
.height(Length::Fill)
.push(self.solar_system.with(&self.state));
Container::new(canvas)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
}
#[derive(Debug)]
struct State {
space_cache: canvas::Cache,
system_cache: canvas::Cache,
cursor_position: Point,
start: Instant,
current: Instant,
now: Instant,
stars: Vec<(Point, f32)>,
}
@ -99,150 +97,120 @@ impl State {
let (width, height) = window::Settings::default().size;
State {
space_cache: Default::default(),
system_cache: Default::default(),
cursor_position: Point::ORIGIN,
start: now,
current: now,
stars: {
use rand::Rng;
let mut rng = rand::thread_rng();
(0..100)
.map(|_| {
(
Point::new(
rng.gen_range(0.0, width as f32),
rng.gen_range(0.0, height as f32),
),
rng.gen_range(0.5, 1.0),
)
})
.collect()
},
now,
stars: Self::generate_stars(width, height),
}
}
pub fn update(&mut self, now: Instant) {
self.current = now;
self.now = now;
self.system_cache.clear();
}
fn generate_stars(width: u32, height: u32) -> Vec<(Point, f32)> {
use rand::Rng;
let mut rng = rand::thread_rng();
(0..100)
.map(|_| {
(
Point::new(
rng.gen_range(
(-(width as f32) / 2.0)..(width as f32 / 2.0),
),
rng.gen_range(
(-(height as f32) / 2.0)..(height as f32 / 2.0),
),
),
rng.gen_range(0.5..1.0),
)
})
.collect()
}
}
impl canvas::Drawable for State {
fn draw(&self, frame: &mut canvas::Frame) {
use canvas::{Fill, Path, Stroke};
impl<Message> canvas::Program<Message> for State {
fn draw(
&self,
bounds: Rectangle,
_cursor: Cursor,
) -> Vec<canvas::Geometry> {
use std::f32::consts::PI;
let center = frame.center();
let background = self.space_cache.draw(bounds.size(), |frame| {
let space = Path::rectangle(Point::new(0.0, 0.0), frame.size());
let space = Path::new(|path| {
path.rectangle(Point::new(0.0, 0.0), frame.size())
});
let stars = Path::new(|path| {
for (p, size) in &self.stars {
path.rectangle(*p, Size::new(*size, *size));
}
});
let sun = Path::new(|path| path.circle(center, Self::SUN_RADIUS));
let orbit = Path::new(|path| path.circle(center, Self::ORBIT_RADIUS));
frame.fill(&space, Fill::Color(Color::BLACK));
frame.fill(&stars, Fill::Color(Color::WHITE));
frame.fill(&sun, Fill::Color(Color::from_rgb8(0xF9, 0xD7, 0x1C)));
frame.stroke(
&orbit,
Stroke {
width: 1.0,
color: Color::from_rgba8(0, 153, 255, 0.1),
..Stroke::default()
},
);
let elapsed = self.current - self.start;
let elapsed_seconds = elapsed.as_secs() as f32;
let elapsed_millis = elapsed.subsec_millis() as f32;
frame.with_save(|frame| {
frame.translate(Vector::new(center.x, center.y));
frame.rotate(
(2.0 * PI / 60.0) * elapsed_seconds
+ (2.0 * PI / 60_000.0) * elapsed_millis,
);
frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0));
let earth = Path::new(|path| {
path.circle(Point::ORIGIN, Self::EARTH_RADIUS)
let stars = Path::new(|path| {
for (p, size) in &self.stars {
path.rectangle(*p, Size::new(*size, *size));
}
});
let shadow = Path::new(|path| {
path.rectangle(
frame.fill(&space, Color::BLACK);
frame.translate(frame.center() - Point::ORIGIN);
frame.fill(&stars, Color::WHITE);
});
let system = self.system_cache.draw(bounds.size(), |frame| {
let center = frame.center();
let sun = Path::circle(center, Self::SUN_RADIUS);
let orbit = Path::circle(center, Self::ORBIT_RADIUS);
frame.fill(&sun, Color::from_rgb8(0xF9, 0xD7, 0x1C));
frame.stroke(
&orbit,
Stroke {
width: 1.0,
color: Color::from_rgba8(0, 153, 255, 0.1),
..Stroke::default()
},
);
let elapsed = self.now - self.start;
let rotation = (2.0 * PI / 60.0) * elapsed.as_secs() as f32
+ (2.0 * PI / 60_000.0) * elapsed.subsec_millis() as f32;
frame.with_save(|frame| {
frame.translate(Vector::new(center.x, center.y));
frame.rotate(rotation);
frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0));
let earth = Path::circle(Point::ORIGIN, Self::EARTH_RADIUS);
let shadow = Path::rectangle(
Point::new(0.0, -Self::EARTH_RADIUS),
Size::new(
Self::EARTH_RADIUS * 4.0,
Self::EARTH_RADIUS * 2.0,
),
)
});
frame.fill(&earth, Fill::Color(Color::from_rgb8(0x6B, 0x93, 0xD6)));
frame.with_save(|frame| {
frame.rotate(
((2.0 * PI) / 6.0) * elapsed_seconds
+ ((2.0 * PI) / 6_000.0) * elapsed_millis,
);
frame.translate(Vector::new(0.0, Self::MOON_DISTANCE));
let moon = Path::new(|path| {
path.circle(Point::ORIGIN, Self::MOON_RADIUS)
frame.fill(&earth, Color::from_rgb8(0x6B, 0x93, 0xD6));
frame.with_save(|frame| {
frame.rotate(rotation * 10.0);
frame.translate(Vector::new(0.0, Self::MOON_DISTANCE));
let moon = Path::circle(Point::ORIGIN, Self::MOON_RADIUS);
frame.fill(&moon, Color::WHITE);
});
frame.fill(&moon, Fill::Color(Color::WHITE));
frame.fill(
&shadow,
Color {
a: 0.7,
..Color::BLACK
},
);
});
frame.fill(
&shadow,
Fill::Color(Color {
a: 0.7,
..Color::BLACK
}),
);
});
}
}
mod time {
use iced::futures;
use std::time::Instant;
pub fn every(duration: std::time::Duration) -> iced::Subscription<Instant> {
iced::Subscription::from_recipe(Every(duration))
}
struct Every(std::time::Duration);
impl<H, I> iced_native::subscription::Recipe<H, I> for Every
where
H: std::hash::Hasher,
{
type Output = Instant;
fn hash(&self, state: &mut H) {
use std::hash::Hash;
std::any::TypeId::of::<Self>().hash(state);
self.0.hash(state);
}
fn stream(
self: Box<Self>,
_input: futures::stream::BoxStream<'static, I>,
) -> futures::stream::BoxStream<'static, Self::Output> {
use futures::stream::StreamExt;
async_std::stream::interval(self.0)
.map(|_| Instant::now())
.boxed()
}
vec![background, system]
}
}

View File

@ -6,7 +6,4 @@ edition = "2018"
publish = false
[dependencies]
iced = { path = "../.." }
iced_native = { path = "../../native" }
iced_futures = { path = "../../futures", features = ["async-std"] }
async-std = { version = "1.0", features = ["unstable"] }
iced = { path = "../..", features = ["smol"] }

View File

@ -1,10 +1,11 @@
use iced::{
button, Align, Application, Button, Column, Command, Container, Element,
HorizontalAlignment, Length, Row, Settings, Subscription, Text,
button, executor, time, Align, Application, Button, Clipboard, Column,
Command, Container, Element, HorizontalAlignment, Length, Row, Settings,
Subscription, Text,
};
use std::time::{Duration, Instant};
pub fn main() {
pub fn main() -> iced::Result {
Stopwatch::run(Settings::default())
}
@ -28,7 +29,7 @@ enum Message {
}
impl Application for Stopwatch {
type Executor = iced_futures::executor::AsyncStd;
type Executor = executor::Default;
type Message = Message;
type Flags = ();
@ -48,7 +49,11 @@ impl Application for Stopwatch {
String::from("Stopwatch - Iced")
}
fn update(&mut self, message: Message) -> Command<Message> {
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
match message {
Message::Toggle => match self.state {
State::Idle => {
@ -143,43 +148,6 @@ impl Application for Stopwatch {
}
}
mod time {
use iced::futures;
pub fn every(
duration: std::time::Duration,
) -> iced::Subscription<std::time::Instant> {
iced::Subscription::from_recipe(Every(duration))
}
struct Every(std::time::Duration);
impl<H, I> iced_native::subscription::Recipe<H, I> for Every
where
H: std::hash::Hasher,
{
type Output = std::time::Instant;
fn hash(&self, state: &mut H) {
use std::hash::Hash;
std::any::TypeId::of::<Self>().hash(state);
self.0.hash(state);
}
fn stream(
self: Box<Self>,
_input: futures::stream::BoxStream<'static, I>,
) -> futures::stream::BoxStream<'static, Self::Output> {
use futures::stream::StreamExt;
async_std::stream::interval(self.0)
.map(|_| std::time::Instant::now())
.boxed()
}
}
}
mod style {
use iced::{button, Background, Color, Vector};
@ -197,7 +165,7 @@ mod style {
Button::Secondary => Color::from_rgb(0.5, 0.5, 0.5),
Button::Destructive => Color::from_rgb(0.8, 0.2, 0.2),
})),
border_radius: 12,
border_radius: 12.0,
shadow_offset: Vector::new(1.0, 1.0),
text_color: Color::WHITE,
..button::Style::default()

View File

@ -1,10 +1,10 @@
use iced::{
button, scrollable, slider, text_input, Align, Button, Checkbox, Column,
Container, Element, Length, ProgressBar, Radio, Row, Sandbox, Scrollable,
Settings, Slider, Space, Text, TextInput,
Container, Element, Length, ProgressBar, Radio, Row, Rule, Sandbox,
Scrollable, Settings, Slider, Space, Text, TextInput, Toggler,
};
pub fn main() {
pub fn main() -> iced::Result {
Styling::run(Settings::default())
}
@ -17,7 +17,8 @@ struct Styling {
button: button::State,
slider: slider::State,
slider_value: f32,
toggle_value: bool,
checkbox_value: bool,
toggler_value: bool,
}
#[derive(Debug, Clone)]
@ -27,6 +28,7 @@ enum Message {
ButtonPressed,
SliderChanged(f32),
CheckboxToggled(bool),
TogglerToggled(bool),
}
impl Sandbox for Styling {
@ -44,9 +46,10 @@ impl Sandbox for Styling {
match message {
Message::ThemeChanged(theme) => self.theme = theme,
Message::InputChanged(value) => self.input_value = value,
Message::ButtonPressed => (),
Message::ButtonPressed => {}
Message::SliderChanged(value) => self.slider_value = value,
Message::CheckboxToggled(value) => self.toggle_value = value,
Message::CheckboxToggled(value) => self.checkbox_value = value,
Message::TogglerToggled(value) => self.toggler_value = value,
}
}
@ -101,11 +104,19 @@ impl Sandbox for Styling {
.push(Text::new("You did it!"));
let checkbox = Checkbox::new(
self.toggle_value,
"Toggle me!",
self.checkbox_value,
"Check me!",
Message::CheckboxToggled,
)
.width(Length::Fill)
.style(self.theme);
let toggler = Toggler::new(
self.toggler_value,
String::from("Toggle me!"),
Message::TogglerToggled,
)
.width(Length::Shrink)
.spacing(10)
.style(self.theme);
let content = Column::new()
@ -113,15 +124,24 @@ impl Sandbox for Styling {
.padding(20)
.max_width(600)
.push(choose_theme)
.push(Rule::horizontal(38).style(self.theme))
.push(Row::new().spacing(10).push(text_input).push(button))
.push(slider)
.push(progress_bar)
.push(
Row::new()
.spacing(10)
.height(Length::Units(100))
.align_items(Align::Center)
.push(scrollable)
.push(checkbox),
.push(Rule::vertical(38).style(self.theme))
.push(
Column::new()
.width(Length::Shrink)
.spacing(20)
.push(checkbox)
.push(toggler),
),
);
Container::new(content)
@ -136,8 +156,8 @@ impl Sandbox for Styling {
mod style {
use iced::{
button, checkbox, container, progress_bar, radio, scrollable, slider,
text_input,
button, checkbox, container, progress_bar, radio, rule, scrollable,
slider, text_input, toggler,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -228,18 +248,34 @@ mod style {
}
}
impl From<Theme> for Box<dyn toggler::StyleSheet> {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
Theme::Dark => dark::Toggler.into(),
}
}
}
impl From<Theme> for Box<dyn rule::StyleSheet> {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
Theme::Dark => dark::Rule.into(),
}
}
}
mod light {
use iced::{button, Background, Color, Vector};
use iced::{button, Color, Vector};
pub struct Button;
impl button::StyleSheet for Button {
fn active(&self) -> button::Style {
button::Style {
background: Some(Background::Color(Color::from_rgb(
0.11, 0.42, 0.87,
))),
border_radius: 12,
background: Color::from_rgb(0.11, 0.42, 0.87).into(),
border_radius: 12.0,
shadow_offset: Vector::new(1.0, 1.0),
text_color: Color::from_rgb8(0xEE, 0xEE, 0xEE),
..button::Style::default()
@ -258,8 +294,8 @@ mod style {
mod dark {
use iced::{
button, checkbox, container, progress_bar, radio, scrollable,
slider, text_input, Background, Color,
button, checkbox, container, progress_bar, radio, rule, scrollable,
slider, text_input, toggler, Color,
};
const SURFACE: Color = Color::from_rgb(
@ -291,10 +327,8 @@ mod style {
impl container::StyleSheet for Container {
fn style(&self) -> container::Style {
container::Style {
background: Some(Background::Color(Color::from_rgb8(
0x36, 0x39, 0x3F,
))),
text_color: Some(Color::WHITE),
background: Color::from_rgb8(0x36, 0x39, 0x3F).into(),
text_color: Color::WHITE.into(),
..container::Style::default()
}
}
@ -305,16 +339,16 @@ mod style {
impl radio::StyleSheet for Radio {
fn active(&self) -> radio::Style {
radio::Style {
background: Background::Color(SURFACE),
background: SURFACE.into(),
dot_color: ACTIVE,
border_width: 1,
border_width: 1.0,
border_color: ACTIVE,
}
}
fn hovered(&self) -> radio::Style {
radio::Style {
background: Background::Color(Color { a: 0.5, ..SURFACE }),
background: Color { a: 0.5, ..SURFACE }.into(),
..self.active()
}
}
@ -325,16 +359,16 @@ mod style {
impl text_input::StyleSheet for TextInput {
fn active(&self) -> text_input::Style {
text_input::Style {
background: Background::Color(SURFACE),
border_radius: 2,
border_width: 0,
background: SURFACE.into(),
border_radius: 2.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
}
}
fn focused(&self) -> text_input::Style {
text_input::Style {
border_width: 1,
border_width: 1.0,
border_color: ACCENT,
..self.active()
}
@ -342,7 +376,7 @@ mod style {
fn hovered(&self) -> text_input::Style {
text_input::Style {
border_width: 1,
border_width: 1.0,
border_color: Color { a: 0.3, ..ACCENT },
..self.focused()
}
@ -366,8 +400,8 @@ mod style {
impl button::StyleSheet for Button {
fn active(&self) -> button::Style {
button::Style {
background: Some(Background::Color(ACTIVE)),
border_radius: 3,
background: ACTIVE.into(),
border_radius: 3.0,
text_color: Color::WHITE,
..button::Style::default()
}
@ -375,7 +409,7 @@ mod style {
fn hovered(&self) -> button::Style {
button::Style {
background: Some(Background::Color(HOVERED)),
background: HOVERED.into(),
text_color: Color::WHITE,
..self.active()
}
@ -383,7 +417,7 @@ mod style {
fn pressed(&self) -> button::Style {
button::Style {
border_width: 1,
border_width: 1.0,
border_color: Color::WHITE,
..self.hovered()
}
@ -395,14 +429,14 @@ mod style {
impl scrollable::StyleSheet for Scrollable {
fn active(&self) -> scrollable::Scrollbar {
scrollable::Scrollbar {
background: Some(Background::Color(SURFACE)),
border_radius: 2,
border_width: 0,
background: SURFACE.into(),
border_radius: 2.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
scroller: scrollable::Scroller {
color: ACTIVE,
border_radius: 2,
border_width: 0,
border_radius: 2.0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
}
@ -412,10 +446,7 @@ mod style {
let active = self.active();
scrollable::Scrollbar {
background: Some(Background::Color(Color {
a: 0.5,
..SURFACE
})),
background: Color { a: 0.5, ..SURFACE }.into(),
scroller: scrollable::Scroller {
color: HOVERED,
..active.scroller
@ -444,9 +475,9 @@ mod style {
slider::Style {
rail_colors: (ACTIVE, Color { a: 0.1, ..ACTIVE }),
handle: slider::Handle {
shape: slider::HandleShape::Circle { radius: 9 },
shape: slider::HandleShape::Circle { radius: 9.0 },
color: ACTIVE,
border_width: 0,
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
}
@ -482,9 +513,9 @@ mod style {
impl progress_bar::StyleSheet for ProgressBar {
fn style(&self) -> progress_bar::Style {
progress_bar::Style {
background: Background::Color(SURFACE),
bar: Background::Color(ACTIVE),
border_radius: 10,
background: SURFACE.into(),
bar: ACTIVE.into(),
border_radius: 10.0,
}
}
}
@ -494,27 +525,67 @@ mod style {
impl checkbox::StyleSheet for Checkbox {
fn active(&self, is_checked: bool) -> checkbox::Style {
checkbox::Style {
background: Background::Color(if is_checked {
ACTIVE
} else {
SURFACE
}),
background: if is_checked { ACTIVE } else { SURFACE }
.into(),
checkmark_color: Color::WHITE,
border_radius: 2,
border_width: 1,
border_radius: 2.0,
border_width: 1.0,
border_color: ACTIVE,
}
}
fn hovered(&self, is_checked: bool) -> checkbox::Style {
checkbox::Style {
background: Background::Color(Color {
background: Color {
a: 0.8,
..if is_checked { ACTIVE } else { SURFACE }
}),
}
.into(),
..self.active(is_checked)
}
}
}
pub struct Toggler;
impl toggler::StyleSheet for Toggler {
fn active(&self, is_active: bool) -> toggler::Style {
toggler::Style {
background: if is_active { ACTIVE } else { SURFACE },
background_border: None,
foreground: if is_active { Color::WHITE } else { ACTIVE },
foreground_border: None,
}
}
fn hovered(&self, is_active: bool) -> toggler::Style {
toggler::Style {
background: if is_active { ACTIVE } else { SURFACE },
background_border: None,
foreground: if is_active {
Color {
a: 0.5,
..Color::WHITE
}
} else {
Color { a: 0.5, ..ACTIVE }
},
foreground_border: None,
}
}
}
pub struct Rule;
impl rule::StyleSheet for Rule {
fn style(&self) -> rule::Style {
rule::Style {
color: SURFACE,
width: 2,
radius: 1.0,
fill_mode: rule::FillMode::Padded(15),
}
}
}
}
}

View File

@ -1,6 +1,6 @@
use iced::{Container, Element, Length, Sandbox, Settings, Svg};
pub fn main() {
pub fn main() -> iced::Result {
Tiger::run(Settings::default())
}

View File

@ -6,13 +6,13 @@ edition = "2018"
publish = false
[dependencies]
iced = { path = "../..", features = ["async-std"] }
iced = { path = "../..", features = ["async-std", "debug"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
async-std = "1.0"
directories = "2.0"
directories-next = "2.0"
[target.'cfg(target_arch = "wasm32")'.dependencies]
web-sys = { version = "0.3", features = ["Window", "Storage"] }

View File

@ -1,11 +1,11 @@
use iced::{
button, scrollable, text_input, Align, Application, Button, Checkbox,
Column, Command, Container, Element, Font, HorizontalAlignment, Length,
Row, Scrollable, Settings, Text, TextInput,
Clipboard, Column, Command, Container, Element, Font, HorizontalAlignment,
Length, Row, Scrollable, Settings, Text, TextInput,
};
use serde::{Deserialize, Serialize};
pub fn main() {
pub fn main() -> iced::Result {
Todos::run(Settings::default())
}
@ -58,7 +58,11 @@ impl Application for Todos {
format!("Todos{} - Iced", if dirty { "*" } else { "" })
}
fn update(&mut self, message: Message) -> Command<Message> {
fn update(
&mut self,
message: Message,
_clipboard: &mut Clipboard,
) -> Command<Message> {
match self {
Todos::Loading => {
match message {
@ -425,7 +429,7 @@ impl Filter {
}
}
fn loading_message() -> Element<'static, Message> {
fn loading_message<'a>() -> Element<'a, Message> {
Container::new(
Text::new("Loading...")
.horizontal_alignment(HorizontalAlignment::Center)
@ -437,7 +441,7 @@ fn loading_message() -> Element<'static, Message> {
.into()
}
fn empty_message(message: &str) -> Element<'static, Message> {
fn empty_message<'a>(message: &str) -> Element<'a, Message> {
Container::new(
Text::new(message)
.width(Length::Fill)
@ -489,7 +493,6 @@ enum LoadError {
#[derive(Debug, Clone)]
enum SaveError {
DirectoryError,
FileError,
WriteError,
FormatError,
@ -499,7 +502,7 @@ enum SaveError {
impl SavedState {
fn path() -> std::path::PathBuf {
let mut path = if let Some(project_dirs) =
directories::ProjectDirs::from("rs", "Iced", "Todos")
directories_next::ProjectDirs::from("rs", "Iced", "Todos")
{
project_dirs.data_dir().into()
} else {
@ -538,7 +541,7 @@ impl SavedState {
if let Some(dir) = path.parent() {
async_std::fs::create_dir_all(dir)
.await
.map_err(|_| SaveError::DirectoryError)?;
.map_err(|_| SaveError::FileError)?;
}
{
@ -611,7 +614,7 @@ mod style {
background: Some(Background::Color(
Color::from_rgb(0.2, 0.2, 0.7),
)),
border_radius: 10,
border_radius: 10.0,
text_color: Color::WHITE,
..button::Style::default()
}
@ -627,7 +630,7 @@ mod style {
background: Some(Background::Color(Color::from_rgb(
0.8, 0.2, 0.2,
))),
border_radius: 5,
border_radius: 5.0,
text_color: Color::WHITE,
shadow_offset: Vector::new(1.0, 1.0),
..button::Style::default()

View File

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

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