Move gradient picking into the color picker (#1778)

* Gradient picker

* Fix up color picker layout CSS problems

* Begin hooking up SpectrumInput for gradient in the ColorPicker

* Working gradient picking on the frontend only

* Plumb FillColorChoice into the backend

* Hook everything else up, just with a weird bug remaining

* Fix some svelty reactivity issues

* Add and remove stops

* Cleanup

* Rename type

* Fill node document format upgrading

* Fix lint

* Polish the color picker UX and fix a bug

---------

Co-authored-by: 0hypercube <0hypercube@gmail.com>
This commit is contained in:
Keavon Chambers
2024-06-09 22:55:13 -07:00
committed by GitHub
co-authored by 0hypercube
parent 449729f1e1
commit a9a4b5cd19
48 changed files with 1380 additions and 664 deletions
@@ -4,6 +4,7 @@ use crate::messages::prelude::*;
use graphene_core::raster::color::Color;
use graphene_core::text::Font;
use graphene_std::vector::style::{FillChoice, GradientStops};
use serde_json::Value;
@@ -83,24 +84,63 @@ impl LayoutMessageHandler {
let callback_message = match action {
WidgetValueAction::Commit => (color_button.on_commit.callback)(&()),
WidgetValueAction::Update => {
let update_value = value.as_object().expect("ColorButton update was not of type: object");
let parsed_color = (|| {
let is_none = update_value.get("none")?.as_bool()?;
let decode_color = |color: &serde_json::map::Map<String, serde_json::value::Value>| -> Option<Color> {
let red = color.get("red").and_then(|x| x.as_f64()).map(|x| x as f32);
let green = color.get("green").and_then(|x| x.as_f64()).map(|x| x as f32);
let blue = color.get("blue").and_then(|x| x.as_f64()).map(|x| x as f32);
let alpha = color.get("alpha").and_then(|x| x.as_f64()).map(|x| x as f32);
if !is_none {
Some(Some(Color::from_rgbaf32(
update_value.get("red")?.as_f64()? as f32,
update_value.get("green")?.as_f64()? as f32,
update_value.get("blue")?.as_f64()? as f32,
update_value.get("alpha")?.as_f64()? as f32,
)?))
} else {
Some(None)
if let (Some(red), Some(green), Some(blue), Some(alpha)) = (red, green, blue, alpha) {
if let Some(color) = Color::from_rgbaf32(red, green, blue, alpha) {
return Some(color);
}
}
None
};
(|| {
let update_value = value.as_object().expect("ColorButton update was not of type: object");
// None
let is_none = update_value.get("none").and_then(|x| x.as_bool());
if is_none == Some(true) {
color_button.value = FillChoice::None;
return (color_button.on_update.callback)(color_button);
}
// Solid
if let Some(color) = decode_color(update_value) {
color_button.value = FillChoice::Solid(color);
return (color_button.on_update.callback)(color_button);
}
// Gradient
let gradient = update_value.get("stops").and_then(|x| x.as_array());
if let Some(stops) = gradient {
let gradient_stops = stops
.iter()
.filter_map(|stop| {
stop.as_object().and_then(|stop| {
let position = stop.get("position").and_then(|x| x.as_f64());
let color = stop.get("color").and_then(|x| x.as_object());
if let (Some(position), Some(color_object)) = (position, color) {
if let Some(color) = decode_color(color_object) {
return Some((position, color));
}
}
None
})
})
.collect::<Vec<_>>();
color_button.value = FillChoice::Gradient(GradientStops(gradient_stops));
return (color_button.on_update.callback)(color_button);
}
panic!("ColorButton update was not able to be parsed with color data: {color_button:?}");
})()
.unwrap_or_else(|| panic!("ColorButton update was not able to be parsed with color data: {color_button:?}"));
color_button.value = parsed_color;
(color_button.on_update.callback)(color_button)
}
};
@@ -2,7 +2,7 @@ use crate::messages::input_mapper::utility_types::misc::ActionKeys;
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::node_graph::utility_types::FrontendGraphDataType;
use graphene_core::raster::color::Color;
use graphene_std::vector::style::FillChoice;
use graphite_proc_macros::WidgetBuilder;
use derivative::*;
@@ -124,7 +124,7 @@ pub struct TextButton {
#[derivative(Debug, PartialEq, Default)]
pub struct ColorButton {
#[widget_builder(constructor)]
pub value: Option<Color>,
pub value: FillChoice,
pub disabled: bool,
@@ -137,7 +137,9 @@ pub struct ColorButton {
#[derivative(Default(value = "true"))]
pub allow_none: bool,
// TODO: Implement
// pub disabled: bool,
//
pub tooltip: String,
#[serde(skip)]