diff options
author | 2024-12-17 17:28:46 +0100 | |
---|---|---|
committer | 2024-12-17 17:28:46 +0100 | |
commit | f2c9b6b2ffc50d67d9789e77cb55eeb2a0ebe470 (patch) | |
tree | 4941905adf134468acc079610bb6f25d7461d543 /core | |
parent | a687a837653a576cb0599f7bc8ecd9c6054213a9 (diff) | |
parent | e5545aaa579f428e45853d125ac86155d8395104 (diff) | |
download | iced-f2c9b6b2ffc50d67d9789e77cb55eeb2a0ebe470.tar.gz iced-f2c9b6b2ffc50d67d9789e77cb55eeb2a0ebe470.tar.bz2 iced-f2c9b6b2ffc50d67d9789e77cb55eeb2a0ebe470.zip |
Merge pull request #2698 from iced-rs/feature/test-crate
Headless Mode Testing
Diffstat (limited to '')
-rw-r--r-- | core/src/keyboard/key.rs | 6 | ||||
-rw-r--r-- | core/src/lib.rs | 2 | ||||
-rw-r--r-- | core/src/renderer.rs | 19 | ||||
-rw-r--r-- | core/src/settings.rs (renamed from src/settings.rs) | 13 | ||||
-rw-r--r-- | core/src/theme.rs | 34 | ||||
-rw-r--r-- | core/src/widget/operation.rs | 199 | ||||
-rw-r--r-- | core/src/widget/operation/focusable.rs | 35 | ||||
-rw-r--r-- | core/src/widget/operation/scrollable.rs | 6 | ||||
-rw-r--r-- | core/src/widget/operation/text_input.rs | 28 | ||||
-rw-r--r-- | core/src/widget/text.rs | 10 | ||||
-rw-r--r-- | core/src/window.rs | 2 | ||||
-rw-r--r-- | core/src/window/screenshot.rs (renamed from runtime/src/window/screenshot.rs) | 2 | ||||
-rw-r--r-- | core/src/window/settings.rs | 1 |
13 files changed, 288 insertions, 69 deletions
diff --git a/core/src/keyboard/key.rs b/core/src/keyboard/key.rs index 69a91902..47169d9a 100644 --- a/core/src/keyboard/key.rs +++ b/core/src/keyboard/key.rs @@ -32,6 +32,12 @@ impl Key { } } +impl From<Named> for Key { + fn from(named: Named) -> Self { + Self::Named(named) + } +} + /// A named key. /// /// This is mostly the `NamedKey` type found in [`winit`]. diff --git a/core/src/lib.rs b/core/src/lib.rs index df599f45..645f7a90 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -40,6 +40,7 @@ mod pixels; mod point; mod rectangle; mod rotation; +mod settings; mod shadow; mod shell; mod size; @@ -67,6 +68,7 @@ pub use point::Point; pub use rectangle::Rectangle; pub use renderer::Renderer; pub use rotation::Rotation; +pub use settings::Settings; pub use shadow::Shadow; pub use shell::Shell; pub use size::Size; diff --git a/core/src/renderer.rs b/core/src/renderer.rs index 6684517f..68e070e8 100644 --- a/core/src/renderer.rs +++ b/core/src/renderer.rs @@ -3,7 +3,8 @@ mod null; use crate::{ - Background, Border, Color, Rectangle, Shadow, Size, Transformation, Vector, + Background, Border, Color, Font, Pixels, Rectangle, Shadow, Size, + Transformation, Vector, }; /// A component that can be used by widgets to draw themselves on a screen. @@ -100,3 +101,19 @@ impl Default for Style { } } } + +/// A headless renderer is a renderer that can render offscreen without +/// a window nor a compositor. +pub trait Headless { + /// Creates a new [`Headless`] renderer; + fn new(default_font: Font, default_text_size: Pixels) -> Self; + + /// Draws offscreen into a screenshot, returning a collection of + /// bytes representing the rendered pixels in RGBA order. + fn screenshot( + &mut self, + size: Size<u32>, + scale_factor: f32, + background_color: Color, + ) -> Vec<u8>; +} diff --git a/src/settings.rs b/core/src/settings.rs index ebac7a86..3189c8d1 100644 --- a/src/settings.rs +++ b/core/src/settings.rs @@ -29,11 +29,9 @@ pub struct Settings { /// primitives. /// /// Enabling it can produce a smoother result in some widgets, like the - /// [`Canvas`], at a performance cost. + /// `canvas` widget, at a performance cost. /// /// By default, it is disabled. - /// - /// [`Canvas`]: crate::widget::Canvas pub antialiasing: bool, } @@ -48,12 +46,3 @@ impl Default for Settings { } } } - -impl From<Settings> for iced_winit::Settings { - fn from(settings: Settings) -> iced_winit::Settings { - iced_winit::Settings { - id: settings.id, - fonts: settings.fonts, - } - } -} diff --git a/core/src/theme.rs b/core/src/theme.rs index 6b2c04da..23480cec 100644 --- a/core/src/theme.rs +++ b/core/src/theme.rs @@ -3,6 +3,8 @@ pub mod palette; pub use palette::Palette; +use crate::Color; + use std::fmt; use std::sync::Arc; @@ -246,3 +248,35 @@ impl fmt::Display for Custom { write!(f, "{}", self.name) } } + +/// The base style of a [`Theme`]. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Style { + /// The background [`Color`] of the application. + pub background_color: Color, + + /// The default text [`Color`] of the application. + pub text_color: Color, +} + +/// The default blank style of a [`Theme`]. +pub trait Base { + /// Returns the default base [`Style`] of a [`Theme`]. + fn base(&self) -> Style; +} + +impl Base for Theme { + fn base(&self) -> Style { + default(self) + } +} + +/// The default [`Style`] of a built-in [`Theme`]. +pub fn default(theme: &Theme) -> Style { + let palette = theme.extended_palette(); + + Style { + background_color: palette.background.base.color, + text_color: palette.background.base.text, + } +} diff --git a/core/src/widget/operation.rs b/core/src/widget/operation.rs index 6bdb27f6..8fc627bf 100644 --- a/core/src/widget/operation.rs +++ b/core/src/widget/operation.rs @@ -30,24 +30,45 @@ pub trait Operation<T = ()>: Send { ); /// Operates on a widget that can be focused. - fn focusable(&mut self, _state: &mut dyn Focusable, _id: Option<&Id>) {} + fn focusable( + &mut self, + _id: Option<&Id>, + _bounds: Rectangle, + _state: &mut dyn Focusable, + ) { + } /// Operates on a widget that can be scrolled. fn scrollable( &mut self, - _state: &mut dyn Scrollable, _id: Option<&Id>, _bounds: Rectangle, _content_bounds: Rectangle, _translation: Vector, + _state: &mut dyn Scrollable, ) { } /// Operates on a widget that has text input. - fn text_input(&mut self, _state: &mut dyn TextInput, _id: Option<&Id>) {} + fn text_input( + &mut self, + _id: Option<&Id>, + _bounds: Rectangle, + _state: &mut dyn TextInput, + ) { + } + + /// Operates on a widget that contains some text. + fn text(&mut self, _id: Option<&Id>, _bounds: Rectangle, _text: &str) {} /// Operates on a custom widget with some state. - fn custom(&mut self, _state: &mut dyn Any, _id: Option<&Id>) {} + fn custom( + &mut self, + _id: Option<&Id>, + _bounds: Rectangle, + _state: &mut dyn Any, + ) { + } /// Finishes the [`Operation`] and returns its [`Outcome`]. fn finish(&self) -> Outcome<T> { @@ -68,33 +89,52 @@ where self.as_mut().container(id, bounds, operate_on_children); } - fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) { - self.as_mut().focusable(state, id); + fn focusable( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn Focusable, + ) { + self.as_mut().focusable(id, bounds, state); } fn scrollable( &mut self, - state: &mut dyn Scrollable, id: Option<&Id>, bounds: Rectangle, content_bounds: Rectangle, translation: Vector, + state: &mut dyn Scrollable, ) { self.as_mut().scrollable( - state, id, bounds, content_bounds, translation, + state, ); } - fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { - self.as_mut().text_input(state, id); + fn text_input( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn TextInput, + ) { + self.as_mut().text_input(id, bounds, state); + } + + fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) { + self.as_mut().text(id, bounds, text); } - fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) { - self.as_mut().custom(state, id); + fn custom( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn Any, + ) { + self.as_mut().custom(id, bounds, state); } fn finish(&self) -> Outcome<O> { @@ -150,33 +190,52 @@ where }); } - fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) { - self.operation.focusable(state, id); + fn focusable( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn Focusable, + ) { + self.operation.focusable(id, bounds, state); } fn scrollable( &mut self, - state: &mut dyn Scrollable, id: Option<&Id>, bounds: Rectangle, content_bounds: Rectangle, translation: Vector, + state: &mut dyn Scrollable, ) { self.operation.scrollable( - state, id, bounds, content_bounds, translation, + state, ); } - fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { - self.operation.text_input(state, id); + fn text_input( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn TextInput, + ) { + self.operation.text_input(id, bounds, state); } - fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) { - self.operation.custom(state, id); + fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) { + self.operation.text(id, bounds, text); + } + + fn custom( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn Any, + ) { + self.operation.custom(id, bounds, state); } fn finish(&self) -> Outcome<O> { @@ -234,39 +293,55 @@ where fn scrollable( &mut self, - state: &mut dyn Scrollable, id: Option<&Id>, bounds: Rectangle, content_bounds: Rectangle, translation: Vector, + state: &mut dyn Scrollable, ) { self.operation.scrollable( - state, id, bounds, content_bounds, translation, + state, ); } fn focusable( &mut self, - state: &mut dyn Focusable, id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn Focusable, ) { - self.operation.focusable(state, id); + self.operation.focusable(id, bounds, state); } fn text_input( &mut self, + id: Option<&Id>, + bounds: Rectangle, state: &mut dyn TextInput, + ) { + self.operation.text_input(id, bounds, state); + } + + fn text( + &mut self, id: Option<&Id>, + bounds: Rectangle, + text: &str, ) { - self.operation.text_input(state, id); + self.operation.text(id, bounds, text); } - fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) { - self.operation.custom(state, id); + fn custom( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn Any, + ) { + self.operation.custom(id, bounds, state); } } @@ -275,33 +350,52 @@ where MapRef { operation }.container(id, bounds, operate_on_children); } - fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) { - self.operation.focusable(state, id); + fn focusable( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn Focusable, + ) { + self.operation.focusable(id, bounds, state); } fn scrollable( &mut self, - state: &mut dyn Scrollable, id: Option<&Id>, bounds: Rectangle, content_bounds: Rectangle, translation: Vector, + state: &mut dyn Scrollable, ) { self.operation.scrollable( - state, id, bounds, content_bounds, translation, + state, ); } - fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { - self.operation.text_input(state, id); + fn text_input( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn TextInput, + ) { + self.operation.text_input(id, bounds, state); + } + + fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) { + self.operation.text(id, bounds, text); } - fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) { - self.operation.custom(state, id); + fn custom( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn Any, + ) { + self.operation.custom(id, bounds, state); } fn finish(&self) -> Outcome<B> { @@ -361,33 +455,52 @@ where }); } - fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) { - self.operation.focusable(state, id); + fn focusable( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn Focusable, + ) { + self.operation.focusable(id, bounds, state); } fn scrollable( &mut self, - state: &mut dyn Scrollable, id: Option<&Id>, bounds: Rectangle, content_bounds: Rectangle, translation: crate::Vector, + state: &mut dyn Scrollable, ) { self.operation.scrollable( - state, id, bounds, content_bounds, translation, + state, ); } - fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { - self.operation.text_input(state, id); + fn text_input( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn TextInput, + ) { + self.operation.text_input(id, bounds, state); } - fn custom(&mut self, state: &mut dyn std::any::Any, id: Option<&Id>) { - self.operation.custom(state, id); + fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) { + self.operation.text(id, bounds, text); + } + + fn custom( + &mut self, + id: Option<&Id>, + bounds: Rectangle, + state: &mut dyn Any, + ) { + self.operation.custom(id, bounds, state); } fn finish(&self) -> Outcome<B> { diff --git a/core/src/widget/operation/focusable.rs b/core/src/widget/operation/focusable.rs index 867c682e..8f66e575 100644 --- a/core/src/widget/operation/focusable.rs +++ b/core/src/widget/operation/focusable.rs @@ -32,7 +32,12 @@ pub fn focus<T>(target: Id) -> impl Operation<T> { } impl<T> Operation<T> for Focus { - fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) { + fn focusable( + &mut self, + id: Option<&Id>, + _bounds: Rectangle, + state: &mut dyn Focusable, + ) { match id { Some(id) if id == &self.target => { state.focus(); @@ -64,7 +69,12 @@ pub fn count() -> impl Operation<Count> { } impl Operation<Count> for CountFocusable { - fn focusable(&mut self, state: &mut dyn Focusable, _id: Option<&Id>) { + fn focusable( + &mut self, + _id: Option<&Id>, + _bounds: Rectangle, + state: &mut dyn Focusable, + ) { if state.is_focused() { self.count.focused = Some(self.count.total); } @@ -104,7 +114,12 @@ where } impl<T> Operation<T> for FocusPrevious { - fn focusable(&mut self, state: &mut dyn Focusable, _id: Option<&Id>) { + fn focusable( + &mut self, + _id: Option<&Id>, + _bounds: Rectangle, + state: &mut dyn Focusable, + ) { if self.count.total == 0 { return; } @@ -147,7 +162,12 @@ where } impl<T> Operation<T> for FocusNext { - fn focusable(&mut self, state: &mut dyn Focusable, _id: Option<&Id>) { + fn focusable( + &mut self, + _id: Option<&Id>, + _bounds: Rectangle, + state: &mut dyn Focusable, + ) { match self.count.focused { None if self.current == 0 => state.focus(), Some(focused) if focused == self.current => state.unfocus(), @@ -179,7 +199,12 @@ pub fn find_focused() -> impl Operation<Id> { } impl Operation<Id> for FindFocused { - fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) { + fn focusable( + &mut self, + id: Option<&Id>, + _bounds: Rectangle, + state: &mut dyn Focusable, + ) { if state.is_focused() && id.is_some() { self.focused = id.cloned(); } diff --git a/core/src/widget/operation/scrollable.rs b/core/src/widget/operation/scrollable.rs index c2fecf56..7c78c087 100644 --- a/core/src/widget/operation/scrollable.rs +++ b/core/src/widget/operation/scrollable.rs @@ -39,11 +39,11 @@ pub fn snap_to<T>(target: Id, offset: RelativeOffset) -> impl Operation<T> { fn scrollable( &mut self, - state: &mut dyn Scrollable, id: Option<&Id>, _bounds: Rectangle, _content_bounds: Rectangle, _translation: Vector, + state: &mut dyn Scrollable, ) { if Some(&self.target) == id { state.snap_to(self.offset); @@ -74,11 +74,11 @@ pub fn scroll_to<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> { fn scrollable( &mut self, - state: &mut dyn Scrollable, id: Option<&Id>, _bounds: Rectangle, _content_bounds: Rectangle, _translation: Vector, + state: &mut dyn Scrollable, ) { if Some(&self.target) == id { state.scroll_to(self.offset); @@ -109,11 +109,11 @@ pub fn scroll_by<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> { fn scrollable( &mut self, - state: &mut dyn Scrollable, id: Option<&Id>, bounds: Rectangle, content_bounds: Rectangle, _translation: Vector, + state: &mut dyn Scrollable, ) { if Some(&self.target) == id { state.scroll_by(self.offset, bounds, content_bounds); diff --git a/core/src/widget/operation/text_input.rs b/core/src/widget/operation/text_input.rs index 41731d4c..a46f1a2d 100644 --- a/core/src/widget/operation/text_input.rs +++ b/core/src/widget/operation/text_input.rs @@ -23,7 +23,12 @@ pub fn move_cursor_to_front<T>(target: Id) -> impl Operation<T> { } impl<T> Operation<T> for MoveCursor { - fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { + fn text_input( + &mut self, + id: Option<&Id>, + _bounds: Rectangle, + state: &mut dyn TextInput, + ) { match id { Some(id) if id == &self.target => { state.move_cursor_to_front(); @@ -53,7 +58,12 @@ pub fn move_cursor_to_end<T>(target: Id) -> impl Operation<T> { } impl<T> Operation<T> for MoveCursor { - fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { + fn text_input( + &mut self, + id: Option<&Id>, + _bounds: Rectangle, + state: &mut dyn TextInput, + ) { match id { Some(id) if id == &self.target => { state.move_cursor_to_end(); @@ -84,7 +94,12 @@ pub fn move_cursor_to<T>(target: Id, position: usize) -> impl Operation<T> { } impl<T> Operation<T> for MoveCursor { - fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { + fn text_input( + &mut self, + id: Option<&Id>, + _bounds: Rectangle, + state: &mut dyn TextInput, + ) { match id { Some(id) if id == &self.target => { state.move_cursor_to(self.position); @@ -113,7 +128,12 @@ pub fn select_all<T>(target: Id) -> impl Operation<T> { } impl<T> Operation<T> for MoveCursor { - fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { + fn text_input( + &mut self, + id: Option<&Id>, + _bounds: Rectangle, + state: &mut dyn TextInput, + ) { match id { Some(id) if id == &self.target => { state.select_all(); diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index d3d1cffd..c7ec3c8b 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -267,6 +267,16 @@ where draw(renderer, defaults, layout, state.0.raw(), style, viewport); } + + fn operate( + &self, + _state: &mut Tree, + layout: Layout<'_>, + _renderer: &Renderer, + operation: &mut dyn super::Operation, + ) { + operation.text(None, layout.bounds(), &self.fragment); + } } /// Produces the [`layout::Node`] of a [`Text`] widget. diff --git a/core/src/window.rs b/core/src/window.rs index 448ffc45..a3389998 100644 --- a/core/src/window.rs +++ b/core/src/window.rs @@ -1,5 +1,6 @@ //! Build window-based GUI applications. pub mod icon; +pub mod screenshot; pub mod settings; mod event; @@ -17,5 +18,6 @@ pub use level::Level; pub use mode::Mode; pub use position::Position; pub use redraw_request::RedrawRequest; +pub use screenshot::Screenshot; pub use settings::Settings; pub use user_attention::UserAttention; diff --git a/runtime/src/window/screenshot.rs b/core/src/window/screenshot.rs index d9adbc01..424168bb 100644 --- a/runtime/src/window/screenshot.rs +++ b/core/src/window/screenshot.rs @@ -1,5 +1,5 @@ //! Take screenshots of a window. -use crate::core::{Rectangle, Size}; +use crate::{Rectangle, Size}; use bytes::Bytes; use std::fmt::{Debug, Formatter}; diff --git a/core/src/window/settings.rs b/core/src/window/settings.rs index fbbf86ab..c1f36a6c 100644 --- a/core/src/window/settings.rs +++ b/core/src/window/settings.rs @@ -28,6 +28,7 @@ use crate::window::{Icon, Level, Position}; use crate::Size; pub use platform::PlatformSpecific; + /// The window settings of an application. #[derive(Debug, Clone)] pub struct Settings { |