Add Polygon/Star toggle to Shape tool (#1215)
* #1212: added checkbox to toggle star for ngon shape * Switch from checkbox to radio input --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
92e10b6610
commit
84343f2abe
|
|
@ -2,7 +2,7 @@ use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
|
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
|
||||||
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, PropertyHolder, WidgetCallback, WidgetLayout};
|
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, PropertyHolder, WidgetCallback, WidgetLayout};
|
||||||
use crate::messages::layout::utility_types::misc::LayoutTarget;
|
use crate::messages::layout::utility_types::misc::LayoutTarget;
|
||||||
use crate::messages::layout::utility_types::widget_prelude::{ColorInput, NumberInput, WidgetHolder};
|
use crate::messages::layout::utility_types::widget_prelude::{ColorInput, NumberInput, RadioEntryData, RadioInput, WidgetHolder};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
|
|
@ -28,6 +28,7 @@ pub struct ShapeOptions {
|
||||||
fill: ToolColorOptions,
|
fill: ToolColorOptions,
|
||||||
stroke: ToolColorOptions,
|
stroke: ToolColorOptions,
|
||||||
vertices: u32,
|
vertices: u32,
|
||||||
|
primitive_shape_type: PrimitiveShapeType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ShapeOptions {
|
impl Default for ShapeOptions {
|
||||||
|
|
@ -37,6 +38,7 @@ impl Default for ShapeOptions {
|
||||||
line_weight: 5.,
|
line_weight: 5.,
|
||||||
fill: ToolColorOptions::new_secondary(),
|
fill: ToolColorOptions::new_secondary(),
|
||||||
stroke: ToolColorOptions::new_primary(),
|
stroke: ToolColorOptions::new_primary(),
|
||||||
|
primitive_shape_type: PrimitiveShapeType::Polygon,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -61,12 +63,19 @@ pub enum ShapeToolMessage {
|
||||||
UpdateOptions(ShapeOptionsUpdate),
|
UpdateOptions(ShapeOptionsUpdate),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Copy, Clone, Debug, Serialize, Deserialize, specta::Type)]
|
||||||
|
pub enum PrimitiveShapeType {
|
||||||
|
Polygon = 0,
|
||||||
|
Star = 1,
|
||||||
|
}
|
||||||
|
|
||||||
#[remain::sorted]
|
#[remain::sorted]
|
||||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)]
|
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)]
|
||||||
pub enum ShapeOptionsUpdate {
|
pub enum ShapeOptionsUpdate {
|
||||||
FillColor(Option<Color>),
|
FillColor(Option<Color>),
|
||||||
FillColorType(ToolColorType),
|
FillColorType(ToolColorType),
|
||||||
LineWeight(f64),
|
LineWeight(f64),
|
||||||
|
PrimitiveShapeType(PrimitiveShapeType),
|
||||||
StrokeColor(Option<Color>),
|
StrokeColor(Option<Color>),
|
||||||
StrokeColorType(ToolColorType),
|
StrokeColorType(ToolColorType),
|
||||||
Vertices(u32),
|
Vertices(u32),
|
||||||
|
|
@ -96,6 +105,14 @@ fn create_sides_widget(vertices: u32) -> WidgetHolder {
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_star_option_widget(primitive_shape_type: PrimitiveShapeType) -> WidgetHolder {
|
||||||
|
let entries = vec![
|
||||||
|
RadioEntryData::new("Polygon").on_update(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::PrimitiveShapeType(PrimitiveShapeType::Polygon)).into()),
|
||||||
|
RadioEntryData::new("Star").on_update(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::PrimitiveShapeType(PrimitiveShapeType::Star)).into()),
|
||||||
|
];
|
||||||
|
RadioInput::new(entries).selected_index(primitive_shape_type as u32).widget_holder()
|
||||||
|
}
|
||||||
|
|
||||||
fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
||||||
NumberInput::new(Some(line_weight))
|
NumberInput::new(Some(line_weight))
|
||||||
.unit(" px")
|
.unit(" px")
|
||||||
|
|
@ -107,7 +124,11 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
||||||
|
|
||||||
impl PropertyHolder for ShapeTool {
|
impl PropertyHolder for ShapeTool {
|
||||||
fn properties(&self) -> Layout {
|
fn properties(&self) -> Layout {
|
||||||
let mut widgets = vec![create_sides_widget(self.options.vertices)];
|
let mut widgets = vec![
|
||||||
|
create_star_option_widget(self.options.primitive_shape_type),
|
||||||
|
WidgetHolder::related_separator(),
|
||||||
|
create_sides_widget(self.options.vertices),
|
||||||
|
];
|
||||||
|
|
||||||
widgets.push(WidgetHolder::section_separator());
|
widgets.push(WidgetHolder::section_separator());
|
||||||
|
|
||||||
|
|
@ -139,6 +160,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for ShapeTo
|
||||||
if let ToolMessage::Shape(ShapeToolMessage::UpdateOptions(action)) = message {
|
if let ToolMessage::Shape(ShapeToolMessage::UpdateOptions(action)) = message {
|
||||||
match action {
|
match action {
|
||||||
ShapeOptionsUpdate::Vertices(vertices) => self.options.vertices = vertices,
|
ShapeOptionsUpdate::Vertices(vertices) => self.options.vertices = vertices,
|
||||||
|
ShapeOptionsUpdate::PrimitiveShapeType(primitive_shape_type) => self.options.primitive_shape_type = primitive_shape_type,
|
||||||
ShapeOptionsUpdate::FillColor(color) => {
|
ShapeOptionsUpdate::FillColor(color) => {
|
||||||
self.options.fill.custom_color = color;
|
self.options.fill.custom_color = color;
|
||||||
self.options.fill.color_type = ToolColorType::Custom;
|
self.options.fill.color_type = ToolColorType::Custom;
|
||||||
|
|
@ -238,7 +260,10 @@ impl Fsm for ShapeToolFsmState {
|
||||||
let layer_path = document.get_path_for_new_layer();
|
let layer_path = document.get_path_for_new_layer();
|
||||||
shape_data.path = Some(layer_path.clone());
|
shape_data.path = Some(layer_path.clone());
|
||||||
|
|
||||||
let subpath = bezier_rs::Subpath::new_regular_polygon(DVec2::ZERO, tool_options.vertices as u64, 1.);
|
let subpath = match tool_options.primitive_shape_type {
|
||||||
|
PrimitiveShapeType::Polygon => bezier_rs::Subpath::new_regular_polygon(DVec2::ZERO, tool_options.vertices as u64, 1.),
|
||||||
|
PrimitiveShapeType::Star => bezier_rs::Subpath::new_regular_star_polygon(DVec2::ZERO, tool_options.vertices as u64, 1., 0.5),
|
||||||
|
};
|
||||||
graph_modification_utils::new_vector_layer(vec![subpath], layer_path.clone(), responses);
|
graph_modification_utils::new_vector_layer(vec![subpath], layer_path.clone(), responses);
|
||||||
|
|
||||||
let fill_color = tool_options.fill.active_color();
|
let fill_color = tool_options.fill.active_color();
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,17 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||||
Self::from_anchors(anchor_positions, true)
|
Self::from_anchors(anchor_positions, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a regular star polygon (n-star). See [new_regular_polygon], but with interspersed vertices at an `inner_radius`.
|
||||||
|
pub fn new_regular_star_polygon(center: DVec2, sides: u64, radius: f64, inner_radius: f64) -> Self {
|
||||||
|
let anchor_positions = (0..sides * 2).map(|i| {
|
||||||
|
let angle = (i as f64) * 0.5 * std::f64::consts::TAU / (sides as f64);
|
||||||
|
let center = center + DVec2::ONE * radius;
|
||||||
|
let r = if i % 2 == 0 { radius } else { inner_radius };
|
||||||
|
DVec2::new(center.x + r * f64::cos(angle), center.y + r * f64::sin(angle)) * 0.5
|
||||||
|
});
|
||||||
|
Self::from_anchors(anchor_positions, true)
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a line from `p1` to `p2`
|
/// Constructs a line from `p1` to `p2`
|
||||||
pub fn new_line(p1: DVec2, p2: DVec2) -> Self {
|
pub fn new_line(p1: DVec2, p2: DVec2) -> Self {
|
||||||
Self::from_anchors([p1, p2], false)
|
Self::from_anchors([p1, p2], false)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue