Implement basic circle stamping (#53)

This commit is contained in:
T0mstone
2021-03-29 01:44:34 +02:00
committed by GitHub
parent c437f1bd22
commit 94f50377a3
10 changed files with 85 additions and 46 deletions
Generated
-7
View File
@@ -49,7 +49,6 @@ name = "graphite-document-core"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"kurbo", "kurbo",
"svg_fmt",
] ]
[[package]] [[package]]
@@ -132,12 +131,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "svg_fmt"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.64" version = "1.0.64"
@@ -17,7 +17,9 @@
@mousedown="canvasMouseDown" @mousedown="canvasMouseDown"
@mouseup="canvasMouseUp" @mouseup="canvasMouseUp"
@mousemove="canvasMouseMove" @mousemove="canvasMouseMove"
></LayoutCol> >
<svg></svg>
</LayoutCol>
</LayoutRow> </LayoutRow>
</LayoutCol> </LayoutCol>
</template> </template>
@@ -65,6 +67,11 @@
.canvas { .canvas {
background: #111; background: #111;
flex: 1 1 100%; flex: 1 1 100%;
svg {
width: 100%;
height: 100%;
}
} }
} }
} }
+2 -2
View File
@@ -1,3 +1,3 @@
export function update_canvas() { export function update_canvas(svg) {
console.log("update_canvas") document.querySelector(".canvas svg").innerHTML = svg;
} }
+3 -3
View File
@@ -9,7 +9,7 @@ use std::cell::RefCell;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
// the thread_local macro provides a way to initialize static variables with non-constant functions // the thread_local macro provides a way to initialize static variables with non-constant functions
thread_local! {pub static EDITOR_STATE: RefCell<Editor> = RefCell::new(Editor::new(Box::new(handle_response)))} thread_local! { pub static EDITOR_STATE: RefCell<Editor> = RefCell::new(Editor::new(Box::new(handle_response))) }
#[wasm_bindgen(start)] #[wasm_bindgen(start)]
pub fn init() { pub fn init() {
@@ -18,13 +18,13 @@ pub fn init() {
fn handle_response(response: Response) { fn handle_response(response: Response) {
match response { match response {
Response::UpdateCanvas => update_canvas(), Response::UpdateCanvas { document } => update_canvas(document),
} }
} }
#[wasm_bindgen(module = "/../src/wasm-callback-processor.js")] #[wasm_bindgen(module = "/../src/wasm-callback-processor.js")]
extern "C" { extern "C" {
fn update_canvas(); fn update_canvas(svg: String);
} }
#[wasm_bindgen] #[wasm_bindgen]
+1 -1
View File
@@ -35,7 +35,7 @@ pub fn on_mouse_down(x: u32, y: u32, mouse_keys: u8) -> Result<(), JsValue> {
#[wasm_bindgen] #[wasm_bindgen]
pub fn on_mouse_up(x: u32, y: u32, mouse_keys: u8) -> Result<(), JsValue> { pub fn on_mouse_up(x: u32, y: u32, mouse_keys: u8) -> Result<(), JsValue> {
let mouse_keys = events::MouseKeys::from_bits(mouse_keys).expect("invalid modifier keys"); let mouse_keys = events::MouseKeys::from_bits(mouse_keys).expect("invalid modifier keys");
let ev = events::Event::MouseDown(events::MouseState { let ev = events::Event::MouseUp(events::MouseState {
position: events::CanvasPosition { x, y }, position: events::CanvasPosition { x, y },
mouse_keys, mouse_keys,
}); });
+1
View File
@@ -9,3 +9,4 @@ repository = "https://github.com/GraphiteEditor/Graphite"
license = "Apache-2.0" license = "Apache-2.0"
[dependencies] [dependencies]
kurbo = "0.8.0"
+25 -5
View File
@@ -1,7 +1,27 @@
#[cfg(test)] pub use kurbo::{Circle, Point};
mod tests {
#[test] #[derive(Debug, Clone, PartialEq)]
fn it_works() { pub enum SvgElement {
assert_eq!(2 + 2, 4); Circle(Circle),
}
impl SvgElement {
pub fn render(&self) -> String {
match self {
Self::Circle(c) => {
format!(r#"<circle cx="{}" cy="{}" r="{}" style="fill: #fff;" />"#, c.center.x, c.center.y, c.radius)
}
}
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Document {
pub svg: Vec<SvgElement>,
}
impl Document {
pub fn render(&self) -> String {
self.svg.iter().map(|element| element.render()).collect::<Vec<_>>().join("\n")
} }
} }
+1 -1
View File
@@ -22,7 +22,7 @@ pub enum Event {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[repr(C)] #[repr(C)]
pub enum Response { pub enum Response {
UpdateCanvas, UpdateCanvas { document: String },
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
+29 -21
View File
@@ -1,6 +1,6 @@
pub mod events; pub mod events;
use crate::tools::ToolState; use crate::{Color, EditorError, EditorState};
use crate::{Color, EditorError}; use document_core::{Circle, Point, SvgElement};
use events::{Event, Response}; use events::{Event, Response};
pub type Callback = Box<dyn Fn(Response)>; pub type Callback = Box<dyn Fn(Response)>;
@@ -9,60 +9,68 @@ pub struct Dispatcher {
} }
impl Dispatcher { impl Dispatcher {
pub fn handle_event(&self, tool_state: &mut ToolState, event: Event) -> Result<(), EditorError> { pub fn handle_event(&self, state: &mut EditorState, event: Event) -> Result<(), EditorError> {
match event { match event {
Event::SelectTool(tool_type) => { Event::SelectTool(tool_type) => {
tool_state.active_tool = tool_type; state.tools.active_tool = tool_type;
Ok(()) Ok(())
} }
Event::SelectPrimaryColor(color) => { Event::SelectPrimaryColor(color) => {
tool_state.primary_color = color; state.tools.primary_color = color;
Ok(()) Ok(())
} }
Event::SelectSecondaryColor(color) => { Event::SelectSecondaryColor(color) => {
tool_state.secondary_color = color; state.tools.secondary_color = color;
Ok(()) Ok(())
} }
Event::SwapColors => { Event::SwapColors => {
std::mem::swap(&mut tool_state.primary_color, &mut tool_state.secondary_color); std::mem::swap(&mut state.tools.primary_color, &mut state.tools.secondary_color);
Ok(()) Ok(())
} }
Event::ResetColors => { Event::ResetColors => {
tool_state.primary_color = Color::BLACK; state.tools.primary_color = Color::BLACK;
tool_state.secondary_color = Color::WHITE; state.tools.secondary_color = Color::WHITE;
Ok(()) Ok(())
} }
Event::MouseDown(mouse_state) => { Event::MouseDown(mouse_state) => {
tool_state.mouse_state = mouse_state; state.tools.mouse_state = mouse_state;
// the state has changed so we add a trace point // the state has changed so we add a trace point
tool_state.record_trace_point(); state.tools.record_trace_point();
self.emit_response(Response::UpdateCanvas); // self.emit_response(Response::UpdateCanvas { document: state.document.render() });
Ok(()) Ok(())
} }
Event::MouseUp(mouse_state) => { Event::MouseUp(mouse_state) => {
tool_state.mouse_state = mouse_state; state.tools.mouse_state = mouse_state;
// the state has changed so we add a trace point // the state has changed so we add a trace point
tool_state.record_trace_point(); state.tools.record_trace_point();
self.emit_response(Response::UpdateCanvas); state.document.svg.push(SvgElement::Circle(Circle {
center: Point {
x: mouse_state.position.x as f64,
y: mouse_state.position.y as f64,
},
radius: 10.0,
}));
self.emit_response(Response::UpdateCanvas { document: state.document.render() });
Ok(()) Ok(())
} }
Event::MouseMovement(pos) => { Event::MouseMovement(pos) => {
tool_state.mouse_state.position = pos; state.tools.mouse_state.position = pos;
tool_state.record_trace_point(); state.tools.record_trace_point();
Ok(()) Ok(())
} }
Event::ModifierKeyDown(mod_keys) => { Event::ModifierKeyDown(mod_keys) => {
tool_state.mod_keys = mod_keys; state.tools.mod_keys = mod_keys;
// the state has changed so we add a trace point // the state has changed so we add a trace point
tool_state.record_trace_point(); state.tools.record_trace_point();
Ok(()) Ok(())
} }
Event::ModifierKeyUp(mod_keys) => { Event::ModifierKeyUp(mod_keys) => {
tool_state.mod_keys = mod_keys; state.tools.mod_keys = mod_keys;
// the state has changed so we add a trace point // the state has changed so we add a trace point
tool_state.record_trace_point(); state.tools.record_trace_point();
Ok(()) Ok(())
} }
Event::KeyPress(key) => todo!(), Event::KeyPress(key) => todo!(),
+15 -5
View File
@@ -17,25 +17,35 @@ pub use dispatcher::events;
pub use dispatcher::Callback; pub use dispatcher::Callback;
use dispatcher::Dispatcher; use dispatcher::Dispatcher;
use document_core::Document;
use tools::ToolState; use tools::ToolState;
use workspace::Workspace; use workspace::Workspace;
// TODO: serialize with serde to save the current editor state pub struct EditorState {
pub struct Editor {
tools: ToolState, tools: ToolState,
workspace: Workspace, workspace: Workspace,
document: Document,
}
// TODO: serialize with serde to save the current editor state
pub struct Editor {
state: EditorState,
dispatcher: Dispatcher, dispatcher: Dispatcher,
} }
impl Editor { impl Editor {
pub fn new(callback: Callback) -> Self { pub fn new(callback: Callback) -> Self {
Self { Self {
tools: ToolState::new(), state: EditorState {
workspace: Workspace::new(), tools: ToolState::new(),
workspace: Workspace::new(),
document: Document::default(),
},
dispatcher: Dispatcher::new(callback), dispatcher: Dispatcher::new(callback),
} }
} }
pub fn handle_event(&mut self, event: events::Event) -> Result<(), EditorError> { pub fn handle_event(&mut self, event: events::Event) -> Result<(), EditorError> {
self.dispatcher.handle_event(&mut self.tools, event) self.dispatcher.handle_event(&mut self.state, event)
} }
} }