Initial stage for arbitrary tool support

This commit is contained in:
Enrico Lumetti 2020-11-25 01:11:03 +01:00
parent f42db5fb69
commit c72ac1cde3
10 changed files with 513 additions and 67 deletions

310
Cargo.lock generated
View File

@ -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"

View File

@ -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"

1
icons/eraser.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 122.88 103.38" style="enable-background:new 0 0 122.88 103.38" xml:space="preserve"><style type="text/css">.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#f0f0f0;}</style><g><path class="st0" stroke="#f0f0f0" d="M27.66,93.53h32.49l9.1-9.08c1.4-1.4,1.41-3.7,0.01-5.1l-27.02-27.1c-1.4-1.4-3.7-1.41-5.1-0.01L14.3,75.03 c-1.41,1.4-1.41,3.7-0.01,5.1L27.66,93.53L27.66,93.53z M71.03,93.53h51.84v9.85H61.16H50.28h-12.8H25.7h-0.35L1.05,79.01 c-1.4-1.4-1.4-3.7,0.01-5.1L74.11,1.05c1.41-1.4,3.7-1.4,5.1,0.01l39.62,39.72c1.4,1.4,1.4,3.7-0.01,5.1L71.03,93.53L71.03,93.53z"/></g></svg>

After

Width:  |  Height:  |  Size: 749 B

1
icons/pen.svg Normal file
View File

@ -0,0 +1 @@
<svg height="21" viewBox="0 0 21 21" width="21" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke="#f0f0f0" stroke-linecap="round" stroke-linejoin="round" transform="translate(2 2)"><path d="m8.24920737-.79402796c1.17157287 0 2.12132033.94974747 2.12132033 2.12132034v13.43502882l-2.12132033 3.5355339-2.08147546-3.495689-.03442539-13.47488064c-.00298547-1.16857977.94191541-2.11832105 2.11049518-2.12130651.00180188-.00000461.00360378-.00000691.00540567-.00000691z" transform="matrix(.70710678 .70710678 -.70710678 .70710678 8.605553 -3.271644)"/><path d="m13.5 4.5 1 1"/></g></svg>

After

Width:  |  Height:  |  Size: 611 B

View File

@ -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<canvas::CanvasElement>,

View File

@ -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<CanvasState> {
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<CanvasToolIconState>,
current_tool: usize,
tool_ctx: CanvasToolCtx,
}
fn build_ui() -> impl Widget<StilettoState> {
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<CanvasState> {
)
}));
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<CanvasState> {
.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<CanvasState> for Delegate {
impl AppDelegate<StilettoState> 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<CanvasState> 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<CanvasState> for Delegate {
let res_snapshot: Result<DocumentSnapshot, serde_json::Error> =
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<CanvasState> 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
}
}

62
src/tool.rs Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
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,
}
}
}

View File

@ -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::*;

5
src/widget/mod.rs Normal file
View File

@ -0,0 +1,5 @@
pub mod canvas;
pub mod tool_icon;
pub use canvas::*;
pub use tool_icon::*;

74
src/widget/tool_icon.rs Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
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::<SvgData>()
.unwrap(),
CanvasToolParams::Eraser => include_str!("../../icons/eraser.svg")
.parse::<SvgData>()
.unwrap(),
}
}
}
pub fn build_simple_tool_widget(
width: f64,
height: f64,
padding: f64,
) -> ViewSwitcher<CanvasToolIconState, (CanvasToolType, bool)> {
ViewSwitcher::<CanvasToolIconState, (CanvasToolType, bool)>::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,
),
)
},
)
}