Options bar widgets for tools to control tool behavior (#283)

* Add JSON-backed options widget

* Add initial tool settings messaging to backend

* Add shape side selection with JSON deserialization

* Enforce minimum number of n-gon sides

* Make tool settings JSON errors safer

* Make tool settings JSON errors safer

* Refactor ToolOptions to ToolSettings

* Revert "Refactor ToolOptions to ToolSettings"

This reverts commit 651161fd16.

* Refactor all instances of "settings" to "options"

* Fix names and formatting

* Rearrange ToolOptions data to enforce types
This commit is contained in:
Henry Sloan
2021-07-21 01:07:48 -04:00
committed by GitHub
parent bc733acb4c
commit 06c26f44d0
8 changed files with 198 additions and 80 deletions

View File

@@ -1,5 +1,5 @@
pub mod tool_message_handler;
pub mod tool_settings;
pub mod tool_options;
pub mod tools;
use crate::document::Document;
@@ -15,8 +15,8 @@ use std::{
fmt::{self, Debug},
};
pub use tool_message_handler::ToolMessageHandler;
use tool_settings::ToolSettings;
pub use tool_settings::*;
use tool_options::ToolOptions;
pub use tool_options::*;
use tools::*;
pub mod tool_messages {
@@ -37,7 +37,7 @@ pub trait Fsm {
pub struct DocumentToolData {
pub primary_color: Color,
pub secondary_color: Color,
tool_settings: HashMap<ToolType, ToolSettings>,
pub tool_options: HashMap<ToolType, ToolOptions>,
}
type SubToolMessageHandler = dyn for<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>>;
@@ -48,7 +48,7 @@ pub struct ToolData {
impl fmt::Debug for ToolData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ToolData").field("active_tool_type", &self.active_tool_type).field("tool_settings", &"[…]").finish()
f.debug_struct("ToolData").field("active_tool_type", &self.active_tool_type).field("tool_options", &"[…]").finish()
}
}
@@ -89,7 +89,7 @@ impl Default for ToolFsmState {
document_tool_data: DocumentToolData {
primary_color: Color::BLACK,
secondary_color: Color::WHITE,
tool_settings: default_tool_settings(),
tool_options: default_tool_options(),
},
}
}
@@ -105,8 +105,8 @@ impl ToolFsmState {
}
}
fn default_tool_settings() -> HashMap<ToolType, ToolSettings> {
let tool_init = |tool: ToolType| (tool, tool.default_settings());
fn default_tool_options() -> HashMap<ToolType, ToolOptions> {
let tool_init = |tool: ToolType| (tool, tool.default_options());
std::array::IntoIter::new([
tool_init(ToolType::Select),
tool_init(ToolType::Ellipse),
@@ -174,12 +174,12 @@ impl fmt::Display for ToolType {
}
impl ToolType {
fn default_settings(&self) -> ToolSettings {
fn default_options(&self) -> ToolOptions {
match self {
ToolType::Select => ToolSettings::Select { append_mode: SelectAppendMode::New },
ToolType::Ellipse => ToolSettings::Ellipse,
ToolType::Shape => ToolSettings::Shape {
shape: Shape::Polygon { vertices: 3 },
ToolType::Select => ToolOptions::Select { append_mode: SelectAppendMode::New },
ToolType::Ellipse => ToolOptions::Ellipse,
ToolType::Shape => ToolOptions::Shape {
shape_type: ShapeType::Polygon { vertices: 6 },
},
_ => todo!(),
}

View File

@@ -4,7 +4,7 @@ use document_core::color::Color;
use crate::input::InputPreprocessor;
use crate::{
document::Document,
tool::{ToolFsmState, ToolType},
tool::{tool_options::ToolOptions, ToolFsmState, ToolType},
};
use std::collections::VecDeque;
@@ -16,6 +16,7 @@ pub enum ToolMessage {
SelectSecondaryColor(Color),
SwapColors,
ResetColors,
SetToolOptions(ToolType, ToolOptions),
#[child]
Fill(FillMessage),
#[child]
@@ -89,6 +90,9 @@ impl MessageHandler<ToolMessage, (&Document, &InputPreprocessor)> for ToolMessag
.into(),
)
}
SetToolOptions(tool_type, tool_options) => {
self.tool_state.document_tool_data.tool_options.insert(tool_type, tool_options);
}
message => {
let tool_type = match message {
Fill(_) => ToolType::Fill,
@@ -111,7 +115,7 @@ impl MessageHandler<ToolMessage, (&Document, &InputPreprocessor)> for ToolMessag
}
}
fn actions(&self) -> ActionList {
let mut list = actions!(ToolMessageDiscriminant; ResetColors, SwapColors, SelectTool);
let mut list = actions!(ToolMessageDiscriminant; ResetColors, SwapColors, SelectTool, SetToolOptions);
list.extend(self.tool_state.tool_data.active_tool().actions());
list
}

View File

@@ -0,0 +1,22 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
pub enum ToolOptions {
Select { append_mode: SelectAppendMode },
Ellipse,
Shape { shape_type: ShapeType },
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
pub enum SelectAppendMode {
New,
Add,
Subtract,
Intersect,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
pub enum ShapeType {
Star { vertices: u32 },
Polygon { vertices: u32 },
}

View File

@@ -1,20 +0,0 @@
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ToolSettings {
Select { append_mode: SelectAppendMode },
Ellipse,
Shape { shape: Shape },
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum SelectAppendMode {
New,
Add,
Subtract,
Intersect,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Shape {
Star { vertices: u32 },
Polygon { vertices: u32 },
}

View File

@@ -1,5 +1,5 @@
use crate::input::{mouse::ViewportPosition, InputPreprocessor};
use crate::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
use crate::tool::{DocumentToolData, Fsm, ShapeType, ToolActionHandlerData, ToolOptions, ToolType};
use crate::{document::Document, message_prelude::*};
use document_core::{layers::style, Operation};
use glam::{DAffine2, DVec2};
@@ -70,7 +70,12 @@ impl Fsm for ShapeToolFsmState {
data.drag_start = input.mouse.position;
data.drag_current = input.mouse.position;
data.sides = 6;
data.sides = match tool_data.tool_options.get(&ToolType::Shape) {
Some(&ToolOptions::Shape {
shape_type: ShapeType::Polygon { vertices },
}) => vertices as u8,
_ => 6,
};
responses.push_back(Operation::MountWorkingFolder { path: vec![] }.into());
Dragging