Cosmic advanced text (#103)

* wip: update to use cosmic-advanced-text

* use cosmic-advanced-text branch of iced

* fix: line height and spacing for segmented button and update to get svg fix

* fix: spin button styling & spacing

* update iced to fix segmented button border radius

* feat: example improvements

* feat: helper for loading fonts

* feat: add focus style to button

* fix: slider height and iced fixed

* feat: hash icon width and height

* cleanup

* update ci

* refactor: always use lazy feature of iced

* update iced

* update iced

* cleanup & update iced

* update iced: new slider & tiny-skia quad updates

* update iced: fixes for tiny-skia quad rendering with edge case border radius

* re-export iced_runtime & iced_widget

* merge master

* udpate iced

* update iced

* update iced

* update iced

* fix: make rectangle_tracker subscription only return update if there is some

* feat: derive macro for loading a cosmic-config

* feat (cosmic-config): iced subscription

* fix (example): update to rectangle tracker subscription

* fix (cosmic-config)

* refactor(cosmic-config-derive): add support for types with generic parameters

* fix (cosmic-config): feature gate updates for subscription helpers

* feat: support for custom & system themes + move cosmic-theme to libcosmic

* feat: sorta hacky way of creating header bars for libcosmic + update iced to get support for resizable windows in iced-sctk

* update iced

* update and reexport sctk

* fix: applet border radius

* feat (cosmic-theme): add id and name methods

* fix(cosmic-theme): reexport palette from cosmic-theme

* fix(cosmic-config-derive): allow use with reexported cosmic-config

* feat: update iced with fix and refactor applet env vars

* update iced
This commit is contained in:
Ashley Wulber 2023-05-30 12:03:15 -04:00 committed by GitHub
parent a173794bed
commit e056e8c830
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 3431 additions and 405 deletions

View file

@ -1,13 +1,13 @@
use iced::widget::Container;
use iced::Size;
use iced_native::alignment;
use iced_native::event::{self, Event};
use iced_native::layout;
use iced_native::mouse;
use iced_native::overlay;
use iced_native::renderer;
use iced_native::widget::{Operation, Tree};
use iced_native::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
use iced_core::alignment;
use iced_core::event::{self, Event};
use iced_core::layout;
use iced_core::mouse;
use iced_core::overlay;
use iced_core::renderer;
use iced_core::widget::Tree;
use iced_core::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
pub use iced_style::container::{Appearance, StyleSheet};
@ -27,7 +27,7 @@ where
#[allow(missing_debug_implementations)]
pub struct AspectRatio<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet,
{
ratio: f32,
@ -36,7 +36,7 @@ where
impl<'a, Message, Renderer> AspectRatio<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet,
{
fn constrain_limits(&self, size: Size) -> Size {
@ -55,7 +55,7 @@ where
impl<'a, Message, Renderer> AspectRatio<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet,
{
/// Creates an empty [`Container`].
@ -92,14 +92,14 @@ where
/// Sets the maximum width of the [`Container`].
#[must_use]
pub fn max_width(mut self, max_width: u32) -> Self {
pub fn max_width(mut self, max_width: f32) -> Self {
self.container = self.container.max_width(max_width);
self
}
/// Sets the maximum height of the [`Container`] in pixels.
#[must_use]
pub fn max_height(mut self, max_height: u32) -> Self {
pub fn max_height(mut self, max_height: f32) -> Self {
self.container = self.container.max_height(max_height);
self
}
@ -142,14 +142,14 @@ where
impl<'a, Message, Renderer> Widget<Message, Renderer> for AspectRatio<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet,
{
fn children(&self) -> Vec<Tree> {
self.container.children()
}
fn diff(&self, tree: &mut Tree) {
fn diff(&mut self, tree: &mut Tree) {
self.container.diff(tree);
}
@ -169,8 +169,16 @@ where
self.container.layout(renderer, &custom_limits)
}
fn operate(&self, tree: &mut Tree, layout: Layout<'_>, operation: &mut dyn Operation<Message>) {
self.container.operate(tree, layout, operation);
fn operate(
&self,
tree: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn iced_core::widget::Operation<
iced_core::widget::OperationOutputWrapper<Message>,
>,
) {
self.container.operate(tree, layout, renderer, operation);
}
fn on_event(
@ -228,7 +236,7 @@ where
}
fn overlay<'b>(
&'b self,
&'b mut self,
tree: &'b mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
@ -241,7 +249,7 @@ impl<'a, Message, Renderer> From<AspectRatio<'a, Message, Renderer>>
for Element<'a, Message, Renderer>
where
Message: 'a,
Renderer: 'a + iced_native::Renderer,
Renderer: 'a + iced_core::Renderer,
Renderer::Theme: StyleSheet,
{
fn from(column: AspectRatio<'a, Message, Renderer>) -> Element<'a, Message, Renderer> {

View file

@ -1,13 +1,13 @@
use cosmic_theme::LayeredTheme;
use iced::widget::Container;
use iced_native::alignment;
use iced_native::event::{self, Event};
use iced_native::layout;
use iced_native::mouse;
use iced_native::overlay;
use iced_native::renderer;
use iced_native::widget::{Operation, Tree};
use iced_native::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
use iced_core::alignment;
use iced_core::event::{self, Event};
use iced_core::layout;
use iced_core::mouse;
use iced_core::overlay;
use iced_core::renderer;
use iced_core::widget::Tree;
use iced_core::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
pub use iced_style::container::{Appearance, StyleSheet};
pub fn container<'a, Message: 'static, T>(
@ -25,7 +25,7 @@ where
#[allow(missing_debug_implementations)]
pub struct LayerContainer<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet + Clone + cosmic_theme::LayeredTheme,
{
layer: Option<cosmic_theme::Layer>,
@ -34,7 +34,7 @@ where
impl<'a, Message, Renderer> LayerContainer<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet + Clone + cosmic_theme::LayeredTheme,
<Renderer::Theme as StyleSheet>::Style: std::convert::From<crate::theme::Container>,
{
@ -83,14 +83,14 @@ where
/// Sets the maximum width of the [`LayerContainer`].
#[must_use]
pub fn max_width(mut self, max_width: u32) -> Self {
pub fn max_width(mut self, max_width: f32) -> Self {
self.container = self.container.max_width(max_width);
self
}
/// Sets the maximum height of the [`LayerContainer`] in pixels.
#[must_use]
pub fn max_height(mut self, max_height: u32) -> Self {
pub fn max_height(mut self, max_height: f32) -> Self {
self.container = self.container.max_height(max_height);
self
}
@ -133,14 +133,14 @@ where
impl<'a, Message, Renderer> Widget<Message, Renderer> for LayerContainer<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet + Clone + cosmic_theme::LayeredTheme,
{
fn children(&self) -> Vec<Tree> {
self.container.children()
}
fn diff(&self, tree: &mut Tree) {
fn diff(&mut self, tree: &mut Tree) {
self.container.diff(tree);
}
@ -156,8 +156,16 @@ where
self.container.layout(renderer, limits)
}
fn operate(&self, tree: &mut Tree, layout: Layout<'_>, operation: &mut dyn Operation<Message>) {
self.container.operate(tree, layout, operation);
fn operate(
&self,
tree: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn iced_core::widget::Operation<
iced_core::widget::OperationOutputWrapper<Message>,
>,
) {
self.container.operate(tree, layout, renderer, operation);
}
fn on_event(
@ -222,7 +230,7 @@ where
}
fn overlay<'b>(
&'b self,
&'b mut self,
tree: &'b mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
@ -235,7 +243,7 @@ impl<'a, Message, Renderer> From<LayerContainer<'a, Message, Renderer>>
for Element<'a, Message, Renderer>
where
Message: 'a,
Renderer: 'a + iced_native::Renderer,
Renderer: 'a + iced_core::Renderer,
Renderer::Theme: StyleSheet + Clone + cosmic_theme::LayeredTheme,
{
fn from(column: LayerContainer<'a, Message, Renderer>) -> Element<'a, Message, Renderer> {

View file

@ -5,6 +5,7 @@ use crate::{theme, Element};
use apply::Apply;
use derive_setters::Setters;
use iced::{self, widget, Length};
use iced_core::renderer::BorderRadius;
use std::borrow::Cow;
#[must_use]
@ -74,12 +75,13 @@ impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> {
});
let mut widget = widget::row(packed)
.height(Length::Units(50))
.height(Length::Fixed(50.0))
.padding(8)
.spacing(8)
.apply(widget::container)
.style(crate::theme::Container::HeaderBar)
.center_y()
.apply(widget::mouse_listener);
.apply(widget::mouse_area);
if let Some(message) = self.on_drag.clone() {
widget = widget.on_press(message);

View file

@ -71,7 +71,7 @@ impl<'a> IconSource<'a> {
let handle = if let Some(path) = icon {
svg::Handle::from_path(path)
} else {
eprintln!("svg icon '{:?}' size {} not found", self, size);
eprintln!("svg icon '{self:?}' size {size} not found");
svg::Handle::from_memory(Vec::new())
};
@ -79,7 +79,7 @@ impl<'a> IconSource<'a> {
} else if let Some(icon) = icon {
Handle::Image(icon.into())
} else {
eprintln!("icon '{:?}' size {} not found", self, size);
eprintln!("icon '{self:?}' size {size} not found");
Handle::Image(image::Handle::from_memory(Vec::new()))
}
}
@ -90,7 +90,13 @@ impl<'a> IconSource<'a> {
}
/// Get a handle to a raster image from memory.
pub fn raster_from_memory(bytes: impl Into<Cow<'static, [u8]>>) -> Self {
pub fn raster_from_memory(
bytes: impl Into<Cow<'static, [u8]>>
+ std::convert::AsRef<[u8]>
+ std::marker::Send
+ std::marker::Sync
+ 'static,
) -> Self {
IconSource::Handle(Handle::Image(image::Handle::from_memory(bytes)))
}
@ -98,7 +104,11 @@ impl<'a> IconSource<'a> {
pub fn raster_from_pixels(
width: u32,
height: u32,
pixels: impl Into<Cow<'static, [u8]>>,
pixels: impl Into<Cow<'static, [u8]>>
+ std::convert::AsRef<[u8]>
+ std::marker::Send
+ std::marker::Sync
+ 'static,
) -> Self {
IconSource::Handle(Handle::Image(image::Handle::from_pixels(
width, height, pixels,
@ -165,7 +175,7 @@ impl From<svg::Handle> for IconSource<'static> {
}
/// A lazily-generated icon.
#[derive(Hash, Setters)]
#[derive(Setters)]
pub struct Icon<'a> {
#[setters(skip)]
source: IconSource<'a>,
@ -181,6 +191,33 @@ pub struct Icon<'a> {
force_svg: bool,
}
// XXX Hopefully this will be enough precision
impl Hash for Icon<'_> {
#[allow(clippy::cast_possible_truncation)]
fn hash<H: Hasher>(&self, state: &mut H) {
self.source.hash(state);
self.theme.hash(state);
self.style.hash(state);
self.size.hash(state);
self.content_fit.hash(state);
self.force_svg.hash(state);
match self.width {
Some(Length::Fill) => 0.hash(state),
Some(Length::Shrink) => 1.hash(state),
Some(Length::Fixed(v)) => ((v * 1000.0) as i32).hash(state),
Some(Length::FillPortion(p)) => p.hash(state),
None => 2.hash(state),
}
match self.height {
Some(Length::Fill) => 0.hash(state),
Some(Length::Shrink) => 1.hash(state),
Some(Length::Fixed(v)) => ((v * 1000.0) as i32).hash(state),
Some(Length::FillPortion(p)) => p.hash(state),
None => 2.hash(state),
}
}
}
/// A lazily-generated icon.
#[must_use]
pub fn icon<'a>(source: impl Into<IconSource<'a>>, size: u16) -> Icon<'a> {
@ -199,8 +236,8 @@ pub fn icon<'a>(source: impl Into<IconSource<'a>>, size: u16) -> Icon<'a> {
impl<'a> Icon<'a> {
fn raster_element<Message: 'static>(&self, handle: image::Handle) -> Element<'static, Message> {
Image::new(handle)
.width(self.width.unwrap_or(Length::Units(self.size)))
.height(self.height.unwrap_or(Length::Units(self.size)))
.width(self.width.unwrap_or(Length::Fixed(f32::from(self.size))))
.height(self.height.unwrap_or(Length::Fixed(f32::from(self.size))))
.content_fit(self.content_fit)
.into()
}
@ -208,8 +245,8 @@ impl<'a> Icon<'a> {
fn svg_element<Message: 'static>(&self, handle: svg::Handle) -> Element<'static, Message> {
svg::Svg::<Renderer>::new(handle)
.style(self.style.clone())
.width(self.width.unwrap_or(Length::Units(self.size)))
.height(self.height.unwrap_or(Length::Units(self.size)))
.width(self.width.unwrap_or(Length::Fixed(f32::from(self.size))))
.height(self.height.unwrap_or(Length::Fixed(f32::from(self.size))))
.content_fit(self.content_fit)
.into()
}
@ -228,7 +265,7 @@ impl<'a> Icon<'a> {
let mut source = IconSource::Name(Cow::Borrowed(""));
std::mem::swap(&mut source, &mut self.source);
iced_lazy::lazy(hash, move || -> Element<Message> {
iced::widget::lazy(hash, move |_| -> Element<Message> {
match source.load(self.size, self.theme.as_deref(), self.force_svg) {
Handle::Svg(handle) => self.svg_element(handle),
Handle::Image(handle) => self.raster_element(handle),

View file

@ -63,7 +63,7 @@ pub fn style(theme: &crate::Theme) -> iced::widget::container::Appearance {
iced::widget::container::Appearance {
text_color: Some(container.on.into()),
background: Some(Background::Color(container.base.into())),
border_radius: 8.0,
border_radius: 8.0.into(),
border_width: 0.0,
border_color: Color::TRANSPARENT,
}

View file

@ -45,7 +45,7 @@ pub fn nav_bar_style(theme: &Theme) -> iced_style::container::Appearance {
iced_style::container::Appearance {
text_color: Some(cosmic.on_bg_color().into()),
background: Some(Background::Color(cosmic.primary.base.into())),
border_radius: 8.0,
border_radius: 8.0.into(),
border_width: 0.0,
border_color: Color::TRANSPARENT,
}

View file

@ -3,13 +3,13 @@
//! A widget showing a popup in an overlay positioned relative to another widget.
use iced_native::event::{self, Event};
use iced_native::layout;
use iced_native::mouse;
use iced_native::overlay;
use iced_native::renderer;
use iced_native::widget::{Operation, Tree};
use iced_native::{Clipboard, Element, Layout, Length, Point, Rectangle, Shell, Size, Widget};
use iced_core::event::{self, Event};
use iced_core::layout;
use iced_core::mouse;
use iced_core::overlay;
use iced_core::renderer;
use iced_core::widget::{Operation, OperationOutputWrapper, Tree};
use iced_core::{Clipboard, Element, Layout, Length, Point, Rectangle, Shell, Size, Widget};
use std::cell::RefCell;
pub use iced_style::container::{Appearance, StyleSheet};
@ -43,15 +43,15 @@ impl<'a, Message, Renderer> Popover<'a, Message, Renderer> {
impl<'a, Message, Renderer> Widget<Message, Renderer> for Popover<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet,
{
fn children(&self) -> Vec<Tree> {
vec![Tree::new(&self.content), Tree::new(&*self.popup.borrow())]
}
fn diff(&self, tree: &mut Tree) {
tree.diff_children(&[&self.content, &self.popup.borrow()])
fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(&mut [&mut self.content, &mut self.popup.borrow_mut()]);
}
fn width(&self) -> Length {
@ -66,10 +66,16 @@ where
self.content.as_widget().layout(renderer, limits)
}
fn operate(&self, tree: &mut Tree, layout: Layout<'_>, operation: &mut dyn Operation<Message>) {
fn operate(
&self,
tree: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn Operation<OperationOutputWrapper<Message>>,
) {
self.content
.as_widget()
.operate(&mut tree.children[0], layout, operation)
.operate(&mut tree.children[0], layout, renderer, operation);
}
fn on_event(
@ -128,11 +134,11 @@ where
layout,
cursor_position,
viewport,
)
);
}
fn overlay<'b>(
&'b self,
&'b mut self,
tree: &'b mut Tree,
layout: Layout<'_>,
_renderer: &Renderer,
@ -155,7 +161,7 @@ where
impl<'a, Message, Renderer> From<Popover<'a, Message, Renderer>> for Element<'a, Message, Renderer>
where
Message: 'static,
Renderer: iced_native::Renderer + 'static,
Renderer: iced_core::Renderer + 'static,
Renderer::Theme: StyleSheet,
{
fn from(popover: Popover<'a, Message, Renderer>) -> Self {
@ -171,7 +177,7 @@ struct Overlay<'a, 'b, Message, Renderer> {
impl<'a, 'b, Message, Renderer> overlay::Overlay<Message, Renderer>
for Overlay<'a, 'b, Message, Renderer>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
{
fn layout(&self, renderer: &Renderer, bounds: Size, mut position: Point) -> layout::Node {
// Position is set to the center bottom of the lower widget
@ -186,11 +192,16 @@ where
node
}
fn operate(&mut self, layout: Layout<'_>, operation: &mut dyn Operation<Message>) {
fn operate(
&mut self,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn Operation<OperationOutputWrapper<Message>>,
) {
self.content
.borrow()
.as_widget()
.operate(self.tree, layout, operation)
.operate(self.tree, layout, renderer, operation);
}
fn on_event(
@ -246,6 +257,6 @@ where
layout,
cursor_position,
&bounds,
)
);
}
}

View file

@ -4,14 +4,14 @@ use iced::futures::channel::mpsc::UnboundedSender;
use iced::widget::Container;
pub use subscription::*;
use iced_native::alignment;
use iced_native::event::{self, Event};
use iced_native::layout;
use iced_native::mouse;
use iced_native::overlay;
use iced_native::renderer;
use iced_native::widget::{Operation, Tree};
use iced_native::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
use iced_core::alignment;
use iced_core::event::{self, Event};
use iced_core::layout;
use iced_core::mouse;
use iced_core::overlay;
use iced_core::renderer;
use iced_core::widget::Tree;
use iced_core::{Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Widget};
use std::{fmt::Debug, hash::Hash};
pub use iced_style::container::{Appearance, StyleSheet};
@ -44,7 +44,7 @@ where
#[allow(missing_debug_implementations)]
pub struct RectangleTrackingContainer<'a, Message, Renderer, I>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet,
{
tx: UnboundedSender<(I, Rectangle)>,
@ -54,7 +54,7 @@ where
impl<'a, Message, Renderer, I> RectangleTrackingContainer<'a, Message, Renderer, I>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet,
I: 'a + Hash + Copy + Send + Sync + Debug,
{
@ -93,14 +93,14 @@ where
/// Sets the maximum width of the [`Container`].
#[must_use]
pub fn max_width(mut self, max_width: u32) -> Self {
pub fn max_width(mut self, max_width: f32) -> Self {
self.container = self.container.max_width(max_width);
self
}
/// Sets the maximum height of the [`Container`] in pixels.
#[must_use]
pub fn max_height(mut self, max_height: u32) -> Self {
pub fn max_height(mut self, max_height: f32) -> Self {
self.container = self.container.max_height(max_height);
self
}
@ -144,7 +144,7 @@ where
impl<'a, Message, Renderer, I> Widget<Message, Renderer>
for RectangleTrackingContainer<'a, Message, Renderer, I>
where
Renderer: iced_native::Renderer,
Renderer: iced_core::Renderer,
Renderer::Theme: StyleSheet,
I: 'a + Hash + Copy + Send + Sync + Debug,
{
@ -152,7 +152,7 @@ where
self.container.children()
}
fn diff(&self, tree: &mut Tree) {
fn diff(&mut self, tree: &mut Tree) {
self.container.diff(tree);
}
@ -168,8 +168,16 @@ where
self.container.layout(renderer, limits)
}
fn operate(&self, tree: &mut Tree, layout: Layout<'_>, operation: &mut dyn Operation<Message>) {
self.container.operate(tree, layout, operation);
fn operate(
&self,
tree: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn iced_core::widget::Operation<
iced_core::widget::OperationOutputWrapper<Message>,
>,
) {
self.container.operate(tree, layout, renderer, operation);
}
fn on_event(
@ -229,7 +237,7 @@ where
}
fn overlay<'b>(
&'b self,
&'b mut self,
tree: &'b mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
@ -242,7 +250,7 @@ impl<'a, Message, Renderer, I> From<RectangleTrackingContainer<'a, Message, Rend
for Element<'a, Message, Renderer>
where
Message: 'a,
Renderer: 'a + iced_native::Renderer,
Renderer: 'a + iced_core::Renderer,
Renderer::Theme: StyleSheet,
I: 'a + Hash + Copy + Send + Sync + Debug,
{

View file

@ -26,44 +26,51 @@ pub enum State<I> {
async fn start_listening<I: Copy, R: 'static + Hash + Copy + Send + Sync + Debug + Eq>(
id: I,
state: State<R>,
) -> (Option<(I, RectangleUpdate<R>)>, State<R>) {
match state {
State::Ready => {
let (tx, rx) = unbounded();
mut state: State<R>,
) -> ((I, RectangleUpdate<R>), State<R>) {
loop {
let (update, new_state) = match state {
State::Ready => {
let (tx, rx) = unbounded();
(
Some((id, RectangleUpdate::Init(RectangleTracker { tx }))),
State::Waiting(rx, HashMap::new()),
)
}
State::Waiting(mut rx, mut map) => match rx.next().await {
Some(u) => {
if let Some(prev) = map.get(&u.0) {
let new = u.1;
if prev.width != new.width
|| prev.height != new.height
|| prev.x != new.x
|| prev.y != new.y
{
map.insert(u.0, new);
return (
(
Some((id, RectangleUpdate::Init(RectangleTracker { tx }))),
State::Waiting(rx, HashMap::new()),
)
}
State::Waiting(mut rx, mut map) => match rx.next().await {
Some(u) => {
if let Some(prev) = map.get(&u.0) {
let new = u.1;
if (prev.width - new.width).abs() > 0.1
|| (prev.height - new.height).abs() > 0.1
|| (prev.x - new.x).abs() > 0.1
|| (prev.y - new.y).abs() > 0.1
{
map.insert(u.0, new);
(
Some((id, RectangleUpdate::Rectangle(u))),
State::Waiting(rx, map),
)
} else {
(None, State::Waiting(rx, map))
}
} else {
map.insert(u.0, u.1);
(
Some((id, RectangleUpdate::Rectangle(u))),
State::Waiting(rx, map),
);
)
}
} else {
map.insert(u.0, u.1);
return (
Some((id, RectangleUpdate::Rectangle(u))),
State::Waiting(rx, map),
);
}
(None, State::Waiting(rx, map))
}
None => (None, State::Finished),
},
State::Finished => iced::futures::future::pending().await,
None => (None, State::Finished),
},
State::Finished => iced::futures::future::pending().await,
};
state = new_state;
if let Some(u) = update {
return (u, state);
}
}
}

View file

@ -8,6 +8,6 @@ pub fn scrollable<'a, Message>(
element: impl Into<Element<'a, Message>>,
) -> widget::Scrollable<'a, Message, Renderer> {
widget::scrollable(element)
.scrollbar_width(8)
.scroller_width(8)
// .scrollbar_width(8) TODO add these back
// .scroller_width(8)
}

View file

@ -11,7 +11,7 @@ use apply::Apply;
/// A search field for COSMIC applications.
pub fn field<Message: 'static + Clone>(
id: iced::widget::text_input::Id,
id: iced_core::id::Id,
phrase: &str,
on_change: fn(String) -> Message,
on_clear: Message,
@ -29,7 +29,7 @@ pub fn field<Message: 'static + Clone>(
/// A search field for COSMIC applications.
#[must_use]
pub struct Field<'a, Message: 'static + Clone> {
id: iced::widget::text_input::Id,
id: iced_core::id::Id,
phrase: &'a str,
on_change: fn(String) -> Message,
on_clear: Message,
@ -38,7 +38,8 @@ pub struct Field<'a, Message: 'static + Clone> {
impl<'a, Message: 'static + Clone> Field<'a, Message> {
pub fn into_element(mut self) -> crate::Element<'a, Message> {
let mut input = iced::widget::text_input("", self.phrase, self.on_change)
let mut input = iced::widget::text_input("", self.phrase)
.on_input(self.on_change)
.style(crate::theme::TextInput::Search)
.width(Length::Fill)
.id(self.id);
@ -52,8 +53,8 @@ impl<'a, Message: 'static + Clone> Field<'a, Message> {
input,
clear_button().on_press(self.on_clear)
)
.width(Length::Units(300))
.height(Length::Units(38))
.width(Length::Fixed(300.0))
.height(Length::Fixed(38.0))
.padding([0, 16])
.spacing(8)
.align_items(iced::Alignment::Center)
@ -84,7 +85,7 @@ fn active_style(theme: &crate::Theme) -> container::Appearance {
iced::widget::container::Appearance {
text_color: Some(cosmic.palette.neutral_9.into()),
background: Some(Background::Color(neutral_7.into())),
border_radius: 24.0,
border_radius: 24.0.into(),
border_width: 2.0,
border_color: cosmic.accent.focus.into(),
}

View file

@ -6,14 +6,13 @@ use crate::iced;
/// A model for managing the state of a search widget.
pub struct Model {
pub input_id: iced::widget::text_input::Id,
pub input_id: iced_core::id::Id,
pub phrase: String,
pub state: State,
}
impl Model {
/// Focuses the search field.
#[must_use]
pub fn focus<Message: 'static>(&mut self) -> crate::iced::Command<Message> {
self.state = State::Active;
iced::widget::text_input::focus(self.input_id.clone())
@ -29,7 +28,7 @@ impl Model {
impl Default for Model {
fn default() -> Self {
Self {
input_id: iced::widget::text_input::Id::unique(),
input_id: iced_core::id::Id::unique(),
phrase: String::with_capacity(32),
state: State::Inactive,
}

View file

@ -8,7 +8,7 @@ use super::style::StyleSheet;
use super::widget::{SegmentedButton, SegmentedVariant};
use iced::{Length, Rectangle, Size};
use iced_native::layout;
use iced_core::layout;
/// Horizontal [`SegmentedButton`].
pub type HorizontalSegmentedButton<'a, SelectionMode, Message, Renderer> =
@ -25,10 +25,10 @@ pub fn horizontal<SelectionMode: Default, Message, Renderer>(
model: &Model<SelectionMode>,
) -> SegmentedButton<Horizontal, SelectionMode, Message, Renderer>
where
Renderer: iced_native::Renderer
+ iced_native::text::Renderer
+ iced_native::image::Renderer
+ iced_native::svg::Renderer,
Renderer: iced_core::Renderer
+ iced_core::text::Renderer
+ iced_core::image::Renderer
+ iced_core::svg::Renderer,
Renderer::Theme: StyleSheet,
Model<SelectionMode>: Selectable,
{
@ -38,10 +38,10 @@ where
impl<'a, SelectionMode, Message, Renderer> SegmentedVariant
for SegmentedButton<'a, Horizontal, SelectionMode, Message, Renderer>
where
Renderer: iced_native::Renderer
+ iced_native::text::Renderer
+ iced_native::image::Renderer
+ iced_native::svg::Renderer,
Renderer: iced_core::Renderer
+ iced_core::text::Renderer
+ iced_core::image::Renderer
+ iced_core::svg::Renderer,
Renderer::Theme: StyleSheet,
Model<SelectionMode>: Selectable,
SelectionMode: Default,
@ -49,8 +49,8 @@ where
type Renderer = Renderer;
fn variant_appearance(
theme: &<Self::Renderer as iced_native::Renderer>::Theme,
style: &<<Self::Renderer as iced_native::Renderer>::Theme as StyleSheet>::Style,
theme: &<Self::Renderer as iced_core::Renderer>::Theme,
style: &<<Self::Renderer as iced_core::Renderer>::Theme as StyleSheet>::Style,
) -> super::Appearance {
theme.horizontal(style)
}
@ -85,7 +85,7 @@ where
}
let size = limits
.height(Length::Units(height as u16))
.height(Length::Fixed(height))
.resolve(Size::new(width, height));
layout::Node::new(size)

View file

@ -1,7 +1,7 @@
// Copyright 2022 System76 <info@system76.com>
// SPDX-License-Identifier: MPL-2.0
use iced_core::{Background, BorderRadius, Color};
use iced_core::{renderer::BorderRadius, Background, Color};
/// Appearance of the segmented button.
#[derive(Default, Clone, Copy)]

View file

@ -8,7 +8,7 @@ use super::style::StyleSheet;
use super::widget::{SegmentedButton, SegmentedVariant};
use iced::{Length, Rectangle, Size};
use iced_native::layout;
use iced_core::layout;
/// A type marker defining the vertical variant of a [`SegmentedButton`].
pub struct Vertical;
@ -25,10 +25,10 @@ pub fn vertical<SelectionMode, Message, Renderer>(
model: &Model<SelectionMode>,
) -> SegmentedButton<Vertical, SelectionMode, Message, Renderer>
where
Renderer: iced_native::Renderer
+ iced_native::text::Renderer
+ iced_native::image::Renderer
+ iced_native::svg::Renderer,
Renderer: iced_core::Renderer
+ iced_core::text::Renderer
+ iced_core::image::Renderer
+ iced_core::svg::Renderer,
Renderer::Theme: StyleSheet,
Model<SelectionMode>: Selectable,
SelectionMode: Default,
@ -39,10 +39,10 @@ where
impl<'a, SelectionMode, Message, Renderer> SegmentedVariant
for SegmentedButton<'a, Vertical, SelectionMode, Message, Renderer>
where
Renderer: iced_native::Renderer
+ iced_native::text::Renderer
+ iced_native::image::Renderer
+ iced_native::svg::Renderer,
Renderer: iced_core::Renderer
+ iced_core::text::Renderer
+ iced_core::image::Renderer
+ iced_core::svg::Renderer,
Renderer::Theme: StyleSheet,
Model<SelectionMode>: Selectable,
SelectionMode: Default,
@ -50,8 +50,8 @@ where
type Renderer = Renderer;
fn variant_appearance(
theme: &<Self::Renderer as iced_native::Renderer>::Theme,
style: &<<Self::Renderer as iced_native::Renderer>::Theme as StyleSheet>::Style,
theme: &<Self::Renderer as iced_core::Renderer>::Theme,
style: &<<Self::Renderer as iced_core::Renderer>::Theme as StyleSheet>::Style,
) -> super::Appearance {
theme.vertical(style)
}
@ -86,7 +86,7 @@ where
}
let size = limits
.height(Length::Units(height as u16))
.height(Length::Fixed(height))
.resolve(Size::new(width, height));
layout::Node::new(size)

View file

@ -10,9 +10,10 @@ use iced::{
alignment, event, keyboard, mouse, touch, Background, Color, Command, Element, Event, Length,
Point, Rectangle, Size,
};
use iced_core::BorderRadius;
use iced_native::widget::{self, operation, tree, Operation};
use iced_native::{layout, renderer, widget::Tree, Clipboard, Layout, Shell, Widget};
use iced_core::renderer::BorderRadius;
use iced_core::text::{LineHeight, Shaping};
use iced_core::widget::{self, operation, tree};
use iced_core::{layout, renderer, widget::Tree, Clipboard, Layout, Shell, Widget};
use std::marker::PhantomData;
/// State that is maintained by each individual widget.
@ -46,15 +47,15 @@ impl operation::Focusable for LocalState {
/// Isolates variant-specific behaviors from [`SegmentedButton`].
pub trait SegmentedVariant {
type Renderer: iced_native::Renderer;
type Renderer: iced_core::Renderer;
/// Get the appearance for this variant of the widget.
fn variant_appearance(
theme: &<Self::Renderer as iced_native::Renderer>::Theme,
style: &<<Self::Renderer as iced_native::Renderer>::Theme as StyleSheet>::Style,
theme: &<Self::Renderer as iced_core::Renderer>::Theme,
style: &<<Self::Renderer as iced_core::Renderer>::Theme as StyleSheet>::Style,
) -> super::Appearance
where
<Self::Renderer as iced_native::Renderer>::Theme: StyleSheet;
<Self::Renderer as iced_core::Renderer>::Theme: StyleSheet;
/// Calculates the bounds for the given button by its position.
fn variant_button_bounds(&self, bounds: Rectangle, position: usize) -> Rectangle;
@ -67,10 +68,10 @@ pub trait SegmentedVariant {
#[derive(Setters)]
pub struct SegmentedButton<'a, Variant, SelectionMode, Message, Renderer>
where
Renderer: iced_native::Renderer
+ iced_native::text::Renderer
+ iced_native::image::Renderer
+ iced_native::svg::Renderer,
Renderer: iced_core::Renderer
+ iced_core::text::Renderer
+ iced_core::image::Renderer
+ iced_core::svg::Renderer,
Renderer::Theme: StyleSheet,
Model<SelectionMode>: Selectable,
SelectionMode: Default,
@ -91,13 +92,13 @@ where
/// Spacing between icon and text in button.
pub(super) button_spacing: u16,
/// Desired font for active tabs.
pub(super) font_active: Renderer::Font,
pub(super) font_active: Option<Renderer::Font>,
/// Desired font for hovered tabs.
pub(super) font_hovered: Renderer::Font,
pub(super) font_hovered: Option<Renderer::Font>,
/// Desired font for inactive tabs.
pub(super) font_inactive: Renderer::Font,
pub(super) font_inactive: Option<Renderer::Font>,
/// Size of the font.
pub(super) font_size: u16,
pub(super) font_size: f32,
/// Size of icon
pub(super) icon_size: u16,
/// Desired width of the widget.
@ -106,6 +107,8 @@ where
pub(super) height: Length,
/// Desired spacing between items.
pub(super) spacing: u16,
/// LineHeight of the font.
pub(super) line_height: LineHeight,
/// Style to draw the widget in.
#[setters(into)]
pub(super) style: <Renderer::Theme as StyleSheet>::Style,
@ -122,10 +125,10 @@ where
impl<'a, Variant, SelectionMode, Message, Renderer>
SegmentedButton<'a, Variant, SelectionMode, Message, Renderer>
where
Renderer: iced_native::Renderer
+ iced_native::text::Renderer
+ iced_native::image::Renderer
+ iced_native::svg::Renderer,
Renderer: iced_core::Renderer
+ iced_core::text::Renderer
+ iced_core::image::Renderer
+ iced_core::svg::Renderer,
Renderer::Theme: StyleSheet,
Self: SegmentedVariant<Renderer = Renderer>,
Model<SelectionMode>: Selectable,
@ -141,14 +144,15 @@ where
button_padding: [4, 4, 4, 4],
button_height: 32,
button_spacing: 4,
font_active: Renderer::Font::default(),
font_hovered: Renderer::Font::default(),
font_inactive: Renderer::Font::default(),
font_size: 17,
font_active: None,
font_hovered: None,
font_inactive: None,
font_size: 17.0,
icon_size: 16,
height: Length::Shrink,
width: Length::Fill,
spacing: 0,
line_height: LineHeight::default(),
style: <Renderer::Theme as StyleSheet>::Style::default(),
on_activate: None,
on_close: None,
@ -212,6 +216,7 @@ where
pub(super) fn max_button_dimensions(&self, renderer: &Renderer, bounds: Size) -> (f32, f32) {
let mut width = 0.0f32;
let mut height = 0.0f32;
let font = renderer.default_font();
for key in self.model.order.iter().copied() {
let mut button_width = 0.0f32;
@ -219,7 +224,14 @@ where
// Add text to measurement if text was given.
if let Some(text) = self.model.text(key) {
let (w, h) = renderer.measure(text, self.font_size, Default::default(), bounds);
let (w, h) = renderer.measure(
text,
self.font_size,
self.line_height,
font,
bounds,
Shaping::Advanced,
);
button_width = w;
button_height = h;
@ -253,10 +265,10 @@ where
impl<'a, Variant, SelectionMode, Message, Renderer> Widget<Message, Renderer>
for SegmentedButton<'a, Variant, SelectionMode, Message, Renderer>
where
Renderer: iced_native::Renderer
+ iced_native::text::Renderer
+ iced_native::image::Renderer
+ iced_native::svg::Renderer,
Renderer: iced_core::Renderer
+ iced_core::text::Renderer
+ iced_core::image::Renderer
+ iced_core::svg::Renderer,
Renderer::Theme: StyleSheet,
Self: SegmentedVariant<Renderer = Renderer>,
Model<SelectionMode>: Selectable,
@ -379,7 +391,10 @@ where
&self,
tree: &mut Tree,
_layout: Layout<'_>,
operation: &mut dyn Operation<Message>,
_renderer: &Renderer,
operation: &mut dyn iced_core::widget::Operation<
iced_core::widget::OperationOutputWrapper<Message>,
>,
) {
let state = tree.state.downcast_mut::<LocalState>();
operation.focusable(state, self.id.as_ref().map(|id| &id.0));
@ -392,7 +407,7 @@ where
cursor_position: iced::Point,
_viewport: &iced::Rectangle,
_renderer: &Renderer,
) -> iced_native::mouse::Interaction {
) -> iced_core::mouse::Interaction {
let bounds = layout.bounds();
if bounds.contains(cursor_position) {
@ -402,15 +417,15 @@ where
.contains(cursor_position)
{
return if self.model.items[key].enabled {
iced_native::mouse::Interaction::Pointer
iced_core::mouse::Interaction::Pointer
} else {
iced_native::mouse::Interaction::Idle
iced_core::mouse::Interaction::Idle
};
}
}
}
iced_native::mouse::Interaction::Idle
iced_core::mouse::Interaction::Idle
}
#[allow(clippy::too_many_lines)]
@ -418,7 +433,7 @@ where
&self,
tree: &Tree,
renderer: &mut Renderer,
theme: &<Renderer as iced_native::Renderer>::Theme,
theme: &<Renderer as iced_core::Renderer>::Theme,
_style: &renderer::Style,
layout: Layout<'_>,
_cursor_position: iced::Point,
@ -458,6 +473,7 @@ where
} else {
(appearance.inactive, &self.font_inactive)
};
let font = font.unwrap_or_else(|| renderer.default_font());
let button_appearance = if nth == 0 {
status_appearance.first
@ -536,7 +552,7 @@ where
unimplemented!()
}
icon::Handle::Svg(handle) => {
iced_native::svg::Renderer::draw(renderer, handle, icon_color, icon_bounds);
iced_core::svg::Renderer::draw(renderer, handle, icon_color, icon_bounds);
}
}
@ -550,14 +566,16 @@ where
bounds.y = y;
// Draw the text in this button.
renderer.fill_text(iced_native::text::Text {
renderer.fill_text(iced_core::text::Text {
content: text,
size: f32::from(self.font_size),
size: self.font_size,
bounds,
color: status_appearance.text_color,
font: font.clone(),
font,
horizontal_alignment,
vertical_alignment: alignment::Vertical::Center,
shaping: Shaping::Advanced,
line_height: self.line_height,
});
}
@ -575,7 +593,7 @@ where
unimplemented!()
}
icon::Handle::Svg(handle) => {
iced_native::svg::Renderer::draw(
iced_core::svg::Renderer::draw(
renderer,
handle,
Some(status_appearance.text_color),
@ -588,11 +606,11 @@ where
}
fn overlay<'b>(
&'b self,
&'b mut self,
_tree: &'b mut Tree,
_layout: iced_native::Layout<'_>,
_layout: iced_core::Layout<'_>,
_renderer: &Renderer,
) -> Option<iced_native::overlay::Element<'b, Message, Renderer>> {
) -> Option<iced_core::overlay::Element<'b, Message, Renderer>> {
None
}
}
@ -601,10 +619,10 @@ impl<'a, Variant, SelectionMode, Message, Renderer>
From<SegmentedButton<'a, Variant, SelectionMode, Message, Renderer>>
for Element<'a, Message, Renderer>
where
Renderer: iced_native::Renderer
+ iced_native::text::Renderer
+ iced_native::image::Renderer
+ iced_native::svg::Renderer
Renderer: iced_core::Renderer
+ iced_core::text::Renderer
+ iced_core::image::Renderer
+ iced_core::svg::Renderer
+ 'a,
Renderer::Theme: StyleSheet,
SegmentedButton<'a, Variant, SelectionMode, Message, Renderer>:
@ -624,7 +642,6 @@ where
}
/// A command that focuses a segmented item stored in a widget.
#[must_use]
pub fn focus<Message: 'static>(id: Id) -> Command<Message> {
Command::widget(operation::focusable::focus(id.0))
}

View file

@ -25,7 +25,7 @@ where
.button_padding([16, 0, 16, 0])
.button_height(32)
.style(crate::theme::SegmentedButton::Selection)
.font_active(crate::font::FONT_SEMIBOLD)
.font_active(Some(crate::font::FONT_SEMIBOLD))
}
/// A selection of multiple choices appearing as a conjoined button.
@ -45,5 +45,5 @@ where
.button_padding([16, 0, 16, 0])
.button_height(32)
.style(crate::theme::SegmentedButton::Selection)
.font_active(crate::font::FONT_SEMIBOLD)
.font_active(Some(crate::font::FONT_SEMIBOLD))
}

View file

@ -46,43 +46,41 @@ impl<'a, Message: 'static> SpinButton<'a, Message> {
icon("list-remove-symbolic", 24)
.style(theme::Svg::Symbolic)
.apply(container)
.width(Length::Fill)
.height(Length::Fill)
.width(Length::Fixed(32.0))
.height(Length::Fixed(32.0))
.align_x(Horizontal::Center)
.align_y(Vertical::Center)
.apply(button)
.width(Length::Fill)
.height(Length::Fill)
.width(Length::Fixed(32.0))
.height(Length::Fixed(32.0))
.style(theme::Button::Text)
.on_press(model::Message::Decrement),
text(label)
.vertical_alignment(Vertical::Center)
.apply(container)
.width(Length::Fill)
.height(Length::Fill)
.align_x(Horizontal::Center)
.align_y(Vertical::Center),
icon("list-add-symbolic", 24)
.style(theme::Svg::Symbolic)
.apply(container)
.width(Length::Fill)
.height(Length::Fill)
.width(Length::Fixed(32.0))
.height(Length::Fixed(32.0))
.align_x(Horizontal::Center)
.align_y(Vertical::Center)
.apply(button)
.width(Length::Fill)
.height(Length::Fill)
.width(Length::Fixed(32.0))
.height(Length::Fixed(32.0))
.style(theme::Button::Text)
.on_press(model::Message::Increment),
]
.width(Length::Fill)
.height(Length::Units(32))
.width(Length::Shrink)
.height(Length::Fixed(32.0))
.spacing(4.0)
.align_items(Alignment::Center),
)
.padding([4, 4])
.align_y(Vertical::Center)
.width(Length::Units(95))
.height(Length::Units(32))
.width(Length::Shrink)
.height(Length::Fixed(32.0))
.style(theme::Container::custom(container_style))
.apply(Element::from)
.map(on_change)
@ -104,7 +102,7 @@ fn container_style(theme: &crate::Theme) -> iced_style::container::Appearance {
iced_style::container::Appearance {
text_color: Some(basic.palette.neutral_10.into()),
background: Some(Background::Color(neutral_10.into())),
border_radius: 24.0,
border_radius: 24.0.into(),
border_width: 0.0,
border_color: accent.base.into(),
}

View file

@ -7,7 +7,7 @@ pub use iced::widget::Text;
/// [`Text`]: widget::Text
pub fn text<'a, Renderer>(text: impl Into<Cow<'a, str>>) -> Text<'a, Renderer>
where
Renderer: iced_native::text::Renderer,
Renderer: iced_core::text::Renderer,
Renderer::Theme: iced::widget::text::StyleSheet,
{
Text::new(text)

View file

@ -9,7 +9,7 @@ pub fn toggler<'a, Message>(
is_checked: bool,
f: impl Fn(bool) -> Message + 'a,
) -> widget::Toggler<'a, Message, Renderer> {
widget::Toggler::new(is_checked, label, f)
widget::Toggler::new(label, is_checked, f)
.size(24)
.spacing(12)
.width(Length::Shrink)

View file

@ -25,7 +25,7 @@ where
.button_padding([16, 0, 16, 0])
.button_height(48)
.style(crate::theme::SegmentedButton::ViewSwitcher)
.font_active(crate::font::FONT_SEMIBOLD)
.font_active(Some(crate::font::FONT_SEMIBOLD))
}
/// A collection of tabs for developing a tabbed interface.
@ -45,5 +45,5 @@ where
.button_padding([16, 0, 16, 0])
.button_height(48)
.style(crate::theme::SegmentedButton::ViewSwitcher)
.font_active(crate::font::FONT_SEMIBOLD)
.font_active(Some(crate::font::FONT_SEMIBOLD))
}

View file

@ -64,11 +64,12 @@ impl<'a, Message: 'static + Clone> From<Warning<'a, Message>> for Element<'a, Me
}
}
#[must_use]
pub fn warning_container(theme: &Theme) -> widget::container::Appearance {
widget::container::Appearance {
text_color: Some(theme.cosmic().warning.on.into()),
background: Some(Background::Color(theme.cosmic().warning_color().into())),
border_radius: 0.0,
border_radius: 0.0.into(),
border_width: 0.0,
border_color: Color::TRANSPARENT,
}