summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--core/src/keyboard/key_code.rs37
-rw-r--r--core/src/point.rs6
-rw-r--r--core/src/size.rs6
-rw-r--r--examples/README.md1
-rw-r--r--examples/color_palette/src/main.rs2
-rw-r--r--examples/custom_widget/src/main.rs3
-rw-r--r--examples/geometry/src/main.rs5
-rw-r--r--examples/scrollable/Cargo.toml9
-rw-r--r--examples/scrollable/README.md15
-rw-r--r--examples/scrollable/screenshot.pngbin0 -> 148253 bytes
-rw-r--r--examples/scrollable/src/main.rs184
-rw-r--r--examples/scrollable/src/style.rs190
-rw-r--r--examples/tour/src/main.rs2
-rw-r--r--glutin/Cargo.toml2
-rw-r--r--graphics/src/overlay/menu.rs15
-rw-r--r--graphics/src/renderer.rs3
-rw-r--r--graphics/src/widget/button.rs1
-rw-r--r--graphics/src/widget/canvas.rs5
-rw-r--r--graphics/src/widget/column.rs12
-rw-r--r--graphics/src/widget/container.rs10
-rw-r--r--graphics/src/widget/pane_grid.rs3
-rw-r--r--graphics/src/widget/row.rs12
-rw-r--r--graphics/src/widget/scrollable.rs38
-rw-r--r--native/src/element.rs13
-rw-r--r--native/src/layout/debugger.rs3
-rw-r--r--native/src/overlay/menu.rs13
-rw-r--r--native/src/renderer/null.rs6
-rw-r--r--native/src/user_interface.rs8
-rw-r--r--native/src/widget.rs5
-rw-r--r--native/src/widget/button.rs7
-rw-r--r--native/src/widget/checkbox.rs1
-rw-r--r--native/src/widget/column.rs21
-rw-r--r--native/src/widget/container.rs3
-rw-r--r--native/src/widget/image.rs4
-rw-r--r--native/src/widget/pane_grid.rs1
-rw-r--r--native/src/widget/pick_list.rs3
-rw-r--r--native/src/widget/progress_bar.rs1
-rw-r--r--native/src/widget/radio.rs7
-rw-r--r--native/src/widget/row.rs25
-rw-r--r--native/src/widget/rule.rs1
-rw-r--r--native/src/widget/scrollable.rs74
-rw-r--r--native/src/widget/slider.rs7
-rw-r--r--native/src/widget/space.rs1
-rw-r--r--native/src/widget/svg.rs4
-rw-r--r--native/src/widget/text.rs1
-rw-r--r--native/src/widget/text_input.rs11
-rw-r--r--src/application.rs2
-rw-r--r--src/executor.rs2
-rw-r--r--src/sandbox.rs3
-rw-r--r--src/window/settings.rs7
-rw-r--r--winit/Cargo.toml2
-rw-r--r--winit/src/conversion.rs14
-rw-r--r--winit/src/settings.rs9
54 files changed, 712 insertions, 109 deletions
diff --git a/Cargo.toml b/Cargo.toml
index d97707ab..e201a4b6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -67,6 +67,7 @@ members = [
"examples/pick_list",
"examples/pokedex",
"examples/progress_bar",
+ "examples/scrollable",
"examples/solar_system",
"examples/stopwatch",
"examples/styling",
diff --git a/core/src/keyboard/key_code.rs b/core/src/keyboard/key_code.rs
index 26020a57..74ead170 100644
--- a/core/src/keyboard/key_code.rs
+++ b/core/src/keyboard/key_code.rs
@@ -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,
diff --git a/core/src/point.rs b/core/src/point.rs
index 3714aa2f..7d93538f 100644
--- a/core/src/point.rs
+++ b/core/src/point.rs
@@ -46,6 +46,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;
diff --git a/core/src/size.rs b/core/src/size.rs
index aceb5311..7c481935 100644
--- a/core/src/size.rs
+++ b/core/src/size.rs
@@ -56,3 +56,9 @@ impl From<[u16; 2]> for Size {
Size::new(width.into(), height.into())
}
}
+
+impl From<Size> for [f32; 2] {
+ fn from(size: Size) -> [f32; 2] {
+ [size.width, size.height]
+ }
+}
diff --git a/examples/README.md b/examples/README.md
index 34a916a1..32ccf724 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -103,6 +103,7 @@ A bunch of simpler examples exist:
- [`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.
diff --git a/examples/color_palette/src/main.rs b/examples/color_palette/src/main.rs
index fec5f48c..bb2c61cb 100644
--- a/examples/color_palette/src/main.rs
+++ b/examples/color_palette/src/main.rs
@@ -284,7 +284,7 @@ impl<C: 'static + ColorSpace + Copy> ColorPicker<C> {
let [s1, s2, s3] = &mut self.sliders;
let [cr1, cr2, cr3] = C::COMPONENT_RANGES;
- fn slider<C>(
+ fn slider<C: Clone>(
state: &mut slider::State,
range: RangeInclusive<f64>,
component: f32,
diff --git a/examples/custom_widget/src/main.rs b/examples/custom_widget/src/main.rs
index 0eba1cd0..a0003d65 100644
--- a/examples/custom_widget/src/main.rs
+++ b/examples/custom_widget/src/main.rs
@@ -12,7 +12,7 @@ mod circle {
use iced_graphics::{Backend, Defaults, Primitive, Renderer};
use iced_native::{
layout, mouse, Background, Color, Element, Hasher, Layout, Length,
- Point, Size, Widget,
+ Point, Rectangle, Size, Widget,
};
pub struct Circle {
@@ -60,6 +60,7 @@ mod circle {
_defaults: &Defaults,
layout: Layout<'_>,
_cursor_position: Point,
+ _viewport: &Rectangle,
) -> (Primitive, mouse::Interaction) {
(
Primitive::Quad {
diff --git a/examples/geometry/src/main.rs b/examples/geometry/src/main.rs
index 1c13c8d5..f650b2c1 100644
--- a/examples/geometry/src/main.rs
+++ b/examples/geometry/src/main.rs
@@ -15,8 +15,8 @@ mod rainbow {
Backend, Defaults, Primitive, Renderer,
};
use iced_native::{
- layout, mouse, Element, Hasher, Layout, Length, Point, Size, Vector,
- Widget,
+ layout, mouse, Element, Hasher, Layout, Length, Point, Rectangle, Size,
+ Vector, Widget,
};
pub struct Rainbow;
@@ -57,6 +57,7 @@ mod rainbow {
_defaults: &Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ _viewport: &Rectangle,
) -> (Primitive, mouse::Interaction) {
let b = layout.bounds();
diff --git a/examples/scrollable/Cargo.toml b/examples/scrollable/Cargo.toml
new file mode 100644
index 00000000..12753fb6
--- /dev/null
+++ b/examples/scrollable/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "scrollable"
+version = "0.1.0"
+authors = ["Clark Moody <clark@clarkmoody.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+iced = { path = "../.." }
diff --git a/examples/scrollable/README.md b/examples/scrollable/README.md
new file mode 100644
index 00000000..ed0e31b5
--- /dev/null
+++ b/examples/scrollable/README.md
@@ -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
+```
diff --git a/examples/scrollable/screenshot.png b/examples/scrollable/screenshot.png
new file mode 100644
index 00000000..2d800251
--- /dev/null
+++ b/examples/scrollable/screenshot.png
Binary files differ
diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs
new file mode 100644
index 00000000..8dd2e20c
--- /dev/null
+++ b/examples/scrollable/src/main.rs
@@ -0,0 +1,184 @@
+mod style;
+
+use iced::{
+ scrollable, Column, Container, Element, Length, 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),
+}
+
+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,
+ }
+ }
+
+ 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()
+ .map(|variant| {
+ let mut scrollable = Scrollable::new(&mut variant.state)
+ .padding(10)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .style(*theme)
+ .push(Text::new(variant.title));
+
+ 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."));
+
+ Container::new(scrollable)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .style(*theme)
+ .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,
+ state: scrollable::State,
+ scrollbar_width: Option<u16>,
+ scrollbar_margin: Option<u16>,
+ scroller_width: Option<u16>,
+}
+
+impl Variant {
+ pub fn all() -> Vec<Self> {
+ vec![
+ Self {
+ title: "Default Scrollbar",
+ state: scrollable::State::new(),
+ scrollbar_width: None,
+ scrollbar_margin: None,
+ scroller_width: None,
+ },
+ Self {
+ title: "Slimmed & Margin",
+ state: scrollable::State::new(),
+ scrollbar_width: Some(4),
+ scrollbar_margin: Some(3),
+ scroller_width: Some(4),
+ },
+ Self {
+ title: "Wide Scroller",
+ state: scrollable::State::new(),
+ scrollbar_width: Some(4),
+ scrollbar_margin: None,
+ scroller_width: Some(10),
+ },
+ Self {
+ title: "Narrow Scroller",
+ state: scrollable::State::new(),
+ scrollbar_width: Some(10),
+ scrollbar_margin: None,
+ scroller_width: Some(4),
+ },
+ ]
+ }
+}
diff --git a/examples/scrollable/src/style.rs b/examples/scrollable/src/style.rs
new file mode 100644
index 00000000..24d711ac
--- /dev/null
+++ b/examples/scrollable/src/style.rs
@@ -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,
+ 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,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
+ scroller: scrollable::Scroller {
+ color: Color { a: 0.7, ..SCROLLER },
+ border_radius: 2,
+ border_width: 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,
+ fill_mode: rule::FillMode::Percent(30.0),
+ }
+ }
+ }
+}
diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs
index ec464801..560d67e2 100644
--- a/examples/tour/src/main.rs
+++ b/examples/tour/src/main.rs
@@ -689,7 +689,7 @@ fn ferris<'a>(width: u16) -> Container<'a, StepMessage> {
.center_x()
}
-fn button<'a, Message>(
+fn button<'a, Message: Clone>(
state: &'a mut button::State,
label: &str,
) -> Button<'a, Message> {
diff --git a/glutin/Cargo.toml b/glutin/Cargo.toml
index 4652112c..b298134c 100644
--- a/glutin/Cargo.toml
+++ b/glutin/Cargo.toml
@@ -14,7 +14,7 @@ categories = ["gui"]
debug = ["iced_winit/debug"]
[dependencies]
-glutin = "0.24"
+glutin = "0.25"
[dependencies.iced_native]
version = "0.2"
diff --git a/graphics/src/overlay/menu.rs b/graphics/src/overlay/menu.rs
index a952f065..f42c5e3c 100644
--- a/graphics/src/overlay/menu.rs
+++ b/graphics/src/overlay/menu.rs
@@ -42,6 +42,7 @@ where
&mut self,
bounds: Rectangle,
cursor_position: Point,
+ viewport: &Rectangle,
options: &[T],
hovered_option: Option<usize>,
padding: u16,
@@ -52,16 +53,24 @@ where
use std::f32;
let is_mouse_over = bounds.contains(cursor_position);
+ let option_height = text_size as usize + padding as usize * 2;
let mut primitives = Vec::new();
- for (i, option) in options.iter().enumerate() {
+ let offset = viewport.y - bounds.y;
+ let start = (offset / option_height as f32) as usize;
+ let end =
+ ((offset + viewport.height) / option_height as f32).ceil() as usize;
+
+ let visible_options = &options[start..end.min(options.len())];
+
+ for (i, option) in visible_options.iter().enumerate() {
+ let i = start + i;
let is_selected = hovered_option == Some(i);
let bounds = Rectangle {
x: bounds.x,
- y: bounds.y
- + ((text_size as usize + padding as usize * 2) * i) as f32,
+ y: bounds.y + (option_height * i) as f32,
width: bounds.width,
height: f32::from(text_size + padding * 2),
};
diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs
index 5d51e6d4..a880e22a 100644
--- a/graphics/src/renderer.rs
+++ b/graphics/src/renderer.rs
@@ -96,10 +96,11 @@ where
widget: &dyn Widget<Message, Self>,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
color: Color,
) -> Self::Output {
let (primitive, cursor) =
- widget.draw(self, defaults, layout, cursor_position);
+ widget.draw(self, defaults, layout, cursor_position, viewport);
let mut primitives = Vec::new();
diff --git a/graphics/src/widget/button.rs b/graphics/src/widget/button.rs
index ecabc868..a1afc940 100644
--- a/graphics/src/widget/button.rs
+++ b/graphics/src/widget/button.rs
@@ -62,6 +62,7 @@ where
},
content_layout,
cursor_position,
+ &bounds,
);
(
diff --git a/graphics/src/widget/canvas.rs b/graphics/src/widget/canvas.rs
index bc0802e5..73778d16 100644
--- a/graphics/src/widget/canvas.rs
+++ b/graphics/src/widget/canvas.rs
@@ -8,8 +8,8 @@
//! [`Frame`]: struct.Frame.html
use crate::{Backend, Defaults, Primitive, Renderer};
use iced_native::{
- layout, mouse, Clipboard, Element, Hasher, Layout, Length, Point, Size,
- Vector, Widget,
+ layout, mouse, Clipboard, Element, Hasher, Layout, Length, Point,
+ Rectangle, Size, Vector, Widget,
};
use std::hash::Hash;
use std::marker::PhantomData;
@@ -196,6 +196,7 @@ where
_defaults: &Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ _viewport: &Rectangle,
) -> (Primitive, mouse::Interaction) {
let bounds = layout.bounds();
let translation = Vector::new(bounds.x, bounds.y);
diff --git a/graphics/src/widget/column.rs b/graphics/src/widget/column.rs
index 6c7235c7..0cf56842 100644
--- a/graphics/src/widget/column.rs
+++ b/graphics/src/widget/column.rs
@@ -1,7 +1,7 @@
use crate::{Backend, Primitive, Renderer};
use iced_native::column;
use iced_native::mouse;
-use iced_native::{Element, Layout, Point};
+use iced_native::{Element, Layout, Point, Rectangle};
/// A container that distributes its contents vertically.
pub type Column<'a, Message, Backend> =
@@ -17,6 +17,7 @@ where
content: &[Element<'_, Message, Self>],
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Self::Output {
let mut mouse_interaction = mouse::Interaction::default();
@@ -26,8 +27,13 @@ where
.iter()
.zip(layout.children())
.map(|(child, layout)| {
- let (primitive, new_mouse_interaction) =
- child.draw(self, defaults, layout, cursor_position);
+ let (primitive, new_mouse_interaction) = child.draw(
+ self,
+ defaults,
+ layout,
+ cursor_position,
+ viewport,
+ );
if new_mouse_interaction > mouse_interaction {
mouse_interaction = new_mouse_interaction;
diff --git a/graphics/src/widget/container.rs b/graphics/src/widget/container.rs
index 5b3a01d2..4854f589 100644
--- a/graphics/src/widget/container.rs
+++ b/graphics/src/widget/container.rs
@@ -24,6 +24,7 @@ where
defaults: &Defaults,
bounds: Rectangle,
cursor_position: Point,
+ viewport: &Rectangle,
style_sheet: &Self::Style,
content: &Element<'_, Message, Self>,
content_layout: Layout<'_>,
@@ -36,8 +37,13 @@ where
},
};
- let (content, mouse_interaction) =
- content.draw(self, &defaults, content_layout, cursor_position);
+ let (content, mouse_interaction) = content.draw(
+ self,
+ &defaults,
+ content_layout,
+ cursor_position,
+ viewport,
+ );
if let Some(background) = background(bounds, &style) {
(
diff --git a/graphics/src/widget/pane_grid.rs b/graphics/src/widget/pane_grid.rs
index aa8a3f7c..5b0eb391 100644
--- a/graphics/src/widget/pane_grid.rs
+++ b/graphics/src/widget/pane_grid.rs
@@ -137,7 +137,7 @@ where
let (body, body_layout) = body;
let (body_primitive, body_interaction) =
- body.draw(self, defaults, body_layout, cursor_position);
+ body.draw(self, defaults, body_layout, cursor_position, &bounds);
let background = crate::widget::container::background(bounds, &style);
@@ -224,6 +224,7 @@ where
&defaults,
controls_layout,
cursor_position,
+ &bounds,
);
(
diff --git a/graphics/src/widget/row.rs b/graphics/src/widget/row.rs
index 4c1dbadc..397d80bf 100644
--- a/graphics/src/widget/row.rs
+++ b/graphics/src/widget/row.rs
@@ -1,7 +1,7 @@
use crate::{Backend, Primitive, Renderer};
use iced_native::mouse;
use iced_native::row;
-use iced_native::{Element, Layout, Point};
+use iced_native::{Element, Layout, Point, Rectangle};
/// A container that distributes its contents horizontally.
pub type Row<'a, Message, Backend> =
@@ -17,6 +17,7 @@ where
content: &[Element<'_, Message, Self>],
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Self::Output {
let mut mouse_interaction = mouse::Interaction::default();
@@ -26,8 +27,13 @@ where
.iter()
.zip(layout.children())
.map(|(child, layout)| {
- let (primitive, new_mouse_interaction) =
- child.draw(self, defaults, layout, cursor_position);
+ let (primitive, new_mouse_interaction) = child.draw(
+ self,
+ defaults,
+ layout,
+ cursor_position,
+ viewport,
+ );
if new_mouse_interaction > mouse_interaction {
mouse_interaction = new_mouse_interaction;
diff --git a/graphics/src/widget/scrollable.rs b/graphics/src/widget/scrollable.rs
index b149db0a..fed79c18 100644
--- a/graphics/src/widget/scrollable.rs
+++ b/graphics/src/widget/scrollable.rs
@@ -15,9 +15,6 @@ pub use iced_style::scrollable::{Scrollbar, Scroller, StyleSheet};
pub type Scrollable<'a, Message, Backend> =
iced_native::Scrollable<'a, Message, Renderer<Backend>>;
-const SCROLLBAR_WIDTH: u16 = 10;
-const SCROLLBAR_MARGIN: u16 = 2;
-
impl<B> scrollable::Renderer for Renderer<B>
where
B: Backend,
@@ -29,29 +26,45 @@ where
bounds: Rectangle,
content_bounds: Rectangle,
offset: u32,
+ scrollbar_width: u16,
+ scrollbar_margin: u16,
+ scroller_width: u16,
) -> Option<scrollable::Scrollbar> {
if content_bounds.height > bounds.height {
+ let outer_width =
+ scrollbar_width.max(scroller_width) + 2 * scrollbar_margin;
+
+ let outer_bounds = Rectangle {
+ x: bounds.x + bounds.width - outer_width as f32,
+ y: bounds.y,
+ width: outer_width as f32,
+ height: bounds.height,
+ };
+
let scrollbar_bounds = Rectangle {
x: bounds.x + bounds.width
- - f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
+ - f32::from(outer_width / 2 + scrollbar_width / 2),
y: bounds.y,
- width: f32::from(SCROLLBAR_WIDTH + 2 * SCROLLBAR_MARGIN),
+ width: scrollbar_width as f32,
height: bounds.height,
};
let ratio = bounds.height / content_bounds.height;
- let scrollbar_height = bounds.height * ratio;
+ let scroller_height = bounds.height * ratio;
let y_offset = offset as f32 * ratio;
let scroller_bounds = Rectangle {
- x: scrollbar_bounds.x + f32::from(SCROLLBAR_MARGIN),
+ x: bounds.x + bounds.width
+ - f32::from(outer_width / 2 + scroller_width / 2),
y: scrollbar_bounds.y + y_offset,
- width: scrollbar_bounds.width - f32::from(2 * SCROLLBAR_MARGIN),
- height: scrollbar_height,
+ width: scroller_width as f32,
+ height: scroller_height,
};
Some(scrollable::Scrollbar {
+ outer_bounds,
bounds: scrollbar_bounds,
+ margin: scrollbar_margin,
scroller: scrollable::Scroller {
bounds: scroller_bounds,
},
@@ -109,12 +122,7 @@ where
let scrollbar = if is_scrollbar_visible {
Primitive::Quad {
- bounds: Rectangle {
- x: scrollbar.bounds.x + f32::from(SCROLLBAR_MARGIN),
- width: scrollbar.bounds.width
- - f32::from(2 * SCROLLBAR_MARGIN),
- ..scrollbar.bounds
- },
+ bounds: scrollbar.bounds,
background: style
.background
.unwrap_or(Background::Color(Color::TRANSPARENT)),
diff --git a/native/src/element.rs b/native/src/element.rs
index 514a135b..10e1b5fb 100644
--- a/native/src/element.rs
+++ b/native/src/element.rs
@@ -1,6 +1,7 @@
+use crate::layout;
+use crate::overlay;
use crate::{
- layout, overlay, Clipboard, Color, Event, Hasher, Layout, Length, Point,
- Widget,
+ Clipboard, Color, Event, Hasher, Layout, Length, Point, Rectangle, Widget,
};
/// A generic [`Widget`].
@@ -260,9 +261,10 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Renderer::Output {
self.widget
- .draw(renderer, defaults, layout, cursor_position)
+ .draw(renderer, defaults, layout, cursor_position, viewport)
}
/// Computes the _layout_ hash of the [`Element`].
@@ -356,9 +358,10 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Renderer::Output {
self.widget
- .draw(renderer, defaults, layout, cursor_position)
+ .draw(renderer, defaults, layout, cursor_position, viewport)
}
fn hash_layout(&self, state: &mut Hasher) {
@@ -437,12 +440,14 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Renderer::Output {
renderer.explain(
defaults,
self.element.widget.as_ref(),
layout,
cursor_position,
+ viewport,
self.color,
)
}
diff --git a/native/src/layout/debugger.rs b/native/src/layout/debugger.rs
index e4b21609..4c6dd793 100644
--- a/native/src/layout/debugger.rs
+++ b/native/src/layout/debugger.rs
@@ -1,4 +1,4 @@
-use crate::{Color, Layout, Point, Renderer, Widget};
+use crate::{Color, Layout, Point, Rectangle, Renderer, Widget};
/// A renderer able to graphically explain a [`Layout`].
///
@@ -21,6 +21,7 @@ pub trait Debugger: Renderer {
widget: &dyn Widget<Message, Self>,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
color: Color,
) -> Self::Output;
}
diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs
index c2df468e..4b392a8e 100644
--- a/native/src/overlay/menu.rs
+++ b/native/src/overlay/menu.rs
@@ -253,9 +253,13 @@ where
layout: Layout<'_>,
cursor_position: Point,
) -> Renderer::Output {
- let primitives =
- self.container
- .draw(renderer, defaults, layout, cursor_position);
+ let primitives = self.container.draw(
+ renderer,
+ defaults,
+ layout,
+ cursor_position,
+ &layout.bounds(),
+ );
renderer.decorate(
layout.bounds(),
@@ -368,11 +372,13 @@ where
_defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Renderer::Output {
self::Renderer::draw(
renderer,
layout.bounds(),
cursor_position,
+ viewport,
self.options,
*self.hovered_option,
self.padding,
@@ -418,6 +424,7 @@ pub trait Renderer:
&mut self,
bounds: Rectangle,
cursor_position: Point,
+ viewport: &Rectangle,
options: &[T],
hovered_option: Option<usize>,
padding: u16,
diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs
index 2aee0da1..a3c3cf33 100644
--- a/native/src/renderer/null.rs
+++ b/native/src/renderer/null.rs
@@ -35,6 +35,7 @@ impl column::Renderer for Null {
_content: &[Element<'_, Message, Self>],
_layout: Layout<'_>,
_cursor_position: Point,
+ _viewport: &Rectangle,
) {
}
}
@@ -46,6 +47,7 @@ impl row::Renderer for Null {
_content: &[Element<'_, Message, Self>],
_layout: Layout<'_>,
_cursor_position: Point,
+ _viewport: &Rectangle,
) {
}
}
@@ -89,6 +91,9 @@ impl scrollable::Renderer for Null {
_bounds: Rectangle,
_content_bounds: Rectangle,
_offset: u32,
+ _scrollbar_width: u16,
+ _scrollbar_margin: u16,
+ _scroller_width: u16,
) -> Option<scrollable::Scrollbar> {
None
}
@@ -234,6 +239,7 @@ impl container::Renderer for Null {
_defaults: &Self::Defaults,
_bounds: Rectangle,
_cursor_position: Point,
+ _viewport: &Rectangle,
_style: &Self::Style,
_content: &Element<'_, Message, Self>,
_content_layout: Layout<'_>,
diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs
index 00a290f1..59d91f42 100644
--- a/native/src/user_interface.rs
+++ b/native/src/user_interface.rs
@@ -1,4 +1,6 @@
-use crate::{layout, overlay, Clipboard, Element, Event, Layout, Point, Size};
+use crate::layout;
+use crate::overlay;
+use crate::{Clipboard, Element, Event, Layout, Point, Rectangle, Size};
use std::hash::Hasher;
@@ -327,6 +329,8 @@ where
renderer: &mut Renderer,
cursor_position: Point,
) -> Renderer::Output {
+ let viewport = Rectangle::with_size(self.bounds);
+
let overlay = if let Some(mut overlay) =
self.root.overlay(Layout::new(&self.base.layout))
{
@@ -365,6 +369,7 @@ where
&Renderer::Defaults::default(),
Layout::new(&self.base.layout),
base_cursor,
+ &viewport,
);
renderer.overlay(
@@ -378,6 +383,7 @@ where
&Renderer::Defaults::default(),
Layout::new(&self.base.layout),
cursor_position,
+ &viewport,
)
}
}
diff --git a/native/src/widget.rs b/native/src/widget.rs
index a10281df..8687ce6f 100644
--- a/native/src/widget.rs
+++ b/native/src/widget.rs
@@ -73,7 +73,9 @@ pub use text::Text;
#[doc(no_inline)]
pub use text_input::TextInput;
-use crate::{layout, overlay, Clipboard, Event, Hasher, Layout, Length, Point};
+use crate::{
+ layout, overlay, Clipboard, Event, Hasher, Layout, Length, Point, Rectangle,
+};
/// A component that displays information and allows interaction.
///
@@ -137,6 +139,7 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Renderer::Output;
/// Computes the _layout_ hash of the [`Widget`].
diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs
index c932da2b..995ba7bc 100644
--- a/native/src/widget/button.rs
+++ b/native/src/widget/button.rs
@@ -18,6 +18,7 @@ use std::hash::Hash;
/// # type Button<'a, Message> =
/// # iced_native::Button<'a, Message, iced_native::renderer::Null>;
/// #
+/// #[derive(Clone)]
/// enum Message {
/// ButtonPressed,
/// }
@@ -41,6 +42,7 @@ pub struct Button<'a, Message, Renderer: self::Renderer> {
impl<'a, Message, Renderer> Button<'a, Message, Renderer>
where
+ Message: Clone,
Renderer: self::Renderer,
{
/// Creates a new [`Button`] with some local [`State`] and the given
@@ -142,8 +144,8 @@ impl State {
impl<'a, Message, Renderer> Widget<Message, Renderer>
for Button<'a, Message, Renderer>
where
- Renderer: self::Renderer,
Message: Clone,
+ Renderer: self::Renderer,
{
fn width(&self) -> Length {
self.width
@@ -215,6 +217,7 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
renderer.draw(
defaults,
@@ -272,8 +275,8 @@ pub trait Renderer: crate::Renderer + Sized {
impl<'a, Message, Renderer> From<Button<'a, Message, Renderer>>
for Element<'a, Message, Renderer>
where
- Renderer: 'a + self::Renderer,
Message: 'a + Clone,
+ Renderer: 'a + self::Renderer,
{
fn from(
button: Button<'a, Message, Renderer>,
diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs
index 99178aae..e389427e 100644
--- a/native/src/widget/checkbox.rs
+++ b/native/src/widget/checkbox.rs
@@ -180,6 +180,7 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
let bounds = layout.bounds();
let mut children = layout.children();
diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs
index 42cfe9b9..e874ad42 100644
--- a/native/src/widget/column.rs
+++ b/native/src/widget/column.rs
@@ -1,18 +1,16 @@
//! Distribute content vertically.
use std::hash::Hash;
+use crate::layout;
+use crate::overlay;
use crate::{
- layout, overlay, Align, Clipboard, Element, Event, Hasher, Layout, Length,
- Point, Widget,
+ Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, Rectangle,
+ Widget,
};
use std::u32;
/// A container that distributes its contents vertically.
-///
-/// A [`Column`] will try to fill the horizontal space of its container.
-///
-/// [`Column`]: struct.Column.html
#[allow(missing_debug_implementations)]
pub struct Column<'a, Message, Renderer> {
spacing: u16,
@@ -185,8 +183,15 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Renderer::Output {
- renderer.draw(defaults, &self.children, layout, cursor_position)
+ renderer.draw(
+ defaults,
+ &self.children,
+ layout,
+ cursor_position,
+ viewport,
+ )
}
fn hash_layout(&self, state: &mut Hasher) {
@@ -199,6 +204,7 @@ where
self.max_height.hash(state);
self.align_items.hash(state);
self.spacing.hash(state);
+ self.padding.hash(state);
for child in &self.children {
child.widget.hash_layout(state);
@@ -240,6 +246,7 @@ pub trait Renderer: crate::Renderer + Sized {
content: &[Element<'_, Message, Self>],
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Self::Output;
}
diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs
index b8316e62..5b04d699 100644
--- a/native/src/widget/container.rs
+++ b/native/src/widget/container.rs
@@ -191,11 +191,13 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Renderer::Output {
renderer.draw(
defaults,
layout.bounds(),
cursor_position,
+ viewport,
&self.style,
&self.content,
layout.children().next().unwrap(),
@@ -242,6 +244,7 @@ pub trait Renderer: crate::Renderer {
defaults: &Self::Defaults,
bounds: Rectangle,
cursor_position: Point,
+ viewport: &Rectangle,
style: &Self::Style,
content: &Element<'_, Message, Self>,
content_layout: Layout<'_>,
diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs
index 132f249d..9586da0f 100644
--- a/native/src/widget/image.rs
+++ b/native/src/widget/image.rs
@@ -1,5 +1,6 @@
//! Display images in your user interface.
-use crate::{layout, Element, Hasher, Layout, Length, Point, Size, Widget};
+use crate::layout;
+use crate::{Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget};
use std::{
hash::{Hash, Hasher as _},
@@ -97,6 +98,7 @@ where
_defaults: &Renderer::Defaults,
layout: Layout<'_>,
_cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
renderer.draw(self.handle.clone(), layout)
}
diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs
index 5180fd3b..276bfae3 100644
--- a/native/src/widget/pane_grid.rs
+++ b/native/src/widget/pane_grid.rs
@@ -588,6 +588,7 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
let picked_split = self
.state
diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs
index 04478225..e086e367 100644
--- a/native/src/widget/pick_list.rs
+++ b/native/src/widget/pick_list.rs
@@ -52,7 +52,7 @@ impl<T> Default for State<T> {
impl<'a, T: 'a, Message, Renderer: self::Renderer>
PickList<'a, T, Message, Renderer>
where
- T: ToString,
+ T: ToString + Eq,
[T]: ToOwned<Owned = Vec<T>>,
{
/// Creates a new [`PickList`] with the given [`State`], a list of options,
@@ -256,6 +256,7 @@ where
_defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
self::Renderer::draw(
renderer,
diff --git a/native/src/widget/progress_bar.rs b/native/src/widget/progress_bar.rs
index 5ab76d47..4f8a7e1b 100644
--- a/native/src/widget/progress_bar.rs
+++ b/native/src/widget/progress_bar.rs
@@ -104,6 +104,7 @@ where
_defaults: &Renderer::Defaults,
layout: Layout<'_>,
_cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
renderer.draw(
layout.bounds(),
diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs
index 5b8d00e9..06d3f846 100644
--- a/native/src/widget/radio.rs
+++ b/native/src/widget/radio.rs
@@ -47,6 +47,8 @@ pub struct Radio<Message, Renderer: self::Renderer + text::Renderer> {
impl<Message, Renderer: self::Renderer + text::Renderer>
Radio<Message, Renderer>
+where
+ Message: Clone,
{
/// Creates a new [`Radio`] button.
///
@@ -123,8 +125,8 @@ impl<Message, Renderer: self::Renderer + text::Renderer>
impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message, Renderer>
where
- Renderer: self::Renderer + text::Renderer + row::Renderer,
Message: Clone,
+ Renderer: self::Renderer + text::Renderer + row::Renderer,
{
fn width(&self) -> Length {
self.width
@@ -181,6 +183,7 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
let bounds = layout.bounds();
let mut children = layout.children();
@@ -264,8 +267,8 @@ pub trait Renderer: crate::Renderer {
impl<'a, Message, Renderer> From<Radio<Message, Renderer>>
for Element<'a, Message, Renderer>
where
- Renderer: 'a + self::Renderer + row::Renderer + text::Renderer,
Message: 'a + Clone,
+ Renderer: 'a + self::Renderer + row::Renderer + text::Renderer,
{
fn from(radio: Radio<Message, Renderer>) -> Element<'a, Message, Renderer> {
Element::new(radio)
diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs
index 2b6db224..bc8a3df1 100644
--- a/native/src/widget/row.rs
+++ b/native/src/widget/row.rs
@@ -1,18 +1,15 @@
//! Distribute content horizontally.
-use std::hash::Hash;
-
+use crate::layout;
+use crate::overlay;
use crate::{
- layout, overlay, Align, Clipboard, Element, Event, Hasher, Layout, Length,
- Point, Widget,
+ Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, Rectangle,
+ Widget,
};
+use std::hash::Hash;
use std::u32;
/// A container that distributes its contents horizontally.
-///
-/// A [`Row`] will try to fill the horizontal space of its container.
-///
-/// [`Row`]: struct.Row.html
#[allow(missing_debug_implementations)]
pub struct Row<'a, Message, Renderer> {
spacing: u16,
@@ -186,8 +183,15 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Renderer::Output {
- renderer.draw(defaults, &self.children, layout, cursor_position)
+ renderer.draw(
+ defaults,
+ &self.children,
+ layout,
+ cursor_position,
+ viewport,
+ )
}
fn hash_layout(&self, state: &mut Hasher) {
@@ -200,7 +204,7 @@ where
self.max_height.hash(state);
self.align_items.hash(state);
self.spacing.hash(state);
- self.spacing.hash(state);
+ self.padding.hash(state);
for child in &self.children {
child.widget.hash_layout(state);
@@ -242,6 +246,7 @@ pub trait Renderer: crate::Renderer + Sized {
children: &[Element<'_, Message, Self>],
layout: Layout<'_>,
cursor_position: Point,
+ viewport: &Rectangle,
) -> Self::Output;
}
diff --git a/native/src/widget/rule.rs b/native/src/widget/rule.rs
index 25cec53b..66328c08 100644
--- a/native/src/widget/rule.rs
+++ b/native/src/widget/rule.rs
@@ -77,6 +77,7 @@ where
_defaults: &Renderer::Defaults,
layout: Layout<'_>,
_cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
renderer.draw(layout.bounds(), &self.style, self.is_horizontal)
}
diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs
index 75e97027..60ec2d7d 100644
--- a/native/src/widget/scrollable.rs
+++ b/native/src/widget/scrollable.rs
@@ -13,6 +13,9 @@ pub struct Scrollable<'a, Message, Renderer: self::Renderer> {
state: &'a mut State,
height: Length,
max_height: u32,
+ scrollbar_width: u16,
+ scrollbar_margin: u16,
+ scroller_width: u16,
content: Column<'a, Message, Renderer>,
style: Renderer::Style,
}
@@ -27,6 +30,9 @@ impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> {
state,
height: Length::Shrink,
max_height: u32::MAX,
+ scrollbar_width: 10,
+ scrollbar_margin: 0,
+ scroller_width: 10,
content: Column::new(),
style: Renderer::Style::default(),
}
@@ -90,6 +96,32 @@ impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> {
self
}
+ /// Sets the scrollbar width of the [`Scrollable`] .
+ /// Silently enforces a minimum value of 1.
+ ///
+ /// [`Scrollable`]: struct.Scrollable.html
+ pub fn scrollbar_width(mut self, scrollbar_width: u16) -> Self {
+ self.scrollbar_width = scrollbar_width.max(1);
+ self
+ }
+
+ /// Sets the scrollbar margin of the [`Scrollable`] .
+ ///
+ /// [`Scrollable`]: struct.Scrollable.html
+ pub fn scrollbar_margin(mut self, scrollbar_margin: u16) -> Self {
+ self.scrollbar_margin = scrollbar_margin;
+ self
+ }
+
+ /// Sets the scroller width of the [`Scrollable`] .
+ /// Silently enforces a minimum value of 1.
+ ///
+ /// [`Scrollable`]: struct.Scrollable.html
+ pub fn scroller_width(mut self, scroller_width: u16) -> Self {
+ self.scroller_width = scroller_width.max(1);
+ self
+ }
+
/// Sets the style of the [`Scrollable`] .
///
/// [`Scrollable`]: struct.Scrollable.html
@@ -178,7 +210,14 @@ where
}
let offset = self.state.offset(bounds, content_bounds);
- let scrollbar = renderer.scrollbar(bounds, content_bounds, offset);
+ let scrollbar = renderer.scrollbar(
+ bounds,
+ content_bounds,
+ offset,
+ self.scrollbar_width,
+ self.scrollbar_margin,
+ self.scroller_width,
+ );
let is_mouse_over_scrollbar = scrollbar
.as_ref()
.map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
@@ -264,12 +303,20 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
let bounds = layout.bounds();
let content_layout = layout.children().next().unwrap();
let content_bounds = content_layout.bounds();
let offset = self.state.offset(bounds, content_bounds);
- let scrollbar = renderer.scrollbar(bounds, content_bounds, offset);
+ let scrollbar = renderer.scrollbar(
+ bounds,
+ content_bounds,
+ offset,
+ self.scrollbar_width,
+ self.scrollbar_margin,
+ self.scroller_width,
+ );
let is_mouse_over = bounds.contains(cursor_position);
let is_mouse_over_scrollbar = scrollbar
@@ -289,6 +336,10 @@ where
defaults,
content_layout,
cursor_position,
+ &Rectangle {
+ y: bounds.y + offset as f32,
+ ..bounds
+ },
)
};
@@ -413,11 +464,23 @@ impl State {
/// [`Scrollable`]: struct.Scrollable.html
#[derive(Debug)]
pub struct Scrollbar {
+ /// The outer bounds of the scrollable, including the [`Scrollbar`] and
+ /// [`Scroller`].
+ ///
+ /// [`Scrollbar`]: struct.Scrollbar.html
+ /// [`Scroller`]: struct.Scroller.html
+ pub outer_bounds: Rectangle,
+
/// The bounds of the [`Scrollbar`].
///
/// [`Scrollbar`]: struct.Scrollbar.html
pub bounds: Rectangle,
+ /// The margin within the [`Scrollbar`].
+ ///
+ /// [`Scrollbar`]: struct.Scrollbar.html
+ pub margin: u16,
+
/// The bounds of the [`Scroller`].
///
/// [`Scroller`]: struct.Scroller.html
@@ -426,11 +489,11 @@ pub struct Scrollbar {
impl Scrollbar {
fn is_mouse_over(&self, cursor_position: Point) -> bool {
- self.bounds.contains(cursor_position)
+ self.outer_bounds.contains(cursor_position)
}
fn grab_scroller(&self, cursor_position: Point) -> Option<f32> {
- if self.bounds.contains(cursor_position) {
+ if self.outer_bounds.contains(cursor_position) {
Some(if self.scroller.bounds.contains(cursor_position) {
(cursor_position.y - self.scroller.bounds.y)
/ self.scroller.bounds.height
@@ -486,6 +549,9 @@ pub trait Renderer: column::Renderer + Sized {
bounds: Rectangle,
content_bounds: Rectangle,
offset: u32,
+ scrollbar_width: u16,
+ scrollbar_margin: u16,
+ scroller_width: u16,
) -> Option<Scrollbar>;
/// Draws the [`Scrollable`].
diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs
index c49053f1..d6e366aa 100644
--- a/native/src/widget/slider.rs
+++ b/native/src/widget/slider.rs
@@ -26,6 +26,7 @@ use std::{hash::Hash, ops::RangeInclusive};
/// # use iced_native::{slider, renderer::Null};
/// #
/// # pub type Slider<'a, T, Message> = iced_native::Slider<'a, T, Message, Null>;
+/// #[derive(Clone)]
/// pub enum Message {
/// SliderChanged(f32),
/// }
@@ -53,6 +54,7 @@ pub struct Slider<'a, T, Message, Renderer: self::Renderer> {
impl<'a, T, Message, Renderer> Slider<'a, T, Message, Renderer>
where
T: Copy + From<u8> + std::cmp::PartialOrd,
+ Message: Clone,
Renderer: self::Renderer,
{
/// Creates a new [`Slider`].
@@ -168,8 +170,8 @@ impl<'a, T, Message, Renderer> Widget<Message, Renderer>
for Slider<'a, T, Message, Renderer>
where
T: Copy + Into<f64> + num_traits::FromPrimitive,
- Renderer: self::Renderer,
Message: Clone,
+ Renderer: self::Renderer,
{
fn width(&self) -> Length {
self.width
@@ -257,6 +259,7 @@ where
_defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
let start = *self.range.start();
let end = *self.range.end();
@@ -322,8 +325,8 @@ impl<'a, T, Message, Renderer> From<Slider<'a, T, Message, Renderer>>
for Element<'a, Message, Renderer>
where
T: 'a + Copy + Into<f64> + num_traits::FromPrimitive,
- Renderer: 'a + self::Renderer,
Message: 'a + Clone,
+ Renderer: 'a + self::Renderer,
{
fn from(
slider: Slider<'a, T, Message, Renderer>,
diff --git a/native/src/widget/space.rs b/native/src/widget/space.rs
index f1576ffb..032f341d 100644
--- a/native/src/widget/space.rs
+++ b/native/src/widget/space.rs
@@ -71,6 +71,7 @@ where
_defaults: &Renderer::Defaults,
layout: Layout<'_>,
_cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
renderer.draw(layout.bounds())
}
diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs
index 114d5e41..ede1aff8 100644
--- a/native/src/widget/svg.rs
+++ b/native/src/widget/svg.rs
@@ -1,5 +1,6 @@
//! Display vector graphics in your application.
-use crate::{layout, Element, Hasher, Layout, Length, Point, Size, Widget};
+use crate::layout;
+use crate::{Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget};
use std::{
hash::{Hash, Hasher as _},
@@ -103,6 +104,7 @@ where
_defaults: &Renderer::Defaults,
layout: Layout<'_>,
_cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
renderer.draw(self.handle.clone(), layout)
}
diff --git a/native/src/widget/text.rs b/native/src/widget/text.rs
index 48a69e34..c2544b8e 100644
--- a/native/src/widget/text.rs
+++ b/native/src/widget/text.rs
@@ -149,6 +149,7 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
_cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
renderer.draw(
defaults,
diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs
index 9e15f4be..64182f2d 100644
--- a/native/src/widget/text_input.rs
+++ b/native/src/widget/text_input.rs
@@ -63,7 +63,11 @@ pub struct TextInput<'a, Message, Renderer: self::Renderer> {
style: Renderer::Style,
}
-impl<'a, Message, Renderer: self::Renderer> TextInput<'a, Message, Renderer> {
+impl<'a, Message, Renderer> TextInput<'a, Message, Renderer>
+where
+ Message: Clone,
+ Renderer: self::Renderer,
+{
/// Creates a new [`TextInput`].
///
/// It expects:
@@ -175,8 +179,8 @@ impl<'a, Message, Renderer: self::Renderer> TextInput<'a, Message, Renderer> {
impl<'a, Message, Renderer> Widget<Message, Renderer>
for TextInput<'a, Message, Renderer>
where
- Renderer: self::Renderer,
Message: Clone,
+ Renderer: self::Renderer,
{
fn width(&self) -> Length {
self.width
@@ -493,6 +497,7 @@ where
_defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
+ _viewport: &Rectangle,
) -> Renderer::Output {
let bounds = layout.bounds();
let text_bounds = layout.children().next().unwrap().bounds();
@@ -629,8 +634,8 @@ pub trait Renderer: text::Renderer + Sized {
impl<'a, Message, Renderer> From<TextInput<'a, Message, Renderer>>
for Element<'a, Message, Renderer>
where
- Renderer: 'a + self::Renderer,
Message: 'a + Clone,
+ Renderer: 'a + self::Renderer,
{
fn from(
text_input: TextInput<'a, Message, Renderer>,
diff --git a/src/application.rs b/src/application.rs
index d46cd2ac..d9e25ad4 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -65,7 +65,7 @@ use crate::{Color, Command, Element, Executor, Settings, Subscription};
/// struct Hello;
///
/// impl Application for Hello {
-/// type Executor = executor::Null;
+/// type Executor = executor::Default;
/// type Message = ();
/// type Flags = ();
///
diff --git a/src/executor.rs b/src/executor.rs
index 59d59a5a..ea6ab14a 100644
--- a/src/executor.rs
+++ b/src/executor.rs
@@ -1,5 +1,5 @@
//! Choose your preferred executor to power your application.
-pub use crate::runtime::{executor::Null, Executor};
+pub use crate::runtime::Executor;
pub use platform::Default;
diff --git a/src/sandbox.rs b/src/sandbox.rs
index c72b58d8..5a668e39 100644
--- a/src/sandbox.rs
+++ b/src/sandbox.rs
@@ -1,4 +1,3 @@
-use crate::executor;
use crate::{
Application, Color, Command, Element, Error, Settings, Subscription,
};
@@ -172,7 +171,7 @@ impl<T> Application for T
where
T: Sandbox,
{
- type Executor = executor::Null;
+ type Executor = crate::runtime::executor::Null;
type Flags = ();
type Message = T::Message;
diff --git a/src/window/settings.rs b/src/window/settings.rs
index 7bc49ce1..6b5d2985 100644
--- a/src/window/settings.rs
+++ b/src/window/settings.rs
@@ -18,9 +18,12 @@ pub struct Settings {
/// Whether the window should have a border, a title bar, etc. or not.
pub decorations: bool,
- /// Whether the window should be transparent
+ /// Whether the window should be transparent.
pub transparent: bool,
+ /// Whether the window will always be on top of other windows.
+ pub always_on_top: bool,
+
/// The icon of the window.
pub icon: Option<Icon>,
}
@@ -34,6 +37,7 @@ impl Default for Settings {
resizable: true,
decorations: true,
transparent: false,
+ always_on_top: false,
icon: None,
}
}
@@ -49,6 +53,7 @@ impl From<Settings> for iced_winit::settings::Window {
resizable: settings.resizable,
decorations: settings.decorations,
transparent: settings.transparent,
+ always_on_top: settings.always_on_top,
icon: settings.icon.map(Icon::into),
platform_specific: Default::default(),
}
diff --git a/winit/Cargo.toml b/winit/Cargo.toml
index 06e5df9a..7cf62821 100644
--- a/winit/Cargo.toml
+++ b/winit/Cargo.toml
@@ -14,7 +14,7 @@ categories = ["gui"]
debug = ["iced_native/debug"]
[dependencies]
-winit = "0.22"
+winit = "0.23"
window_clipboard = "0.1"
log = "0.4"
thiserror = "1.0"
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 638787ab..de38f246 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -127,7 +127,7 @@ pub fn window_event(
/// [`Mode`]: ../enum.Mode.html
/// [`winit`]: https://github.com/rust-windowing/winit
pub fn fullscreen(
- monitor: winit::monitor::MonitorHandle,
+ monitor: Option<winit::monitor::MonitorHandle>,
mode: Mode,
) -> Option<winit::window::Fullscreen> {
match mode {
@@ -299,7 +299,8 @@ pub fn key_code(virtual_keycode: winit::event::VirtualKeyCode) -> KeyCode {
winit::event::VirtualKeyCode::Numpad9 => KeyCode::Numpad9,
winit::event::VirtualKeyCode::AbntC1 => KeyCode::AbntC1,
winit::event::VirtualKeyCode::AbntC2 => KeyCode::AbntC2,
- winit::event::VirtualKeyCode::Add => KeyCode::Add,
+ winit::event::VirtualKeyCode::NumpadAdd => KeyCode::NumpadAdd,
+ winit::event::VirtualKeyCode::Plus => KeyCode::Plus,
winit::event::VirtualKeyCode::Apostrophe => KeyCode::Apostrophe,
winit::event::VirtualKeyCode::Apps => KeyCode::Apps,
winit::event::VirtualKeyCode::At => KeyCode::At,
@@ -310,8 +311,8 @@ pub fn key_code(virtual_keycode: winit::event::VirtualKeyCode) -> KeyCode {
winit::event::VirtualKeyCode::Colon => KeyCode::Colon,
winit::event::VirtualKeyCode::Comma => KeyCode::Comma,
winit::event::VirtualKeyCode::Convert => KeyCode::Convert,
- winit::event::VirtualKeyCode::Decimal => KeyCode::Decimal,
- winit::event::VirtualKeyCode::Divide => KeyCode::Divide,
+ winit::event::VirtualKeyCode::NumpadDecimal => KeyCode::NumpadDecimal,
+ winit::event::VirtualKeyCode::NumpadDivide => KeyCode::NumpadDivide,
winit::event::VirtualKeyCode::Equals => KeyCode::Equals,
winit::event::VirtualKeyCode::Grave => KeyCode::Grave,
winit::event::VirtualKeyCode::Kana => KeyCode::Kana,
@@ -325,7 +326,7 @@ pub fn key_code(virtual_keycode: winit::event::VirtualKeyCode) -> KeyCode {
winit::event::VirtualKeyCode::MediaSelect => KeyCode::MediaSelect,
winit::event::VirtualKeyCode::MediaStop => KeyCode::MediaStop,
winit::event::VirtualKeyCode::Minus => KeyCode::Minus,
- winit::event::VirtualKeyCode::Multiply => KeyCode::Multiply,
+ winit::event::VirtualKeyCode::NumpadMultiply => KeyCode::NumpadMultiply,
winit::event::VirtualKeyCode::Mute => KeyCode::Mute,
winit::event::VirtualKeyCode::MyComputer => KeyCode::MyComputer,
winit::event::VirtualKeyCode::NavigateForward => {
@@ -353,7 +354,7 @@ pub fn key_code(virtual_keycode: winit::event::VirtualKeyCode) -> KeyCode {
winit::event::VirtualKeyCode::Slash => KeyCode::Slash,
winit::event::VirtualKeyCode::Sleep => KeyCode::Sleep,
winit::event::VirtualKeyCode::Stop => KeyCode::Stop,
- winit::event::VirtualKeyCode::Subtract => KeyCode::Subtract,
+ winit::event::VirtualKeyCode::NumpadSubtract => KeyCode::NumpadSubtract,
winit::event::VirtualKeyCode::Sysrq => KeyCode::Sysrq,
winit::event::VirtualKeyCode::Tab => KeyCode::Tab,
winit::event::VirtualKeyCode::Underline => KeyCode::Underline,
@@ -372,6 +373,7 @@ pub fn key_code(virtual_keycode: winit::event::VirtualKeyCode) -> KeyCode {
winit::event::VirtualKeyCode::Copy => KeyCode::Copy,
winit::event::VirtualKeyCode::Paste => KeyCode::Paste,
winit::event::VirtualKeyCode::Cut => KeyCode::Cut,
+ winit::event::VirtualKeyCode::Asterisk => KeyCode::Asterisk,
}
}
diff --git a/winit/src/settings.rs b/winit/src/settings.rs
index 92541e7d..a6b96ec7 100644
--- a/winit/src/settings.rs
+++ b/winit/src/settings.rs
@@ -45,9 +45,12 @@ pub struct Window {
/// Whether the window should have a border, a title bar, etc.
pub decorations: bool,
- /// Whether the window should be transparent
+ /// Whether the window should be transparent.
pub transparent: bool,
+ /// Whether the window will always be on top of other windows.
+ pub always_on_top: bool,
+
/// The window icon, which is also usually used in the taskbar
pub icon: Option<winit::window::Icon>,
@@ -61,7 +64,7 @@ impl Window {
self,
title: &str,
mode: Mode,
- primary_monitor: MonitorHandle,
+ primary_monitor: Option<MonitorHandle>,
) -> WindowBuilder {
let mut window_builder = WindowBuilder::new();
@@ -74,6 +77,7 @@ impl Window {
.with_decorations(self.decorations)
.with_transparent(self.transparent)
.with_window_icon(self.icon)
+ .with_always_on_top(self.always_on_top)
.with_fullscreen(conversion::fullscreen(primary_monitor, mode));
if let Some((width, height)) = self.min_size {
@@ -108,6 +112,7 @@ impl Default for Window {
resizable: true,
decorations: true,
transparent: false,
+ always_on_top: false,
icon: None,
platform_specific: Default::default(),
}