mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-30 21:58:12 +08:00
Add plumbing for event system (#52)
* Add plumbing for event system * Apply review suggestions * Add swap and reset color functions
This commit is contained in:
Generated
+33
@@ -1,5 +1,17 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.6.1"
|
version = "3.6.1"
|
||||||
@@ -35,11 +47,17 @@ version = "0.1.0"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "graphite-document-core"
|
name = "graphite-document-core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"kurbo",
|
||||||
|
"svg_fmt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "graphite-editor-core"
|
name = "graphite-editor-core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"graphite-document-core",
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -66,6 +84,15 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kurbo"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb348d766edbac91ba1eb83020d96f4f8867924d194393083c15a51f185e6a82"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -105,6 +132,12 @@ 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"
|
||||||
|
|||||||
Generated
+89
-89
@@ -605,6 +605,95 @@
|
|||||||
"tslint": "^5.20.1",
|
"tslint": "^5.20.1",
|
||||||
"webpack": "^4.0.0",
|
"webpack": "^4.0.0",
|
||||||
"yorkie": "^2.0.0"
|
"yorkie": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"fork-ts-checker-webpack-plugin-v5": {
|
||||||
|
"version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/code-frame": "^7.8.3",
|
||||||
|
"@types/json-schema": "^7.0.5",
|
||||||
|
"chalk": "^4.1.0",
|
||||||
|
"cosmiconfig": "^6.0.0",
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"fs-extra": "^9.0.0",
|
||||||
|
"memfs": "^3.1.2",
|
||||||
|
"minimatch": "^3.0.4",
|
||||||
|
"schema-utils": "2.7.0",
|
||||||
|
"semver": "^7.3.2",
|
||||||
|
"tapable": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"schema-utils": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/json-schema": "^7.0.4",
|
||||||
|
"ajv": "^6.12.2",
|
||||||
|
"ajv-keywords": "^3.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@vue/cli-plugin-vuex": {
|
"@vue/cli-plugin-vuex": {
|
||||||
@@ -5386,95 +5475,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fork-ts-checker-webpack-plugin-v5": {
|
|
||||||
"version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz",
|
|
||||||
"integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"@babel/code-frame": "^7.8.3",
|
|
||||||
"@types/json-schema": "^7.0.5",
|
|
||||||
"chalk": "^4.1.0",
|
|
||||||
"cosmiconfig": "^6.0.0",
|
|
||||||
"deepmerge": "^4.2.2",
|
|
||||||
"fs-extra": "^9.0.0",
|
|
||||||
"memfs": "^3.1.2",
|
|
||||||
"minimatch": "^3.0.4",
|
|
||||||
"schema-utils": "2.7.0",
|
|
||||||
"semver": "^7.3.2",
|
|
||||||
"tapable": "^1.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-styles": {
|
|
||||||
"version": "4.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
|
||||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"color-convert": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chalk": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
|
||||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"ansi-styles": "^4.1.0",
|
|
||||||
"supports-color": "^7.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-convert": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"color-name": "~1.1.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-name": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"has-flag": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"schema-utils": {
|
|
||||||
"version": "2.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
|
|
||||||
"integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/json-schema": "^7.0.4",
|
|
||||||
"ajv": "^6.12.2",
|
|
||||||
"ajv-keywords": "^3.4.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"supports-color": {
|
|
||||||
"version": "7.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
|
||||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"has-flag": "^4.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"form-data": {
|
"form-data": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||||
|
|||||||
@@ -12,7 +12,12 @@
|
|||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
<LayoutRow :class="'tools-and-viewport'">
|
<LayoutRow :class="'tools-and-viewport'">
|
||||||
<LayoutCol :class="'tools'"></LayoutCol>
|
<LayoutCol :class="'tools'"></LayoutCol>
|
||||||
<LayoutCol :class="'viewport-container'" @click="canvasClick"></LayoutCol>
|
<LayoutCol
|
||||||
|
:class="'canvas'"
|
||||||
|
@mousedown="canvasMouseDown"
|
||||||
|
@mouseup="canvasMouseUp"
|
||||||
|
@mousemove="canvasMouseMove"
|
||||||
|
></LayoutCol>
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
</LayoutCol>
|
</LayoutCol>
|
||||||
</template>
|
</template>
|
||||||
@@ -57,7 +62,7 @@
|
|||||||
flex: 0 0 32px;
|
flex: 0 0 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewport-container {
|
.canvas {
|
||||||
background: #111;
|
background: #111;
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
}
|
}
|
||||||
@@ -78,11 +83,21 @@ export default defineComponent({
|
|||||||
LayoutCol,
|
LayoutCol,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async canvasClick(e: MouseEvent) {
|
async canvasMouseDown(e: MouseEvent) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
const { on_mouse_click } = await wasm;
|
const { on_mouse_down } = await wasm;
|
||||||
on_mouse_click(e.offsetX, e.offsetY);
|
on_mouse_down(e.offsetX, e.offsetY, e.buttons);
|
||||||
}
|
},
|
||||||
|
async canvasMouseUp(e: MouseEvent) {
|
||||||
|
console.log(e);
|
||||||
|
const { on_mouse_up } = await wasm;
|
||||||
|
on_mouse_up(e.offsetX, e.offsetY, e.buttons);
|
||||||
|
},
|
||||||
|
async canvasMouseMove(e: MouseEvent) {
|
||||||
|
console.log(e);
|
||||||
|
const { on_mouse_move } = await wasm;
|
||||||
|
on_mouse_move(e.offsetX, e.offsetY);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -8,51 +8,68 @@ use wasm_bindgen::prelude::*;
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn select_tool(tool: String) -> Result<(), JsValue> {
|
pub fn select_tool(tool: String) -> Result<(), JsValue> {
|
||||||
EDITOR_STATE.with(|editor| match translate_tool(&tool) {
|
EDITOR_STATE.with(|editor| match translate_tool(&tool) {
|
||||||
Some(tool) => {
|
Some(tool) => editor.borrow_mut().handle_event(events::Event::SelectTool(tool)).map_err(|err| Error::new(&err.to_string()).into()),
|
||||||
editor.borrow_mut().tools.active_tool = tool;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
None => Err(Error::new(&format!("Couldn't select {} because it was not recognized as a valid tool", tool)).into()),
|
None => Err(Error::new(&format!("Couldn't select {} because it was not recognized as a valid tool", tool)).into()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mouse movement with the bounds of the canvas
|
/// Mouse movement with the bounds of the canvas
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn on_mouse_move(x: u32, y: u32) {
|
pub fn on_mouse_move(x: u32, y: u32) -> Result<(), JsValue> {
|
||||||
EDITOR_STATE.with(|editor| {
|
let ev = events::Event::MouseMovement(events::CanvasPosition { x, y });
|
||||||
let mut editor = editor.borrow_mut();
|
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_event(ev)).map_err(|err| Error::new(&err.to_string()).into())
|
||||||
if editor.tools.mouse_is_clicked {
|
|
||||||
editor.tools.trace.append_point(x, y)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mouse click within the bounds of the canvas
|
/// Mouse click within the bounds of the canvas
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn on_mouse_click(x: u32, y: u32) -> Result<(), JsValue> {
|
pub fn on_mouse_down(x: u32, y: u32, mouse_keys: u8) -> Result<(), JsValue> {
|
||||||
let ev = events::Event::Click(events::MouseState::from_pos(x, y));
|
let mouse_keys = events::MouseKeys::from_bits(mouse_keys).expect("invalid modifier keys");
|
||||||
EDITOR_STATE
|
let ev = events::Event::MouseDown(events::MouseState {
|
||||||
.with(|editor| {
|
position: events::CanvasPosition { x, y },
|
||||||
let mut editor = editor.borrow_mut();
|
mouse_keys,
|
||||||
editor.tools.mouse_is_clicked = true;
|
});
|
||||||
editor.tools.trace.clear();
|
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_event(ev)).map_err(|err| Error::new(&err.to_string()).into())
|
||||||
editor.handle_event(ev)
|
|
||||||
})
|
|
||||||
.map_err(|err| Error::new(&err.to_string()).into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mouse released
|
/// Mouse released
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn on_mouse_release() {
|
pub fn on_mouse_up(x: u32, y: u32, mouse_keys: u8) -> Result<(), JsValue> {
|
||||||
EDITOR_STATE.with(|editor| editor.borrow_mut().tools.mouse_is_clicked = false)
|
let mouse_keys = events::MouseKeys::from_bits(mouse_keys).expect("invalid modifier keys");
|
||||||
|
let ev = events::Event::MouseDown(events::MouseState {
|
||||||
|
position: events::CanvasPosition { x, y },
|
||||||
|
mouse_keys,
|
||||||
|
});
|
||||||
|
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_event(ev)).map_err(|err| Error::new(&err.to_string()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update working colors
|
/// Update primary color
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn update_colors(primary_color: Color, secondary_color: Color) {
|
pub fn update_primary_color(primary_color: Color) -> Result<(), JsValue> {
|
||||||
EDITOR_STATE.with(|editor| {
|
EDITOR_STATE
|
||||||
let mut editor = editor.borrow_mut();
|
.with(|editor| editor.borrow_mut().handle_event(events::Event::SelectPrimaryColor(primary_color.inner())))
|
||||||
editor.tools.primary_color = primary_color.inner();
|
.map_err(|err: editor_core::EditorError| Error::new(&err.to_string()).into())
|
||||||
editor.tools.secondary_color = secondary_color.inner();
|
}
|
||||||
})
|
|
||||||
|
/// Update secondary color
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn update_secondary_color(secondary_color: Color) -> Result<(), JsValue> {
|
||||||
|
EDITOR_STATE
|
||||||
|
.with(|editor| editor.borrow_mut().handle_event(events::Event::SelectSecondaryColor(secondary_color.inner())))
|
||||||
|
.map_err(|err: editor_core::EditorError| Error::new(&err.to_string()).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Swap primary and secondary color
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn swap_colors() -> Result<(), JsValue> {
|
||||||
|
EDITOR_STATE
|
||||||
|
.with(|editor| editor.borrow_mut().handle_event(events::Event::SwapColors))
|
||||||
|
.map_err(|err: editor_core::EditorError| Error::new(&err.to_string()).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset primary and secondary colors to their defaults
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn reset_colors() -> Result<(), JsValue> {
|
||||||
|
EDITOR_STATE
|
||||||
|
.with(|editor| editor.borrow_mut().handle_event(events::Event::ResetColors))
|
||||||
|
.map_err(|err: editor_core::EditorError| Error::new(&err.to_string()).into())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,3 +10,8 @@ license = "Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
bitflags = "1.2.1"
|
||||||
|
|
||||||
|
[dependencies.document-core]
|
||||||
|
path = "../document"
|
||||||
|
package = "graphite-document-core"
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
use crate::tools::ToolType;
|
use crate::tools::ToolType;
|
||||||
|
use crate::Color;
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
SelectTool(ToolType),
|
SelectTool(ToolType),
|
||||||
ModifierKeyDown(ModKey),
|
SelectPrimaryColor(Color),
|
||||||
ModifierKeyUp(ModKey),
|
SelectSecondaryColor(Color),
|
||||||
MouseMovement(Trace),
|
SwapColors,
|
||||||
Click(MouseState),
|
ResetColors,
|
||||||
|
MouseDown(MouseState),
|
||||||
|
MouseUp(MouseState),
|
||||||
|
MouseMovement(CanvasPosition),
|
||||||
|
ModifierKeyDown(ModKeys),
|
||||||
|
ModifierKeyUp(ModKeys),
|
||||||
KeyPress(Key),
|
KeyPress(Key),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,92 +26,81 @@ pub enum Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct Trace(Vec<MouseState>);
|
pub struct Trace(Vec<TracePoint>);
|
||||||
|
|
||||||
|
impl Deref for Trace {
|
||||||
|
type Target = Vec<TracePoint>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Trace {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Trace {
|
impl Trace {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
pub fn first_point(&self) -> Option<&MouseState> {
|
|
||||||
self.0.first()
|
|
||||||
}
|
|
||||||
pub fn last_point(&self) -> Option<&MouseState> {
|
|
||||||
self.0.last()
|
|
||||||
}
|
|
||||||
pub fn append_point(&mut self, x: u32, y: u32) {
|
|
||||||
self.0.push(MouseState::from_pos(x, y))
|
|
||||||
}
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.0.clear()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
|
// origin is top left
|
||||||
|
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
|
||||||
|
pub struct CanvasPosition {
|
||||||
|
pub x: u32,
|
||||||
|
pub y: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
|
||||||
|
pub struct TracePoint {
|
||||||
|
pub mouse_state: MouseState,
|
||||||
|
pub mod_keys: ModKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
|
||||||
pub struct MouseState {
|
pub struct MouseState {
|
||||||
x: u32,
|
pub position: CanvasPosition,
|
||||||
y: u32,
|
pub mouse_keys: MouseKeys,
|
||||||
mod_keys: ModKeysStorage,
|
|
||||||
mouse_keys: MouseKeysStorage,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseState {
|
impl MouseState {
|
||||||
pub const fn new() -> MouseState {
|
pub fn new() -> MouseState {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_pos(x: u32, y: u32) -> MouseState {
|
||||||
MouseState {
|
MouseState {
|
||||||
x: 0,
|
position: CanvasPosition { x, y },
|
||||||
y: 0,
|
mouse_keys: MouseKeys::default(),
|
||||||
mod_keys: 0,
|
|
||||||
mouse_keys: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const fn from_pos(x: u32, y: u32) -> MouseState {
|
|
||||||
MouseState { x, y, mod_keys: 0, mouse_keys: 0 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
None,
|
UnknownKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ModKeysStorage = u8;
|
bitflags! {
|
||||||
pub type MouseKeysStorage = u8;
|
#[derive(Default)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[repr(transparent)]
|
||||||
#[repr(transparent)]
|
pub struct ModKeys: u8 {
|
||||||
pub struct ModKeys(ModKeysStorage);
|
const CONTROL = 0b0000_0001;
|
||||||
|
const SHIFT = 0b0000_0010;
|
||||||
impl ModKeys {
|
const ALT = 0b0000_0100;
|
||||||
pub fn get_key(&self, key: ModKey) -> bool {
|
|
||||||
key as ModKeysStorage & self.0 > 0
|
|
||||||
}
|
|
||||||
pub fn set_key(&mut self, key: ModKey) {
|
|
||||||
self.0 |= key as ModKeysStorage
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
bitflags! {
|
||||||
#[repr(transparent)]
|
#[derive(Default)]
|
||||||
struct MouseKeys(u8);
|
#[repr(transparent)]
|
||||||
|
pub struct MouseKeys: u8 {
|
||||||
impl MouseKeys {
|
const LEFT = 0b0000_0001;
|
||||||
pub fn get_key(&self, key: MouseKey) -> bool {
|
const RIGHT = 0b0000_0010;
|
||||||
key as ModKeysStorage & self.0 > 0
|
const MIDDLE = 0b0000_0100;
|
||||||
}
|
|
||||||
pub fn set_key(&mut self, key: MouseKey) {
|
|
||||||
self.0 |= key as MouseKeysStorage
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum ModKey {
|
|
||||||
Control = 1,
|
|
||||||
Shift = 2,
|
|
||||||
Alt = 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum MouseKey {
|
|
||||||
LeftMouse = 1,
|
|
||||||
RightMouse = 2,
|
|
||||||
MiddleMouse = 4,
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
pub mod events;
|
pub mod events;
|
||||||
use crate::EditorError;
|
use crate::tools::ToolState;
|
||||||
|
use crate::{Color, EditorError};
|
||||||
use events::{Event, Response};
|
use events::{Event, Response};
|
||||||
|
|
||||||
pub type Callback = Box<dyn Fn(Response)>;
|
pub type Callback = Box<dyn Fn(Response)>;
|
||||||
@@ -8,10 +9,63 @@ pub struct Dispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Dispatcher {
|
impl Dispatcher {
|
||||||
pub fn handle_event(&self, event: Event) -> Result<(), EditorError> {
|
pub fn handle_event(&self, tool_state: &mut ToolState, event: Event) -> Result<(), EditorError> {
|
||||||
match event {
|
match event {
|
||||||
Event::Click(_) => Ok(self.emit_response(Response::UpdateCanvas)),
|
Event::SelectTool(tool_type) => {
|
||||||
_ => todo!(),
|
tool_state.active_tool = tool_type;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Event::SelectPrimaryColor(color) => {
|
||||||
|
tool_state.primary_color = color;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Event::SelectSecondaryColor(color) => {
|
||||||
|
tool_state.secondary_color = color;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Event::SwapColors => {
|
||||||
|
std::mem::swap(&mut tool_state.primary_color, &mut tool_state.secondary_color);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Event::ResetColors => {
|
||||||
|
tool_state.primary_color = Color::BLACK;
|
||||||
|
tool_state.secondary_color = Color::WHITE;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Event::MouseDown(mouse_state) => {
|
||||||
|
tool_state.mouse_state = mouse_state;
|
||||||
|
// the state has changed so we add a trace point
|
||||||
|
tool_state.record_trace_point();
|
||||||
|
|
||||||
|
self.emit_response(Response::UpdateCanvas);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Event::MouseUp(mouse_state) => {
|
||||||
|
tool_state.mouse_state = mouse_state;
|
||||||
|
// the state has changed so we add a trace point
|
||||||
|
tool_state.record_trace_point();
|
||||||
|
|
||||||
|
self.emit_response(Response::UpdateCanvas);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Event::MouseMovement(pos) => {
|
||||||
|
tool_state.mouse_state.position = pos;
|
||||||
|
tool_state.record_trace_point();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Event::ModifierKeyDown(mod_keys) => {
|
||||||
|
tool_state.mod_keys = mod_keys;
|
||||||
|
// the state has changed so we add a trace point
|
||||||
|
tool_state.record_trace_point();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Event::ModifierKeyUp(mod_keys) => {
|
||||||
|
tool_state.mod_keys = mod_keys;
|
||||||
|
// the state has changed so we add a trace point
|
||||||
|
tool_state.record_trace_point();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Event::KeyPress(key) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn emit_response(&self, response: Response) {
|
pub fn emit_response(&self, response: Response) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ use workspace::Workspace;
|
|||||||
|
|
||||||
// TODO: serialize with serde to save the current editor state
|
// TODO: serialize with serde to save the current editor state
|
||||||
pub struct Editor {
|
pub struct Editor {
|
||||||
pub tools: ToolState,
|
tools: ToolState,
|
||||||
workspace: Workspace,
|
workspace: Workspace,
|
||||||
dispatcher: Dispatcher,
|
dispatcher: Dispatcher,
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,6 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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(event)
|
self.dispatcher.handle_event(&mut self.tools, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
use crate::events::{ModKeys, MouseState, TracePoint};
|
||||||
use crate::{events::Trace, Color};
|
use crate::{events::Trace, Color};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct ToolState {
|
pub struct ToolState {
|
||||||
pub mouse_is_clicked: bool,
|
pub mouse_state: MouseState,
|
||||||
|
pub mod_keys: ModKeys,
|
||||||
pub trace: Trace,
|
pub trace: Trace,
|
||||||
pub primary_color: Color,
|
pub primary_color: Color,
|
||||||
pub secondary_color: Color,
|
pub secondary_color: Color,
|
||||||
@@ -10,10 +12,11 @@ pub struct ToolState {
|
|||||||
tool_settings: HashMap<ToolType, ToolSettings>,
|
tool_settings: HashMap<ToolType, ToolSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToolState {
|
impl Default for ToolState {
|
||||||
pub fn new() -> Self {
|
fn default() -> Self {
|
||||||
ToolState {
|
ToolState {
|
||||||
mouse_is_clicked: false,
|
mouse_state: MouseState::default(),
|
||||||
|
mod_keys: ModKeys::default(),
|
||||||
trace: Trace::new(),
|
trace: Trace::new(),
|
||||||
primary_color: Color::BLACK,
|
primary_color: Color::BLACK,
|
||||||
secondary_color: Color::WHITE,
|
secondary_color: Color::WHITE,
|
||||||
@@ -23,14 +26,29 @@ impl ToolState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToolState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn record_trace_point(&mut self) {
|
||||||
|
self.trace.push(TracePoint {
|
||||||
|
mouse_state: self.mouse_state,
|
||||||
|
mod_keys: self.mod_keys,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn default_tool_settings() -> HashMap<ToolType, ToolSettings> {
|
fn default_tool_settings() -> HashMap<ToolType, ToolSettings> {
|
||||||
let tool_init = |tool: &ToolType| (*tool, tool.default_settings());
|
let tool_init = |tool: &ToolType| (*tool, tool.default_settings());
|
||||||
|
// TODO: when 1.51 is more common, change this to use array::IntoIter
|
||||||
[
|
[
|
||||||
tool_init(&ToolType::Select),
|
tool_init(&ToolType::Select),
|
||||||
|
tool_init(&ToolType::Ellipse),
|
||||||
tool_init(&ToolType::Shape), // TODO: Add more tool defaults
|
tool_init(&ToolType::Shape), // TODO: Add more tool defaults
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.copied()
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +72,7 @@ impl ToolType {
|
|||||||
fn default_settings(&self) -> ToolSettings {
|
fn default_settings(&self) -> ToolSettings {
|
||||||
match self {
|
match self {
|
||||||
ToolType::Select => ToolSettings::Select { append_mode: SelectAppendMode::New },
|
ToolType::Select => ToolSettings::Select { append_mode: SelectAppendMode::New },
|
||||||
|
ToolType::Ellipse => ToolSettings::Ellipse,
|
||||||
ToolType::Shape => ToolSettings::Shape {
|
ToolType::Shape => ToolSettings::Shape {
|
||||||
shape: Shape::Polygon { vertices: 3 },
|
shape: Shape::Polygon { vertices: 3 },
|
||||||
},
|
},
|
||||||
@@ -62,13 +81,14 @@ impl ToolType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum ToolSettings {
|
pub enum ToolSettings {
|
||||||
Select { append_mode: SelectAppendMode },
|
Select { append_mode: SelectAppendMode },
|
||||||
|
Ellipse,
|
||||||
Shape { shape: Shape },
|
Shape { shape: Shape },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum SelectAppendMode {
|
pub enum SelectAppendMode {
|
||||||
New,
|
New,
|
||||||
Add,
|
Add,
|
||||||
@@ -76,7 +96,7 @@ pub enum SelectAppendMode {
|
|||||||
Intersect,
|
Intersect,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum Shape {
|
pub enum Shape {
|
||||||
Star { vertices: u32 },
|
Star { vertices: u32 },
|
||||||
Polygon { vertices: u32 },
|
Polygon { vertices: u32 },
|
||||||
|
|||||||
Reference in New Issue
Block a user