Round corners on colour picker
Diff
shalom/src/widgets/colour_picker.rs | 60 +++++++++++++++++++++++++++++++++++++++++-------------------
shalom/src/widgets/forced_rounded.rs | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
shalom/src/widgets/image_card.rs | 30 +++++++++++++++++++++++-------
shalom/src/widgets/mod.rs | 1 +
4 files changed, 235 insertions(+), 35 deletions(-)
@@ -7,11 +7,13 @@
widget::{
canvas,
canvas::{Cache, Event, Frame, Geometry, Path, Stroke, Style},
component, Column, Component,
component, Component, Row,
},
Color, Point, Rectangle, Renderer, Size, Theme,
};
use crate::widgets::forced_rounded::forced_rounded;
pub struct ColourPicker<Event> {
hue: f32,
saturation: f32,
@@ -51,23 +53,29 @@
}
fn view(&self, _state: &Self::State) -> Element<'_, Self::Event, Renderer> {
let saturation_brightness_picker = canvas(SaturationBrightnessPicker::new(
self.hue,
self.saturation,
self.brightness,
Message::OnSaturationBrightnessChange,
))
.height(192)
.width(192);
let hue_slider = canvas(HueSlider::new(self.hue, Message::OnHueChanged))
.height(24)
.width(192);
Column::new()
let saturation_brightness_picker = forced_rounded(
canvas(SaturationBrightnessPicker::new(
self.hue,
self.saturation,
self.brightness,
Message::OnSaturationBrightnessChange,
))
.height(192)
.width(192)
.into(),
);
let hue_slider = forced_rounded(
canvas(HueSlider::new(self.hue, Message::OnHueChanged))
.height(192)
.width(32)
.into(),
);
Row::new()
.push(saturation_brightness_picker)
.push(hue_slider)
.spacing(4)
.spacing(0)
.into()
}
}
@@ -134,7 +142,7 @@
if let Some(position) = cursor.position_in(bounds) {
state.arrow_cache.clear();
let hue = (position.x / bounds.width) * 360.;
let hue = (position.y / bounds.height) * 360.;
(Status::Captured, Some((self.on_hue_change)(hue)))
} else {
(Status::Captured, None)
@@ -163,12 +171,12 @@
clippy::cast_sign_loss,
clippy::cast_precision_loss
)]
for x in 0..size.width as u32 {
let hue = (x as f32 / size.width) * 360.0;
for y in 0..size.height as u32 {
let hue = (y as f32 / size.height) * 360.0;
let color = colour_from_hsb(hue, 1.0, 1.0);
frame.fill_rectangle(
Point::new(x as f32, 0.0),
Size::new(1.0, size.height),
Point::new(0.0, y as f32),
Size::new(size.width, 1.0),
color,
);
}
@@ -182,15 +190,15 @@
let arrow_width = 10.0;
let arrow_height = 10.0;
let arrow_x = (self.hue / 360.0) * size.width - (arrow_width / 2.0);
let arrow_y = size.height - arrow_height;
let arrow_x = size.width;
let arrow_y = (self.hue / 360.0) * size.height - (arrow_height / 2.0);
let arrow = Path::new(|p| {
p.move_to(Point::new(arrow_x, arrow_y));
p.line_to(Point::new(arrow_x + arrow_width, arrow_y));
p.line_to(Point::new(arrow_x, arrow_y - arrow_width));
p.line_to(Point::new(
arrow_x + (arrow_width / 2.0),
arrow_y + arrow_height,
arrow_x - arrow_height,
arrow_y - (arrow_width / 2.0),
));
p.line_to(Point::new(arrow_x, arrow_y));
p.close();
@@ -1,0 +1,179 @@
use iced::{
advanced::{
layout::{Limits, Node},
overlay,
overlay::Element,
renderer::{Quad, Style},
widget::{
tree::{State, Tag},
Operation, Tree,
},
Clipboard, Layout, Renderer, Shell, Widget,
},
event::Status,
mouse::{Cursor, Interaction},
Background, Color, Event, Length, Point, Rectangle, Size,
};
pub fn forced_rounded<'a, M: 'a, R>(element: iced::Element<'a, M, R>) -> ForcedRounded<'a, M, R> {
ForcedRounded { element }
}
pub struct ForcedRounded<'a, M, R> {
element: iced::Element<'a, M, R>,
}
impl<'a, M, R: Renderer> Widget<M, R> for ForcedRounded<'a, M, R> {
fn width(&self) -> Length {
self.element.as_widget().width()
}
fn height(&self) -> Length {
self.element.as_widget().height()
}
fn layout(&self, renderer: &R, limits: &Limits) -> Node {
self.element.as_widget().layout(renderer, limits)
}
fn draw(
&self,
state: &Tree,
renderer: &mut R,
theme: &R::Theme,
style: &Style,
layout: Layout<'_>,
cursor: Cursor,
viewport: &Rectangle,
) {
self.element
.as_widget()
.draw(state, renderer, theme, style, layout, cursor, viewport);
}
fn tag(&self) -> Tag {
self.element.as_widget().tag()
}
fn children(&self) -> Vec<Tree> {
self.element.as_widget().children()
}
fn diff(&self, tree: &mut Tree) {
self.element.as_widget().diff(tree);
}
fn mouse_interaction(
&self,
state: &Tree,
layout: Layout<'_>,
cursor: Cursor,
viewport: &Rectangle,
renderer: &R,
) -> Interaction {
self.element
.as_widget()
.mouse_interaction(state, layout, cursor, viewport, renderer)
}
fn on_event(
&mut self,
state: &mut Tree,
event: Event,
layout: Layout<'_>,
cursor: Cursor,
renderer: &R,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, M>,
viewport: &Rectangle,
) -> Status {
self.element.as_widget_mut().on_event(
state, event, layout, cursor, renderer, clipboard, shell, viewport,
)
}
fn operate(
&self,
state: &mut Tree,
layout: Layout<'_>,
renderer: &R,
operation: &mut dyn Operation<M>,
) {
self.element
.as_widget()
.operate(state, layout, renderer, operation);
}
fn state(&self) -> State {
self.element.as_widget().state()
}
fn overlay<'b>(
&'b mut self,
_state: &'b mut Tree,
layout: Layout<'_>,
_renderer: &R,
) -> Option<Element<'b, M, R>> {
Some(overlay::Element::new(
layout.position(),
Box::new(Overlay {
size: layout.bounds().size(),
position: Some(layout.bounds().position()),
}),
))
}
}
impl<'a, M, R> From<ForcedRounded<'a, M, R>> for iced::Element<'a, M, R>
where
M: 'a + Clone,
R: 'a + Renderer,
{
fn from(e: ForcedRounded<'a, M, R>) -> Self {
iced::Element::new(e)
}
}
pub struct Overlay {
pub size: Size,
pub position: Option<Point>,
}
impl<M, R: Renderer> overlay::Overlay<M, R> for Overlay {
fn layout(&self, _renderer: &R, _bounds: Size, position: Point) -> Node {
let mut node = Node::new(self.size);
node.move_to(self.position.unwrap_or(position));
node
}
fn draw(
&self,
renderer: &mut R,
_theme: &R::Theme,
_style: &Style,
layout: Layout<'_>,
_cursor: Cursor,
) {
renderer.with_layer(layout.bounds(), |renderer| {
renderer.fill_quad(
Quad {
bounds: Rectangle {
height: self.size.height + 12.,
width: self.size.width + 12.,
x: layout.bounds().x - 6.,
y: layout.bounds().y - 6.,
},
border_radius: [20., 20., 20., 20.].into(),
border_width: 10.,
border_color: Color::WHITE,
},
Background::Color(Color::TRANSPARENT),
);
});
}
fn is_over(&self, _layout: Layout<'_>, _renderer: &R, _cursor_position: Point) -> bool {
false
}
}
@@ -122,15 +122,27 @@
layout: Layout<'_>,
_renderer: &Renderer,
) -> Option<iced::advanced::overlay::Element<'b, M, Renderer>> {
Some(overlay::Element::new(
layout.position(),
Box::new(Overlay {
text: &mut self.text,
tree: &mut state.children[0],
size: layout.bounds().size(),
on_press: self.on_press.as_ref(),
}),
))
Some(
overlay::Group::with_children(vec![
overlay::Element::new(
layout.position(),
Box::new(super::forced_rounded::Overlay {
size: layout.bounds().size(),
position: None,
}),
),
overlay::Element::new(
layout.position(),
Box::new(Overlay {
text: &mut self.text,
tree: &mut state.children[0],
size: layout.bounds().size(),
on_press: self.on_press.as_ref(),
}),
),
])
.overlay(),
)
}
}
@@ -1,6 +1,7 @@
pub mod cards;
pub mod colour_picker;
pub mod context_menu;
pub mod forced_rounded;
pub mod image_card;
pub mod media_player;
pub mod mouse_area;