diff --git a/Cargo.lock b/Cargo.lock
index 48b2189..abe61a2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,5 +1,11 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
+[[package]]
+name = "adler"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
+
[[package]]
name = "anyhow"
version = "1.0.34"
@@ -61,6 +67,12 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
+[[package]]
+name = "base64"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
+
[[package]]
name = "bitflags"
version = "1.2.1"
@@ -127,9 +139,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.62"
+version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40"
+checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
[[package]]
name = "cfg-if"
@@ -143,6 +155,15 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+[[package]]
+name = "cmake"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855"
+dependencies = [
+ "cc",
+]
+
[[package]]
name = "cocoa"
version = "0.20.2"
@@ -214,6 +235,24 @@ dependencies = [
"libc",
]
+[[package]]
+name = "crc32fast"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
+[[package]]
+name = "data-url"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d33fe99ccedd6e84bc035f1931bb2e6be79739d6242bd895e7311c886c50dc9c"
+dependencies = [
+ "matches",
+]
+
[[package]]
name = "direct2d"
version = "0.2.0"
@@ -257,7 +296,7 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "druid"
version = "0.6.0"
-source = "git+https://github.com/doppioandante/druid?branch=stylus_events_0.6.0#b0f9dc0268409a56b5066f569ad245e5df016166"
+source = "git+https://github.com/doppioandante/druid?branch=v0.6.0_stiletto#f8f8a566b77795cfa10caf7f2861f9240d159e90"
dependencies = [
"console_log",
"druid-derive",
@@ -272,13 +311,14 @@ dependencies = [
"simple_logger",
"unic-langid",
"unicode-segmentation",
+ "usvg",
"xi-unicode",
]
[[package]]
name = "druid-derive"
version = "0.3.1"
-source = "git+https://github.com/doppioandante/druid?branch=stylus_events_0.6.0#b0f9dc0268409a56b5066f569ad245e5df016166"
+source = "git+https://github.com/doppioandante/druid?branch=v0.6.0_stiletto#f8f8a566b77795cfa10caf7f2861f9240d159e90"
dependencies = [
"proc-macro2",
"quote",
@@ -288,7 +328,7 @@ dependencies = [
[[package]]
name = "druid-shell"
version = "0.6.0"
-source = "git+https://github.com/doppioandante/druid?branch=stylus_events_0.6.0#b0f9dc0268409a56b5066f569ad245e5df016166"
+source = "git+https://github.com/doppioandante/druid?branch=v0.6.0_stiletto#f8f8a566b77795cfa10caf7f2861f9240d159e90"
dependencies = [
"anyhow",
"bitflags",
@@ -336,6 +376,24 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+[[package]]
+name = "flate2"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crc32fast",
+ "libc",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "float-cmp"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75224bec9bfe1a65e2d34132933f2de7fe79900c96a0174307554244ece8150e"
+
[[package]]
name = "fluent-bundle"
version = "0.12.0"
@@ -387,6 +445,27 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+[[package]]
+name = "freetype"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b73222ab32d9ad65fe0e1c3258da8d614fd47cf19fce92b09eb520060c5c5ad5"
+dependencies = [
+ "freetype-sys",
+ "libc",
+]
+
+[[package]]
+name = "freetype-sys"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d48ac0ce366dd47a115ec8e598d7c51b4a974fc52ded5e53a56b31f55f34f3ea"
+dependencies = [
+ "cmake",
+ "libc",
+ "pkg-config",
+]
+
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
@@ -395,24 +474,24 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "futures-channel"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0448174b01148032eed37ac4aed28963aaaa8cfa93569a08e5b479bbc6c2c151"
+checksum = "4b7109687aa4e177ef6fe84553af6280ef2778bdb7783ba44c9dc3399110fe64"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18eaa56102984bed2c88ea39026cff3ce3b4c7f508ca970cedf2450ea10d4e46"
+checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748"
[[package]]
name = "futures-executor"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5f8e0c9258abaea85e78ebdda17ef9666d390e987f006be6080dfe354b708cb"
+checksum = "4caa2b2b68b880003057c1dd49f1ed937e38f22fcf6c212188a121f08cf40a65"
dependencies = [
"futures-core",
"futures-task",
@@ -421,15 +500,15 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e1798854a4727ff944a7b12aa999f58ce7aa81db80d2dfaaf2ba06f065ddd2b"
+checksum = "611834ce18aaa1bd13c4b374f5d653e1027cf99b6b502584ff8c9a64413b30bb"
[[package]]
name = "futures-macro"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e36fccf3fc58563b4a14d265027c627c3b665d7fed489427e88e7cc929559efe"
+checksum = "77408a692f1f97bcc61dc001d752e00643408fbc922e4d634c655df50d595556"
dependencies = [
"proc-macro-hack",
"proc-macro2",
@@ -439,18 +518,18 @@ dependencies = [
[[package]]
name = "futures-task"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96d502af37186c4fef99453df03e374683f8a1eec9dcc1e66b3b82dc8278ce3c"
+checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d"
dependencies = [
"once_cell",
]
[[package]]
name = "futures-util"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abcb44342f62e6f3e8ac427b8aa815f724fd705dfad060b18ac7866c15bb8e34"
+checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2"
dependencies = [
"futures-core",
"futures-macro",
@@ -650,6 +729,30 @@ dependencies = [
"pkg-config",
]
+[[package]]
+name = "harfbuzz-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "845f3e65ec4e30b0b1b6e1c055900871f3776d3492cc76744e3fc5943a6129a9"
+dependencies = [
+ "cc",
+ "core-graphics",
+ "core-text",
+ "foreign-types",
+ "freetype",
+ "pkg-config",
+]
+
+[[package]]
+name = "harfbuzz_rs"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5bba81dd6b356135f0b31c42447e49d45116adc2e02910070947a322c423aa5"
+dependencies = [
+ "bitflags",
+ "harfbuzz-sys",
+]
+
[[package]]
name = "hermit-abi"
version = "0.1.17"
@@ -675,9 +778,9 @@ dependencies = [
[[package]]
name = "instant"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613"
+checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
@@ -759,6 +862,31 @@ dependencies = [
"libc",
]
+[[package]]
+name = "matches"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
+
+[[package]]
+name = "memmap2"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b70ca2a6103ac8b665dc150b142ef0e4e89df640c9e6cf295d189c3caebe5a"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
+dependencies = [
+ "adler",
+ "autocfg",
+]
+
[[package]]
name = "num"
version = "0.1.42"
@@ -848,9 +976,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.4.1"
+version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad"
+checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "pango"
@@ -962,18 +1090,18 @@ dependencies = [
[[package]]
name = "pin-project"
-version = "1.0.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee41d838744f60d959d7074e3afb6b35c7456d0f61cad38a24e35e6553f73841"
+checksum = "9ccc2237c2c489783abd8c4c80e5450fc0e98644555b1364da68cc29aa151ca7"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
-version = "1.0.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86"
+checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f"
dependencies = [
"proc-macro2",
"quote",
@@ -1065,6 +1193,12 @@ dependencies = [
"rand_core 0.5.1",
]
+[[package]]
+name = "rctree"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be9e29cb19c8fe84169fcb07f8f11e66bc9e6e0280efd4715c54818296f8a4a8"
+
[[package]]
name = "rdrand"
version = "0.4.0"
@@ -1095,6 +1229,15 @@ dependencies = [
"syn",
]
+[[package]]
+name = "roxmltree"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5001f134077069d87f77c8b9452b690df2445f7a43f1c7ca4a1af8dd505789d"
+dependencies = [
+ "xmlparser",
+]
+
[[package]]
name = "rustc-serialize"
version = "0.3.24"
@@ -1179,6 +1322,21 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "simplecss"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "596554e63596d556a0dbd681416342ca61c75f1a45203201e7e77d3fa2fa9014"
+dependencies = [
+ "log",
+]
+
+[[package]]
+name = "siphasher"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
+
[[package]]
name = "sized-chunks"
version = "0.6.2"
@@ -1197,9 +1355,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "smallvec"
-version = "1.4.2"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
+checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85"
[[package]]
name = "stable_deref_trait"
@@ -1209,9 +1367,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "standback"
-version = "0.2.11"
+version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4e0831040d2cf2bdfd51b844be71885783d489898a192f254ae25d57cce725c"
+checksum = "cf906c8b8fc3f6ecd1046e01da1d8ddec83e48c8b08b84dcc02b585a6bedf5a8"
dependencies = [
"version_check",
]
@@ -1280,10 +1438,20 @@ dependencies = [
]
[[package]]
-name = "syn"
-version = "1.0.48"
+name = "svgtypes"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
+checksum = "9c536faaff1a10837cfe373142583f6e27d81e96beba339147e77b67c9f260ff"
+dependencies = [
+ "float-cmp",
+ "siphasher",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "443b4178719c5a851e1bde36ce12da21d74a0e60b4d982ec3385a933c812f0f6"
dependencies = [
"proc-macro2",
"quote",
@@ -1292,9 +1460,9 @@ dependencies = [
[[package]]
name = "time"
-version = "0.2.22"
+version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55b7151c9065e80917fbf285d9a5d1432f60db41d170ccafc749a136b41a93af"
+checksum = "bcdaeea317915d59b2b4cd3b5efcd156c309108664277793f5351700c02ce98b"
dependencies = [
"const_fn",
"libc",
@@ -1334,6 +1502,12 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29738eedb4388d9ea620eeab9384884fc3f06f586a2eddb56bedc5885126c7c1"
+[[package]]
+name = "ttf-parser"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc"
+
[[package]]
name = "type-map"
version = "0.3.0"
@@ -1368,10 +1542,31 @@ dependencies = [
]
[[package]]
-name = "unicode-segmentation"
-version = "1.6.0"
+name = "unicode-bidi"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
+dependencies = [
+ "matches",
+]
+
+[[package]]
+name = "unicode-script"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79bf4d5fc96546fdb73f9827097810bbda93b11a6770ff3a54e1f445d4135787"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db8716a166f290ff49dabc18b44aa407cb7c6dbe1aa0971b44b8a24b0ca35aae"
+
+[[package]]
+name = "unicode-vo"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
[[package]]
name = "unicode-xid"
@@ -1379,6 +1574,31 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+[[package]]
+name = "usvg"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d98fe4bbd8cfe811fb84dabebd670d26b1e633ecb4d3a4ef3a4b8c10252448d"
+dependencies = [
+ "base64",
+ "data-url",
+ "flate2",
+ "harfbuzz_rs",
+ "kurbo",
+ "log",
+ "memmap2",
+ "rctree",
+ "roxmltree",
+ "simplecss",
+ "siphasher",
+ "svgtypes",
+ "ttf-parser",
+ "unicode-bidi",
+ "unicode-script",
+ "unicode-vo",
+ "xmlwriter",
+]
+
[[package]]
name = "version_check"
version = "0.9.2"
@@ -1485,3 +1705,15 @@ name = "xi-unicode"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e71b85d8b1b8bfaf4b5c834187554d201a8cd621c2bbfa33efd41a3ecabd48b2"
+
+[[package]]
+name = "xmlparser"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
+
+[[package]]
+name = "xmlwriter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
diff --git a/Cargo.toml b/Cargo.toml
index dc2905d..6ca75fc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,14 +6,14 @@ edition = "2018"
[dependencies]
log = "0.4"
-druid = { version = "0.6.0", features = ["im"] }
+druid = { version = "0.6.0", features = ["im", "svg"] }
im = { version = "*" }
serde = { version = "1.0", features = ["derive"] }
#serde_bare = "0.3.0"
serde_json = "1.0"
[patch.crates-io]
-druid = { git = "https://github.com/doppioandante/druid", branch = "stylus_events_0.6.0", features = ["im"] }
+druid = { git = "https://github.com/doppioandante/druid", branch = "v0.6.0_stiletto", features = ["im", "svg"] }
[dependencies.gtk]
version = "0.8.1"
diff --git a/icons/eraser.svg b/icons/eraser.svg
new file mode 100644
index 0000000..c49dd42
--- /dev/null
+++ b/icons/eraser.svg
@@ -0,0 +1 @@
+
diff --git a/icons/pen.svg b/icons/pen.svg
new file mode 100644
index 0000000..7ef6b16
--- /dev/null
+++ b/icons/pen.svg
@@ -0,0 +1 @@
+
diff --git a/src/lib.rs b/src/lib.rs
index a9e355d..2e325ab 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,8 +19,15 @@ use std::vec::Vec;
pub mod canvas;
pub mod history;
+pub mod tool;
pub mod widget;
+pub mod commands {
+ use druid::Selector;
+
+ pub const UPDATE_TOOL: Selector = Selector::new("stiletto_update_tool");
+}
+
#[derive(Serialize, Deserialize, Debug)]
pub struct DocumentSnapshot {
pub canvas_elements: Vec,
diff --git a/src/main.rs b/src/main.rs
index d23821f..7f5d697 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -19,14 +19,19 @@ use log::{info, warn};
use druid::commands;
use druid::im::vector;
use druid::widget::prelude::*;
-use druid::widget::{Align, Button, CrossAxisAlignment, Flex, SizedBox};
+use druid::widget::{
+ Align, Button, CrossAxisAlignment, Flex, List, ListGrowDirection, SizedBox, WidgetExt,
+};
use druid::{
- AppDelegate, AppLauncher, Command, DelegateCtx, Env, FileDialogOptions, FileSpec,
- LocalizedString, Target, WindowDesc,
+ AppDelegate, AppLauncher, Color, Command, Data, DelegateCtx, Env, FileDialogOptions, FileSpec,
+ Lens, LocalizedString, Target, WindowDesc,
};
+use im::Vector;
+
use stiletto::history::VersionedCanvas;
-use stiletto::widget::{CanvasState, CanvasWidget};
+use stiletto::tool::{CanvasToolCtx, CanvasToolParams};
+use stiletto::widget::{build_simple_tool_widget, CanvasState, CanvasToolIconState, CanvasWidget};
use stiletto::DocumentSnapshot;
pub fn main() {
@@ -35,9 +40,28 @@ pub fn main() {
.title(
LocalizedString::new("custom-widget-demo-window-title").with_placeholder("Stiletto"),
);
- let canvas_data = CanvasState {
- current_element: None,
- elements: VersionedCanvas::new(vector![]),
+
+ let default_pen_params = CanvasToolParams::Pen {
+ thickness: 2.0,
+ color: Color::rgb(0, 0, 0),
+ };
+ let canvas_data = StilettoState {
+ canvas: CanvasState {
+ current_element: None,
+ elements: VersionedCanvas::new(vector![]),
+ },
+ tool_icons: vector![
+ CanvasToolIconState {
+ tool_params: default_pen_params.clone(),
+ selected: true,
+ },
+ CanvasToolIconState {
+ tool_params: CanvasToolParams::Eraser,
+ selected: false,
+ }
+ ],
+ current_tool: 0,
+ tool_ctx: CanvasToolCtx::new(default_pen_params.clone()),
};
AppLauncher::with_window(window)
.use_simple_logger()
@@ -46,16 +70,23 @@ pub fn main() {
.expect("launch failed");
}
-fn build_ui() -> impl Widget {
- let history_buttons =
- Flex::row()
- .cross_axis_alignment(CrossAxisAlignment::Center)
- .with_child(Button::new("Undo").on_click(
- |_ctx: &mut EventCtx, data: &mut CanvasState, _env: &Env| data.perform_undo(),
- ))
- .with_child(Button::new("Redo").on_click(
- |_ctx: &mut EventCtx, data: &mut CanvasState, _env: &Env| data.perform_redo(),
- ));
+#[derive(Clone, Data, Lens)]
+struct StilettoState {
+ canvas: CanvasState,
+ tool_icons: Vector,
+ current_tool: usize,
+ tool_ctx: CanvasToolCtx,
+}
+
+fn build_ui() -> impl Widget {
+ let history_buttons = Flex::row()
+ .cross_axis_alignment(CrossAxisAlignment::Center)
+ .with_child(Button::new("Undo").on_click(
+ |_ctx: &mut EventCtx, data: &mut StilettoState, _env: &Env| data.canvas.perform_undo(),
+ ))
+ .with_child(Button::new("Redo").on_click(
+ |_ctx: &mut EventCtx, data: &mut StilettoState, _env: &Env| data.canvas.perform_redo(),
+ ));
let stlt = FileSpec::new("Stiletto notebook", &["stlt"]);
let save_dialog_options = FileDialogOptions::new()
@@ -84,10 +115,29 @@ fn build_ui() -> impl Widget {
)
}));
+ let tool_buttons = Flex::row()
+ .cross_axis_alignment(CrossAxisAlignment::Center)
+ .with_flex_child(
+ List::new(|| {
+ build_simple_tool_widget(30.0, 30.0, 5.0)
+ .padding((8.0, 0.0))
+ .on_click(|ctx, tool_state, _| {
+ tool_state.selected = true;
+ ctx.submit_command(stiletto::commands::UPDATE_TOOL, None);
+ })
+ })
+ .grow(ListGrowDirection::Right)
+ .lens(StilettoState::tool_icons),
+ 1.0,
+ );
+
let toolbar = Flex::row()
.cross_axis_alignment(CrossAxisAlignment::Center)
.with_spacer(30.0)
.with_flex_child(Align::left(history_buttons), 1.0)
+ .with_spacer(10.0)
+ .with_flex_child(Align::left(tool_buttons), 2.0)
+ .with_spacer(20.0)
.with_flex_child(Align::right(save_buttons), 1.0)
.with_spacer(30.0);
@@ -95,18 +145,18 @@ fn build_ui() -> impl Widget {
.cross_axis_alignment(CrossAxisAlignment::Center)
.must_fill_main_axis(true)
.with_child(SizedBox::new(Align::left(toolbar)).height(50.0))
- .with_flex_child(CanvasWidget {}, 1.0)
+ .with_flex_child((CanvasWidget {}).lens(StilettoState::canvas), 1.0)
}
struct Delegate;
-impl AppDelegate for Delegate {
+impl AppDelegate for Delegate {
fn command(
&mut self,
_ctx: &mut DelegateCtx,
_target: Target,
cmd: &Command,
- data: &mut CanvasState,
+ data: &mut StilettoState,
_env: &Env,
) -> bool {
use std::fs::File;
@@ -114,7 +164,8 @@ impl AppDelegate for Delegate {
if let Some(Some(file_info)) = cmd.get(commands::SAVE_FILE) {
let res_file = File::create(file_info.path());
if let Ok(f) = res_file {
- let write_res = serde_json::to_writer_pretty(f, &data.get_document_snapshot());
+ let write_res =
+ serde_json::to_writer_pretty(f, &data.canvas.get_document_snapshot());
if write_res.is_err() {
warn!("Error while saving: {:?}", write_res.err());
} else {
@@ -130,7 +181,7 @@ impl AppDelegate for Delegate {
let res_snapshot: Result =
serde_json::from_reader(f);
if let Ok(document_snapshot) = res_snapshot {
- data.set_from_snapshot(document_snapshot);
+ data.canvas.set_from_snapshot(document_snapshot);
info!("Loaded file {}", file_info.path().display());
} else {
warn!("didn't work: {:?}", res_snapshot.err());
@@ -138,6 +189,19 @@ impl AppDelegate for Delegate {
}
return true;
}
+ if let Some(_) = cmd.get(stiletto::commands::UPDATE_TOOL) {
+ let old_tool = data.current_tool;
+ if let Some(new_tool) = data
+ .tool_icons
+ .iter()
+ .enumerate()
+ .position(|(pos, x)| pos != old_tool && x.selected)
+ {
+ info!("Changing active tool to: tool #{}", new_tool);
+ data.tool_icons.get_mut(old_tool).unwrap().selected = false;
+ data.current_tool = new_tool;
+ }
+ }
false
}
}
diff --git a/src/tool.rs b/src/tool.rs
new file mode 100644
index 0000000..24925fd
--- /dev/null
+++ b/src/tool.rs
@@ -0,0 +1,62 @@
+// Stiletto
+// Copyright (C) 2020 Stiletto Authors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+use druid::{Color, Data};
+
+use crate::canvas::CanvasElement;
+use crate::history::VersionedCanvas;
+
+#[derive(Clone, Data)]
+pub enum CanvasToolParams {
+ Pen { thickness: f64, color: Color },
+ Eraser,
+}
+
+#[derive(Clone, PartialEq)]
+pub enum CanvasToolType {
+ Pen,
+ Eraser,
+}
+
+#[derive(Clone, Data)]
+pub enum CanvasToolState {
+ Idle,
+ DrawingFreehand { current_path: CanvasElement },
+}
+
+#[derive(Clone, Data)]
+pub struct CanvasToolCtx {
+ initial_params: CanvasToolParams,
+ state: CanvasToolState,
+}
+
+impl CanvasToolParams {
+ pub fn tool_type(&self) -> CanvasToolType {
+ match self {
+ CanvasToolParams::Pen { .. } => CanvasToolType::Pen,
+ CanvasToolParams::Eraser => CanvasToolType::Eraser,
+ }
+ }
+}
+
+impl CanvasToolCtx {
+ pub fn new(params: CanvasToolParams) -> Self {
+ CanvasToolCtx {
+ initial_params: params,
+ state: CanvasToolState::Idle,
+ }
+ }
+}
diff --git a/src/widget.rs b/src/widget/canvas.rs
similarity index 97%
rename from src/widget.rs
rename to src/widget/canvas.rs
index 180eca1..8053029 100644
--- a/src/widget.rs
+++ b/src/widget/canvas.rs
@@ -16,10 +16,10 @@
use im::Vector;
-use super::canvas;
-use super::canvas::{Canvas, CanvasElement};
-use super::history::VersionedCanvas;
-use super::DocumentSnapshot;
+use crate::canvas;
+use crate::canvas::{Canvas, CanvasElement};
+use crate::history::VersionedCanvas;
+use crate::DocumentSnapshot;
use druid::kurbo::BezPath;
use druid::widget::prelude::*;
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
new file mode 100644
index 0000000..5d05f31
--- /dev/null
+++ b/src/widget/mod.rs
@@ -0,0 +1,5 @@
+pub mod canvas;
+pub mod tool_icon;
+
+pub use canvas::*;
+pub use tool_icon::*;
diff --git a/src/widget/tool_icon.rs b/src/widget/tool_icon.rs
new file mode 100644
index 0000000..b9b4a0c
--- /dev/null
+++ b/src/widget/tool_icon.rs
@@ -0,0 +1,74 @@
+// Stiletto
+// Copyright (C) 2020 Stiletto Authors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+use druid::widget::{Container, SizedBox, Svg, SvgData, ViewSwitcher, WidgetExt};
+use druid::{Color, Data, UnitPoint};
+
+use crate::tool::{CanvasToolParams, CanvasToolType};
+
+#[derive(Clone, Data)]
+pub struct CanvasToolIconState {
+ pub tool_params: CanvasToolParams,
+ pub selected: bool,
+}
+
+impl CanvasToolIconState {
+ fn tool_type(&self) -> CanvasToolType {
+ self.tool_params.tool_type()
+ }
+
+ fn svg_data(&self) -> SvgData {
+ match self.tool_params {
+ CanvasToolParams::Pen { .. } => include_str!("../../icons/pen.svg")
+ .parse::()
+ .unwrap(),
+ CanvasToolParams::Eraser => include_str!("../../icons/eraser.svg")
+ .parse::()
+ .unwrap(),
+ }
+ }
+}
+
+pub fn build_simple_tool_widget(
+ width: f64,
+ height: f64,
+ padding: f64,
+) -> ViewSwitcher {
+ ViewSwitcher::::new(
+ |tool_state, _| (tool_state.tool_type(), tool_state.selected),
+ move |_, tool_state, _| {
+ Box::new(
+ Container::new(
+ SizedBox::new(
+ Svg::new(tool_state.svg_data())
+ .align_horizontal(UnitPoint::CENTER)
+ .fix_width(width)
+ .fix_height(height),
+ )
+ .padding(padding),
+ )
+ .border(
+ if tool_state.selected {
+ Color::rgb(10, 10, 10)
+ } else {
+ Color::BLACK
+ },
+ 1.0,
+ ),
+ )
+ },
+ )
+}