mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-28 22:58:12 +08:00
Implement active tool visual syncing with tool shelf state
This commit is contained in:
@@ -35,36 +35,36 @@
|
|||||||
<LayoutRow :class="'shelf-and-viewport'">
|
<LayoutRow :class="'shelf-and-viewport'">
|
||||||
<LayoutCol :class="'shelf'">
|
<LayoutCol :class="'shelf'">
|
||||||
<div class="tools">
|
<div class="tools">
|
||||||
<ShelfItem active title="Select Tool (V)"><SelectTool /></ShelfItem>
|
<ShelfItem title="Select Tool (V)" :active="activeTool === 'Select'" @click="selectTool('Select')"><SelectTool /></ShelfItem>
|
||||||
<ShelfItem title="Crop Tool"><CropTool /></ShelfItem>
|
<ShelfItem title="Crop Tool" :active="activeTool === 'Crop'" @click="'tool not implemented' || selectTool('Crop')"><CropTool /></ShelfItem>
|
||||||
<ShelfItem title="Navigate Tool"><NavigateTool /></ShelfItem>
|
<ShelfItem title="Navigate Tool" :active="activeTool === 'Navigate'" @click="'tool not implemented' || selectTool('Navigate')"><NavigateTool /></ShelfItem>
|
||||||
<ShelfItem title="Sample Tool"><SampleTool /></ShelfItem>
|
<ShelfItem title="Sample Tool" :active="activeTool === 'Sample'" @click="'tool not implemented' || selectTool('Sample')"><SampleTool /></ShelfItem>
|
||||||
|
|
||||||
<ItemDivider horizontal />
|
<ItemDivider horizontal />
|
||||||
|
|
||||||
<ShelfItem title="Text Tool"><TextTool /></ShelfItem>
|
<ShelfItem title="Text Tool" :active="activeTool === 'Text'" @click="'tool not implemented' || selectTool('Text')"><TextTool /></ShelfItem>
|
||||||
<ShelfItem title="Fill Tool"><FillTool /></ShelfItem>
|
<ShelfItem title="Fill Tool" :active="activeTool === 'Fill'" @click="'tool not implemented' || selectTool('Fill')"><FillTool /></ShelfItem>
|
||||||
<ShelfItem title="Gradient Tool"><GradientTool /></ShelfItem>
|
<ShelfItem title="Gradient Tool" :active="activeTool === 'Gradient'" @click="'tool not implemented' || selectTool('Gradient')"><GradientTool /></ShelfItem>
|
||||||
|
|
||||||
<ItemDivider horizontal />
|
<ItemDivider horizontal />
|
||||||
|
|
||||||
<ShelfItem title="Brush Tool"><BrushTool /></ShelfItem>
|
<ShelfItem title="Brush Tool" :active="activeTool === 'Brush'" @click="'tool not implemented' || selectTool('Brush')"><BrushTool /></ShelfItem>
|
||||||
<ShelfItem title="Heal Tool"><HealTool /></ShelfItem>
|
<ShelfItem title="Heal Tool" :active="activeTool === 'Heal'" @click="'tool not implemented' || selectTool('Heal')"><HealTool /></ShelfItem>
|
||||||
<ShelfItem title="Clone Tool"><CloneTool /></ShelfItem>
|
<ShelfItem title="Clone Tool" :active="activeTool === 'Clone'" @click="'tool not implemented' || selectTool('Clone')"><CloneTool /></ShelfItem>
|
||||||
<ShelfItem title="Patch Tool"><PatchTool /></ShelfItem>
|
<ShelfItem title="Patch Tool" :active="activeTool === 'Patch'" @click="'tool not implemented' || selectTool('Patch')"><PatchTool /></ShelfItem>
|
||||||
<ShelfItem title="Blur/Sharpen Tool"><BlurSharpenTool /></ShelfItem>
|
<ShelfItem title="Blur/Sharpen Tool" :active="activeTool === 'BlurSharpen'" @click="'tool not implemented' || selectTool('BlurSharpen')"><BlurSharpenTool /></ShelfItem>
|
||||||
<ShelfItem title="Relight Tool"><RelightTool /></ShelfItem>
|
<ShelfItem title="Relight Tool" :active="activeTool === 'Relight'" @click="'tool not implemented' || selectTool('Relight')"><RelightTool /></ShelfItem>
|
||||||
|
|
||||||
<ItemDivider horizontal />
|
<ItemDivider horizontal />
|
||||||
|
|
||||||
<ShelfItem title="Path Tool"><PathTool /></ShelfItem>
|
<ShelfItem title="Path Tool" :active="activeTool === 'Path'" @click="'tool not implemented' || selectTool('Path')"><PathTool /></ShelfItem>
|
||||||
<ShelfItem title="Pen Tool"><PenTool /></ShelfItem>
|
<ShelfItem title="Pen Tool" :active="activeTool === 'Pen'" @click="'tool not implemented' || selectTool('Pen')"><PenTool /></ShelfItem>
|
||||||
<ShelfItem title="Freehand Tool"><FreehandTool /></ShelfItem>
|
<ShelfItem title="Freehand Tool" :active="activeTool === 'Freehand'" @click="'tool not implemented' || selectTool('Freehand')"><FreehandTool /></ShelfItem>
|
||||||
<ShelfItem title="Spline Tool"><SplineTool /></ShelfItem>
|
<ShelfItem title="Spline Tool" :active="activeTool === 'Spline'" @click="'tool not implemented' || selectTool('Spline')"><SplineTool /></ShelfItem>
|
||||||
<ShelfItem title="Line Tool"><LineTool /></ShelfItem>
|
<ShelfItem title="Line Tool" :active="activeTool === 'Line'" @click="'tool not implemented' || selectTool('Line')"><LineTool /></ShelfItem>
|
||||||
<ShelfItem title="Rectangle Tool (M)"><RectangleTool /></ShelfItem>
|
<ShelfItem title="Rectangle Tool (M)" :active="activeTool === 'Rectangle'" @click="selectTool('Rectangle')"><RectangleTool /></ShelfItem>
|
||||||
<ShelfItem title="Ellipse Tool (E)"><EllipseTool /></ShelfItem>
|
<ShelfItem title="Ellipse Tool (E)" :active="activeTool === 'Ellipse'" @click="selectTool('Ellipse')"><EllipseTool /></ShelfItem>
|
||||||
<ShelfItem title="Shape Tool"><ShapeTool /></ShelfItem>
|
<ShelfItem title="Shape Tool" :active="activeTool === 'Shape'" @click="'tool not implemented' || selectTool('Shape')"><ShapeTool /></ShelfItem>
|
||||||
</div>
|
</div>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<div class="working-colors">
|
<div class="working-colors">
|
||||||
@@ -293,17 +293,26 @@ export default defineComponent({
|
|||||||
const { on_key_up } = await wasm;
|
const { on_key_up } = await wasm;
|
||||||
on_key_up(e.key);
|
on_key_up(e.key);
|
||||||
},
|
},
|
||||||
|
async selectTool(toolName: string) {
|
||||||
|
const { select_tool } = await wasm;
|
||||||
|
select_tool(toolName);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
registerResponseHandler(ResponseType.UpdateCanvas, (responseData) => {
|
registerResponseHandler(ResponseType.UpdateCanvas, (responseData) => {
|
||||||
this.viewportSvg = responseData;
|
this.viewportSvg = responseData.split("\n").map((shape, i) => shape.replace("#fff", `#${Math.floor(Math.abs(Math.sin(i + 1)) * 16777215).toString(16)}`)).join("\n");
|
||||||
});
|
});
|
||||||
|
registerResponseHandler(ResponseType.SetActiveTool, (responseData) => {
|
||||||
|
this.activeTool = responseData;
|
||||||
|
});
|
||||||
|
|
||||||
window.addEventListener("keyup", (e: KeyboardEvent) => this.keyUp(e));
|
window.addEventListener("keyup", (e: KeyboardEvent) => this.keyUp(e));
|
||||||
window.addEventListener("keydown", (e: KeyboardEvent) => this.keyDown(e));
|
window.addEventListener("keydown", (e: KeyboardEvent) => this.keyDown(e));
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
viewportSvg: "",
|
viewportSvg: "",
|
||||||
|
activeTool: "Select",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ declare global {
|
|||||||
|
|
||||||
export enum ResponseType {
|
export enum ResponseType {
|
||||||
UpdateCanvas = "UpdateCanvas",
|
UpdateCanvas = "UpdateCanvas",
|
||||||
|
SetActiveTool = "SetActiveTool",
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attachResponseHandlerToPage() {
|
export function attachResponseHandlerToPage() {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ fn handle_response(response: Response) {
|
|||||||
let response_type = response.to_string();
|
let response_type = response.to_string();
|
||||||
match response {
|
match response {
|
||||||
Response::UpdateCanvas { document } => handleResponse(response_type, document),
|
Response::UpdateCanvas { document } => handleResponse(response_type, document),
|
||||||
|
Response::SetActiveTool { tool_name } => handleResponse(response_type, tool_name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,19 @@ pub fn translate_tool(name: &str) -> Option<ToolType> {
|
|||||||
"Crop" => Some(ToolType::Crop),
|
"Crop" => Some(ToolType::Crop),
|
||||||
"Navigate" => Some(ToolType::Navigate),
|
"Navigate" => Some(ToolType::Navigate),
|
||||||
"Sample" => Some(ToolType::Sample),
|
"Sample" => Some(ToolType::Sample),
|
||||||
|
"Text" => Some(ToolType::Text),
|
||||||
|
"Fill" => Some(ToolType::Fill),
|
||||||
|
"Gradient" => Some(ToolType::Gradient),
|
||||||
|
"Brush" => Some(ToolType::Brush),
|
||||||
|
"Heal" => Some(ToolType::Heal),
|
||||||
|
"Clone" => Some(ToolType::Clone),
|
||||||
|
"Patch" => Some(ToolType::Patch),
|
||||||
|
"BlurSharpen" => Some(ToolType::BlurSharpen),
|
||||||
|
"Relight" => Some(ToolType::Relight),
|
||||||
"Path" => Some(ToolType::Path),
|
"Path" => Some(ToolType::Path),
|
||||||
"Pen" => Some(ToolType::Pen),
|
"Pen" => Some(ToolType::Pen),
|
||||||
|
"Freehand" => Some(ToolType::Freehand),
|
||||||
|
"Spline" => Some(ToolType::Spline),
|
||||||
"Line" => Some(ToolType::Line),
|
"Line" => Some(ToolType::Line),
|
||||||
"Rectangle" => Some(ToolType::Rectangle),
|
"Rectangle" => Some(ToolType::Rectangle),
|
||||||
"Ellipse" => Some(ToolType::Ellipse),
|
"Ellipse" => Some(ToolType::Ellipse),
|
||||||
|
|||||||
@@ -26,12 +26,14 @@ pub enum Event {
|
|||||||
// TODO - Make Copy when possible
|
// TODO - Make Copy when possible
|
||||||
pub enum Response {
|
pub enum Response {
|
||||||
UpdateCanvas { document: String },
|
UpdateCanvas { document: String },
|
||||||
|
SetActiveTool { tool_name: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Response {
|
impl fmt::Display for Response {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Response::UpdateCanvas { document: _ } => write!(formatter, "UpdateCanvas"),
|
Response::UpdateCanvas { document: _ } => write!(formatter, "UpdateCanvas"),
|
||||||
|
Response::SetActiveTool { tool_name: _ } => write!(formatter, "SetActiveTool"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ impl Dispatcher {
|
|||||||
log::trace!("{:?}", event);
|
log::trace!("{:?}", event);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::SelectTool(tool_type) => {
|
Event::SelectTool(tool_name) => {
|
||||||
editor_state.tool_state.active_tool_type = *tool_type;
|
editor_state.tool_state.active_tool_type = *tool_name;
|
||||||
|
self.dispatch_response(Response::SetActiveTool { tool_name: tool_name.to_string() });
|
||||||
}
|
}
|
||||||
Event::SelectPrimaryColor(color) => {
|
Event::SelectPrimaryColor(color) => {
|
||||||
editor_state.tool_state.primary_color = *color;
|
editor_state.tool_state.primary_color = *color;
|
||||||
@@ -56,14 +57,23 @@ impl Dispatcher {
|
|||||||
log::set_max_level(log::LevelFilter::Trace);
|
log::set_max_level(log::LevelFilter::Trace);
|
||||||
log::debug!("set log verbosity to trace");
|
log::debug!("set log verbosity to trace");
|
||||||
}
|
}
|
||||||
|
Key::KeyV => {
|
||||||
|
editor_state.tool_state.active_tool_type = ToolType::Select;
|
||||||
|
self.dispatch_response(Response::SetActiveTool {
|
||||||
|
tool_name: ToolType::Select.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
Key::KeyM => {
|
Key::KeyM => {
|
||||||
editor_state.tool_state.active_tool_type = ToolType::Rectangle;
|
editor_state.tool_state.active_tool_type = ToolType::Rectangle;
|
||||||
|
self.dispatch_response(Response::SetActiveTool {
|
||||||
|
tool_name: ToolType::Rectangle.to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Key::KeyE => {
|
Key::KeyE => {
|
||||||
editor_state.tool_state.active_tool_type = ToolType::Ellipse;
|
editor_state.tool_state.active_tool_type = ToolType::Ellipse;
|
||||||
}
|
self.dispatch_response(Response::SetActiveTool {
|
||||||
Key::KeyV => {
|
tool_name: ToolType::Ellipse.to_string(),
|
||||||
editor_state.tool_state.active_tool_type = ToolType::Select;
|
});
|
||||||
}
|
}
|
||||||
Key::KeyX => {
|
Key::KeyX => {
|
||||||
editor_state.tool_state.swap_colors();
|
editor_state.tool_state.swap_colors();
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use crate::Color;
|
|||||||
use crate::Document;
|
use crate::Document;
|
||||||
use crate::EditorError;
|
use crate::EditorError;
|
||||||
use document_core::Operation;
|
use document_core::Operation;
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, fmt};
|
||||||
|
|
||||||
pub trait Tool {
|
pub trait Tool {
|
||||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>);
|
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>);
|
||||||
@@ -44,7 +44,7 @@ impl Default for ToolFsmState {
|
|||||||
trace: Trace::new(),
|
trace: Trace::new(),
|
||||||
primary_color: Color::BLACK,
|
primary_color: Color::BLACK,
|
||||||
secondary_color: Color::WHITE,
|
secondary_color: Color::WHITE,
|
||||||
active_tool_type: ToolType::Rectangle,
|
active_tool_type: ToolType::Select,
|
||||||
tools: gen_tools_hash_map! {
|
tools: gen_tools_hash_map! {
|
||||||
Select => select::Select,
|
Select => select::Select,
|
||||||
Crop => crop::Crop,
|
Crop => crop::Crop,
|
||||||
@@ -103,13 +103,51 @@ pub enum ToolType {
|
|||||||
Crop,
|
Crop,
|
||||||
Navigate,
|
Navigate,
|
||||||
Sample,
|
Sample,
|
||||||
|
Text,
|
||||||
|
Fill,
|
||||||
|
Gradient,
|
||||||
|
Brush,
|
||||||
|
Heal,
|
||||||
|
Clone,
|
||||||
|
Patch,
|
||||||
|
BlurSharpen,
|
||||||
|
Relight,
|
||||||
Path,
|
Path,
|
||||||
Pen,
|
Pen,
|
||||||
|
Freehand,
|
||||||
|
Spline,
|
||||||
Line,
|
Line,
|
||||||
Rectangle,
|
Rectangle,
|
||||||
Ellipse,
|
Ellipse,
|
||||||
Shape,
|
Shape,
|
||||||
// all discriminats must be strictly smaller than TOOL_COUNT!
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ToolType {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ToolType::Select => write!(formatter, "Select"),
|
||||||
|
ToolType::Crop => write!(formatter, "Crop"),
|
||||||
|
ToolType::Navigate => write!(formatter, "Navigate"),
|
||||||
|
ToolType::Sample => write!(formatter, "Sample"),
|
||||||
|
ToolType::Text => write!(formatter, "Text"),
|
||||||
|
ToolType::Fill => write!(formatter, "Fill"),
|
||||||
|
ToolType::Gradient => write!(formatter, "Gradient"),
|
||||||
|
ToolType::Brush => write!(formatter, "Brush"),
|
||||||
|
ToolType::Heal => write!(formatter, "Heal"),
|
||||||
|
ToolType::Clone => write!(formatter, "Clone"),
|
||||||
|
ToolType::Patch => write!(formatter, "Patch"),
|
||||||
|
ToolType::BlurSharpen => write!(formatter, "BlurSharpen"),
|
||||||
|
ToolType::Relight => write!(formatter, "Relight"),
|
||||||
|
ToolType::Path => write!(formatter, "Path"),
|
||||||
|
ToolType::Pen => write!(formatter, "Pen"),
|
||||||
|
ToolType::Freehand => write!(formatter, "Freehand"),
|
||||||
|
ToolType::Spline => write!(formatter, "Spline"),
|
||||||
|
ToolType::Line => write!(formatter, "Line"),
|
||||||
|
ToolType::Rectangle => write!(formatter, "Rectangle"),
|
||||||
|
ToolType::Ellipse => write!(formatter, "Ellipse"),
|
||||||
|
ToolType::Shape => write!(formatter, "Shape"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToolType {
|
impl ToolType {
|
||||||
|
|||||||
Reference in New Issue
Block a user