Merge branch 'iced-rs:master' into viewer_content_fit
This commit is contained in:
commit
0ebe0629ce
124 changed files with 5702 additions and 4490 deletions
|
|
@ -17,7 +17,7 @@ use crate::core::mouse;
|
|||
use crate::core::renderer;
|
||||
use crate::core::widget::tree::{self, Tree};
|
||||
use crate::core::{
|
||||
Clipboard, Element, Length, Rectangle, Shell, Size, Transformation, Widget,
|
||||
Clipboard, Element, Length, Rectangle, Shell, Size, Vector, Widget,
|
||||
};
|
||||
use crate::graphics::geometry;
|
||||
|
||||
|
|
@ -222,8 +222,8 @@ where
|
|||
|
||||
let state = tree.state.downcast_ref::<P::State>();
|
||||
|
||||
renderer.with_transformation(
|
||||
Transformation::translate(bounds.x, bounds.y),
|
||||
renderer.with_translation(
|
||||
Vector::new(bounds.x, bounds.y),
|
||||
|renderer| {
|
||||
let layers =
|
||||
self.program.draw(state, renderer, theme, bounds, cursor);
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ where
|
|||
if self.is_checked {
|
||||
renderer.fill_text(
|
||||
text::Text {
|
||||
content: &code_point.to_string(),
|
||||
content: code_point.to_string(),
|
||||
font: *font,
|
||||
size,
|
||||
line_height: *line_height,
|
||||
|
|
|
|||
|
|
@ -33,11 +33,18 @@ where
|
|||
Self::from_vec(Vec::new())
|
||||
}
|
||||
|
||||
/// Creates a [`Column`] with the given capacity.
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self::from_vec(Vec::with_capacity(capacity))
|
||||
}
|
||||
|
||||
/// Creates a [`Column`] with the given elements.
|
||||
pub fn with_children(
|
||||
children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,
|
||||
) -> Self {
|
||||
Self::new().extend(children)
|
||||
let iterator = children.into_iter();
|
||||
|
||||
Self::with_capacity(iterator.size_hint().0).extend(iterator)
|
||||
}
|
||||
|
||||
/// Creates a [`Column`] from an already allocated [`Vec`].
|
||||
|
|
|
|||
|
|
@ -700,38 +700,47 @@ where
|
|||
..
|
||||
} = tree.state.downcast_mut::<Menu<T>>();
|
||||
|
||||
let bounds = layout.bounds();
|
||||
|
||||
self.state.sync_filtered_options(filtered_options);
|
||||
|
||||
let mut menu = menu::Menu::new(
|
||||
menu,
|
||||
&filtered_options.options,
|
||||
hovered_option,
|
||||
|x| {
|
||||
tree.children[0]
|
||||
.state
|
||||
.downcast_mut::<text_input::State<Renderer::Paragraph>>(
|
||||
)
|
||||
.unfocus();
|
||||
if filtered_options.options.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let bounds = layout.bounds();
|
||||
|
||||
(self.on_selected)(x)
|
||||
},
|
||||
self.on_option_hovered.as_deref(),
|
||||
&self.menu_class,
|
||||
)
|
||||
.width(bounds.width)
|
||||
.padding(self.padding);
|
||||
let mut menu = menu::Menu::new(
|
||||
menu,
|
||||
&filtered_options.options,
|
||||
hovered_option,
|
||||
|x| {
|
||||
tree.children[0]
|
||||
.state
|
||||
.downcast_mut::<text_input::State<Renderer::Paragraph>>(
|
||||
)
|
||||
.unfocus();
|
||||
|
||||
if let Some(font) = self.font {
|
||||
menu = menu.font(font);
|
||||
(self.on_selected)(x)
|
||||
},
|
||||
self.on_option_hovered.as_deref(),
|
||||
&self.menu_class,
|
||||
)
|
||||
.width(bounds.width)
|
||||
.padding(self.padding);
|
||||
|
||||
if let Some(font) = self.font {
|
||||
menu = menu.font(font);
|
||||
}
|
||||
|
||||
if let Some(size) = self.size {
|
||||
menu = menu.text_size(size);
|
||||
}
|
||||
|
||||
Some(
|
||||
menu.overlay(
|
||||
layout.position() + translation,
|
||||
bounds.height,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if let Some(size) = self.size {
|
||||
menu = menu.text_size(size);
|
||||
}
|
||||
|
||||
Some(menu.overlay(layout.position() + translation, bounds.height))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,13 +145,26 @@ where
|
|||
///
|
||||
/// [`Text`]: core::widget::Text
|
||||
pub fn text<'a, Theme, Renderer>(
|
||||
text: impl ToString,
|
||||
text: impl text::IntoFragment<'a>,
|
||||
) -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
Renderer: core::text::Renderer,
|
||||
{
|
||||
Text::new(text.to_string())
|
||||
Text::new(text)
|
||||
}
|
||||
|
||||
/// Creates a new [`Text`] widget that displays the provided value.
|
||||
///
|
||||
/// [`Text`]: core::widget::Text
|
||||
pub fn value<'a, Theme, Renderer>(
|
||||
value: impl ToString,
|
||||
) -> Text<'a, Theme, Renderer>
|
||||
where
|
||||
Theme: text::Catalog + 'a,
|
||||
Renderer: core::text::Renderer,
|
||||
{
|
||||
Text::new(value.to_string())
|
||||
}
|
||||
|
||||
/// Creates a new [`Checkbox`].
|
||||
|
|
|
|||
|
|
@ -40,27 +40,49 @@ where
|
|||
{
|
||||
/// Creates an empty [`Column`].
|
||||
pub fn new() -> Self {
|
||||
Column {
|
||||
Self::from_vecs(Vec::new(), Vec::new())
|
||||
}
|
||||
|
||||
/// Creates a [`Column`] from already allocated [`Vec`]s.
|
||||
///
|
||||
/// Keep in mind that the [`Column`] will not inspect the [`Vec`]s, which means
|
||||
/// it won't automatically adapt to the sizing strategy of its contents.
|
||||
///
|
||||
/// If any of the children have a [`Length::Fill`] strategy, you will need to
|
||||
/// call [`Column::width`] or [`Column::height`] accordingly.
|
||||
pub fn from_vecs(
|
||||
keys: Vec<Key>,
|
||||
children: Vec<Element<'a, Message, Theme, Renderer>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
spacing: 0.0,
|
||||
padding: Padding::ZERO,
|
||||
width: Length::Shrink,
|
||||
height: Length::Shrink,
|
||||
max_width: f32::INFINITY,
|
||||
align_items: Alignment::Start,
|
||||
keys: Vec::new(),
|
||||
children: Vec::new(),
|
||||
keys,
|
||||
children,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a [`Column`] with the given capacity.
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self::from_vecs(
|
||||
Vec::with_capacity(capacity),
|
||||
Vec::with_capacity(capacity),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a [`Column`] with the given elements.
|
||||
pub fn with_children(
|
||||
children: impl IntoIterator<
|
||||
Item = (Key, Element<'a, Message, Theme, Renderer>),
|
||||
>,
|
||||
) -> Self {
|
||||
children
|
||||
.into_iter()
|
||||
.fold(Self::new(), |column, (key, child)| column.push(key, child))
|
||||
let iterator = children.into_iter();
|
||||
|
||||
Self::with_capacity(iterator.size_hint().0).extend(iterator)
|
||||
}
|
||||
|
||||
/// Sets the vertical spacing _between_ elements.
|
||||
|
|
@ -132,6 +154,18 @@ where
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Extends the [`Column`] with the given children.
|
||||
pub fn extend(
|
||||
self,
|
||||
children: impl IntoIterator<
|
||||
Item = (Key, Element<'a, Message, Theme, Renderer>),
|
||||
>,
|
||||
) -> Self {
|
||||
children
|
||||
.into_iter()
|
||||
.fold(self, |column, (key, child)| column.push(key, child))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Key, Message, Renderer> Default for Column<'a, Key, Message, Renderer>
|
||||
|
|
|
|||
|
|
@ -18,11 +18,12 @@ use crate::core::widget::tree::{self, Tree};
|
|||
use crate::core::widget::{self, Widget};
|
||||
use crate::core::Element;
|
||||
use crate::core::{
|
||||
self, Clipboard, Hasher, Length, Point, Rectangle, Shell, Size, Vector,
|
||||
self, Clipboard, Length, Point, Rectangle, Shell, Size, Vector,
|
||||
};
|
||||
use crate::runtime::overlay::Nested;
|
||||
|
||||
use ouroboros::self_referencing;
|
||||
use rustc_hash::FxHasher;
|
||||
use std::cell::RefCell;
|
||||
use std::hash::{Hash, Hasher as H};
|
||||
use std::rc::Rc;
|
||||
|
|
@ -106,9 +107,12 @@ where
|
|||
}
|
||||
|
||||
fn state(&self) -> tree::State {
|
||||
let mut hasher = Hasher::default();
|
||||
self.dependency.hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
let hash = {
|
||||
let mut hasher = FxHasher::default();
|
||||
self.dependency.hash(&mut hasher);
|
||||
|
||||
hasher.finish()
|
||||
};
|
||||
|
||||
let element =
|
||||
Rc::new(RefCell::new(Some((self.view)(&self.dependency).into())));
|
||||
|
|
@ -127,9 +131,12 @@ where
|
|||
.state
|
||||
.downcast_mut::<Internal<Message, Theme, Renderer>>();
|
||||
|
||||
let mut hasher = Hasher::default();
|
||||
self.dependency.hash(&mut hasher);
|
||||
let new_hash = hasher.finish();
|
||||
let new_hash = {
|
||||
let mut hasher = FxHasher::default();
|
||||
self.dependency.hash(&mut hasher);
|
||||
|
||||
hasher.finish()
|
||||
};
|
||||
|
||||
if current.hash != new_hash {
|
||||
current.hash = new_hash;
|
||||
|
|
|
|||
|
|
@ -2,13 +2,6 @@
|
|||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
||||
)]
|
||||
#![forbid(unsafe_code, rust_2018_idioms)]
|
||||
#![deny(
|
||||
missing_debug_implementations,
|
||||
missing_docs,
|
||||
unused_results,
|
||||
rustdoc::broken_intra_doc_links
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
pub use iced_renderer as renderer;
|
||||
pub use iced_renderer::graphics;
|
||||
|
|
|
|||
|
|
@ -526,7 +526,7 @@ where
|
|||
|
||||
renderer.fill_text(
|
||||
Text {
|
||||
content: &option.to_string(),
|
||||
content: option.to_string(),
|
||||
bounds: Size::new(f32::INFINITY, bounds.height),
|
||||
size: text_size,
|
||||
line_height: self.text_line_height,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::pane_grid::{
|
|||
Axis, Configuration, Direction, Edge, Node, Pane, Region, Split, Target,
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
/// The state of a [`PaneGrid`].
|
||||
///
|
||||
|
|
@ -25,7 +25,7 @@ pub struct State<T> {
|
|||
/// The panes of the [`PaneGrid`].
|
||||
///
|
||||
/// [`PaneGrid`]: super::PaneGrid
|
||||
pub panes: HashMap<Pane, T>,
|
||||
pub panes: FxHashMap<Pane, T>,
|
||||
|
||||
/// The internal state of the [`PaneGrid`].
|
||||
///
|
||||
|
|
@ -52,7 +52,7 @@ impl<T> State<T> {
|
|||
|
||||
/// Creates a new [`State`] with the given [`Configuration`].
|
||||
pub fn with_configuration(config: impl Into<Configuration<T>>) -> Self {
|
||||
let mut panes = HashMap::new();
|
||||
let mut panes = FxHashMap::default();
|
||||
|
||||
let internal =
|
||||
Internal::from_configuration(&mut panes, config.into(), 0);
|
||||
|
|
@ -353,7 +353,7 @@ impl Internal {
|
|||
///
|
||||
/// [`PaneGrid`]: super::PaneGrid
|
||||
pub fn from_configuration<T>(
|
||||
panes: &mut HashMap<Pane, T>,
|
||||
panes: &mut FxHashMap<Pane, T>,
|
||||
content: Configuration<T>,
|
||||
next_id: usize,
|
||||
) -> Self {
|
||||
|
|
|
|||
|
|
@ -479,7 +479,7 @@ where
|
|||
|
||||
renderer.fill_text(
|
||||
Text {
|
||||
content: &code_point.to_string(),
|
||||
content: code_point.to_string(),
|
||||
size,
|
||||
line_height,
|
||||
font,
|
||||
|
|
@ -502,7 +502,7 @@ where
|
|||
|
||||
let label = selected.map(ToString::to_string);
|
||||
|
||||
if let Some(label) = label.as_deref().or(self.placeholder.as_deref()) {
|
||||
if let Some(label) = label.or_else(|| self.placeholder.clone()) {
|
||||
let text_size =
|
||||
self.text_size.unwrap_or_else(|| renderer.default_size());
|
||||
|
||||
|
|
|
|||
|
|
@ -31,11 +31,18 @@ where
|
|||
Self::from_vec(Vec::new())
|
||||
}
|
||||
|
||||
/// Creates a [`Row`] with the given capacity.
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self::from_vec(Vec::with_capacity(capacity))
|
||||
}
|
||||
|
||||
/// Creates a [`Row`] with the given elements.
|
||||
pub fn with_children(
|
||||
children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,
|
||||
) -> Self {
|
||||
Self::new().extend(children)
|
||||
let iterator = children.into_iter();
|
||||
|
||||
Self::with_capacity(iterator.size_hint().0).extend(iterator)
|
||||
}
|
||||
|
||||
/// Creates a [`Row`] from an already allocated [`Vec`].
|
||||
|
|
|
|||
|
|
@ -651,7 +651,7 @@ where
|
|||
defaults: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
_viewport: &Rectangle,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
let state = tree.state.downcast_ref::<State>();
|
||||
|
||||
|
|
@ -767,8 +767,8 @@ where
|
|||
|
||||
renderer.with_layer(
|
||||
Rectangle {
|
||||
width: bounds.width + 2.0,
|
||||
height: bounds.height + 2.0,
|
||||
width: (bounds.width + 2.0).min(viewport.width),
|
||||
height: (bounds.height + 2.0).min(viewport.height),
|
||||
..bounds
|
||||
},
|
||||
|renderer| {
|
||||
|
|
|
|||
|
|
@ -13,12 +13,13 @@ use crate::core::widget::tree::{self, Tree};
|
|||
use crate::core::widget::{self, Widget};
|
||||
use crate::core::window;
|
||||
use crate::core::{Clipboard, Element, Length, Rectangle, Shell, Size};
|
||||
use crate::renderer::wgpu::primitive::pipeline;
|
||||
use crate::renderer::wgpu::primitive;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub use crate::graphics::Viewport;
|
||||
pub use crate::renderer::wgpu::wgpu;
|
||||
pub use pipeline::{Primitive, Storage};
|
||||
pub use primitive::{Primitive, Storage};
|
||||
|
||||
/// A widget which can render custom shaders with Iced's `wgpu` backend.
|
||||
///
|
||||
|
|
@ -60,7 +61,7 @@ impl<P, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
|
|||
for Shader<Message, P>
|
||||
where
|
||||
P: Program<Message>,
|
||||
Renderer: pipeline::Renderer,
|
||||
Renderer: primitive::Renderer,
|
||||
{
|
||||
fn tag(&self) -> tree::Tag {
|
||||
struct Tag<T>(T);
|
||||
|
|
@ -160,7 +161,7 @@ where
|
|||
let bounds = layout.bounds();
|
||||
let state = tree.state.downcast_ref::<P::State>();
|
||||
|
||||
renderer.draw_pipeline_primitive(
|
||||
renderer.draw_primitive(
|
||||
bounds,
|
||||
self.program.draw(state, cursor_position, bounds),
|
||||
);
|
||||
|
|
@ -171,7 +172,7 @@ impl<'a, Message, Theme, Renderer, P> From<Shader<Message, P>>
|
|||
for Element<'a, Message, Theme, Renderer>
|
||||
where
|
||||
Message: 'a,
|
||||
Renderer: pipeline::Renderer,
|
||||
Renderer: primitive::Renderer,
|
||||
P: Program<Message> + 'a,
|
||||
{
|
||||
fn from(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::core::event;
|
||||
use crate::core::mouse;
|
||||
use crate::core::{Rectangle, Shell};
|
||||
use crate::renderer::wgpu::primitive::pipeline;
|
||||
use crate::renderer::wgpu::Primitive;
|
||||
use crate::shader;
|
||||
|
||||
/// The state and logic of a [`Shader`] widget.
|
||||
|
|
@ -15,7 +15,7 @@ pub trait Program<Message> {
|
|||
type State: Default + 'static;
|
||||
|
||||
/// The type of primitive this [`Program`] can draw.
|
||||
type Primitive: pipeline::Primitive + 'static;
|
||||
type Primitive: Primitive + 'static;
|
||||
|
||||
/// Update the internal [`State`] of the [`Program`]. This can be used to reflect state changes
|
||||
/// based on mouse & other events. You can use the [`Shell`] to publish messages, request a
|
||||
|
|
|
|||
|
|
@ -110,6 +110,21 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the text size of the [`TextEditor`].
|
||||
pub fn size(mut self, size: impl Into<Pixels>) -> Self {
|
||||
self.text_size = Some(size.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the [`text::LineHeight`] of the [`TextEditor`].
|
||||
pub fn line_height(
|
||||
mut self,
|
||||
line_height: impl Into<text::LineHeight>,
|
||||
) -> Self {
|
||||
self.line_height = line_height.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the [`Padding`] of the [`TextEditor`].
|
||||
pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
|
||||
self.padding = padding.into();
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ where
|
|||
let placeholder_text = Text {
|
||||
font,
|
||||
line_height: self.line_height,
|
||||
content: &self.placeholder,
|
||||
content: self.placeholder.as_str(),
|
||||
bounds: Size::new(f32::INFINITY, text_bounds.height),
|
||||
size: text_size,
|
||||
horizontal_alignment: alignment::Horizontal::Left,
|
||||
|
|
@ -251,9 +251,11 @@ where
|
|||
});
|
||||
|
||||
if let Some(icon) = &self.icon {
|
||||
let mut content = [0; 4];
|
||||
|
||||
let icon_text = Text {
|
||||
line_height: self.line_height,
|
||||
content: &icon.code_point.to_string(),
|
||||
content: icon.code_point.encode_utf8(&mut content) as &_,
|
||||
font: icon.font,
|
||||
size: icon.size.unwrap_or_else(|| renderer.default_size()),
|
||||
bounds: Size::new(f32::INFINITY, text_bounds.height),
|
||||
|
|
@ -366,7 +368,7 @@ where
|
|||
|
||||
let text = value.to_string();
|
||||
|
||||
let (cursor, offset) = if let Some(focus) = state
|
||||
let (cursor, offset, is_selecting) = if let Some(focus) = state
|
||||
.is_focused
|
||||
.as_ref()
|
||||
.filter(|focus| focus.is_window_focused)
|
||||
|
|
@ -404,7 +406,7 @@ where
|
|||
None
|
||||
};
|
||||
|
||||
(cursor, offset)
|
||||
(cursor, offset, false)
|
||||
}
|
||||
cursor::State::Selection { start, end } => {
|
||||
let left = start.min(end);
|
||||
|
|
@ -444,11 +446,12 @@ where
|
|||
} else {
|
||||
left_offset
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(None, 0.0)
|
||||
(None, 0.0, false)
|
||||
};
|
||||
|
||||
let draw = |renderer: &mut Renderer, viewport| {
|
||||
|
|
@ -480,7 +483,7 @@ where
|
|||
);
|
||||
};
|
||||
|
||||
if cursor.is_some() {
|
||||
if is_selecting {
|
||||
renderer
|
||||
.with_layer(text_bounds, |renderer| draw(renderer, *viewport));
|
||||
} else {
|
||||
|
|
@ -710,7 +713,8 @@ where
|
|||
|
||||
match key.as_ref() {
|
||||
keyboard::Key::Character("c")
|
||||
if state.keyboard_modifiers.command() =>
|
||||
if state.keyboard_modifiers.command()
|
||||
&& !self.is_secure =>
|
||||
{
|
||||
if let Some((start, end)) =
|
||||
state.cursor.selection(&self.value)
|
||||
|
|
@ -724,7 +728,8 @@ where
|
|||
return event::Status::Captured;
|
||||
}
|
||||
keyboard::Key::Character("x")
|
||||
if state.keyboard_modifiers.command() =>
|
||||
if state.keyboard_modifiers.command()
|
||||
&& !self.is_secure =>
|
||||
{
|
||||
if let Some((start, end)) =
|
||||
state.cursor.selection(&self.value)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue