Merge pull request 'Make it pretty.' (#69) from feat/themes into master
Reviewed-on: #69
This commit is contained in:
commit
e51ac19a26
14 changed files with 859 additions and 53 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -4,3 +4,6 @@
|
|||
[submodule "lib/steamlocate-rs"]
|
||||
path = lib/steamlocate-rs
|
||||
url = git@github.com:sclu1034/steamlocate-rs.git
|
||||
[submodule "crates/dtmm/assets/icons"]
|
||||
path = crates/dtmm/assets/icons
|
||||
url = https://github.com/tabler/tabler-icons
|
||||
|
|
312
Cargo.lock
generated
312
Cargo.lock
generated
|
@ -44,6 +44,12 @@ version = "1.0.69"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
|
@ -118,6 +124,12 @@ dependencies = [
|
|||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
|
@ -411,6 +423,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "colors-transform"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9226dbc05df4fb986f48d730b001532580883c4c06c5d1c213f4b34c1c157178"
|
||||
|
||||
[[package]]
|
||||
name = "confy"
|
||||
version = "0.5.1"
|
||||
|
@ -580,6 +598,12 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-url"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.6"
|
||||
|
@ -666,11 +690,14 @@ dependencies = [
|
|||
"fnv",
|
||||
"im",
|
||||
"instant",
|
||||
"resvg",
|
||||
"tiny-skia",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"tracing-wasm",
|
||||
"unic-langid",
|
||||
"unicode-segmentation",
|
||||
"usvg",
|
||||
"xi-unicode",
|
||||
]
|
||||
|
||||
|
@ -723,6 +750,7 @@ dependencies = [
|
|||
"bitflags",
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"colors-transform",
|
||||
"confy",
|
||||
"druid",
|
||||
"dtmt-shared",
|
||||
|
@ -911,6 +939,12 @@ dependencies = [
|
|||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "float-cmp"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
||||
|
||||
[[package]]
|
||||
name = "fluent-bundle"
|
||||
version = "0.15.2"
|
||||
|
@ -951,6 +985,27 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "fontconfig-parser"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ab2e12762761366dcb876ab8b6e0cfa4797ddcd890575919f008b5ba655672a"
|
||||
dependencies = [
|
||||
"roxmltree 0.18.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fontdb"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52186a39c335aa6f79fc0bf1c3cf854870b6ad4e50a7bb8a59b4ba1331f478a"
|
||||
dependencies = [
|
||||
"fontconfig-parser",
|
||||
"log",
|
||||
"memmap2",
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
|
@ -1150,6 +1205,16 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.27.2"
|
||||
|
@ -1533,6 +1598,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kurbo"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a53776d271cfb873b17c618af0298445c88afc52837f3e948fa3fafd131f449"
|
||||
dependencies = [
|
||||
"arrayvec 0.7.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kurbo"
|
||||
version = "0.9.1"
|
||||
|
@ -1621,6 +1695,15 @@ version = "2.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
|
@ -2053,6 +2136,12 @@ dependencies = [
|
|||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pico-args"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
|
||||
|
||||
[[package]]
|
||||
name = "piet"
|
||||
version = "0.6.2"
|
||||
|
@ -2060,7 +2149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e381186490a3e2017a506d62b759ea8eaf4be14666b13ed53973e8ae193451b1"
|
||||
dependencies = [
|
||||
"image",
|
||||
"kurbo",
|
||||
"kurbo 0.9.1",
|
||||
"unic-bidi",
|
||||
]
|
||||
|
||||
|
@ -2256,6 +2345,12 @@ dependencies = [
|
|||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rctree"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
|
@ -2302,6 +2397,51 @@ version = "0.6.28"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||
|
||||
[[package]]
|
||||
name = "resvg"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea0337740f86c70141e7596d81c2e76c0cd3726dbcee053ac18d0ec45101f8e"
|
||||
dependencies = [
|
||||
"gif",
|
||||
"jpeg-decoder",
|
||||
"log",
|
||||
"pico-args",
|
||||
"png",
|
||||
"rgb",
|
||||
"svgfilters",
|
||||
"svgtypes",
|
||||
"tiny-skia",
|
||||
"usvg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b9de9831a129b122e7e61f242db509fa9d0838008bf0b29bb0624669edfe48a"
|
||||
dependencies = [
|
||||
"xmlparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8f595a457b6b8c6cda66a48503e92ee8d19342f905948f29c383200ec9eb1d8"
|
||||
dependencies = [
|
||||
"xmlparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
|
@ -2337,6 +2477,22 @@ dependencies = [
|
|||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustybuzz"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab9e34ecf6900625412355a61bda0bd68099fe674de707c67e5e4aed2c05e489"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytemuck",
|
||||
"smallvec",
|
||||
"ttf-parser",
|
||||
"unicode-bidi-mirroring",
|
||||
"unicode-ccc",
|
||||
"unicode-general-category",
|
||||
"unicode-script",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustyline"
|
||||
version = "9.1.2"
|
||||
|
@ -2490,6 +2646,21 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simplecss"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a11be7c62927d9427e9f40f3444d5499d868648e2edbc4e2116de69e7ec0e89d"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
|
||||
|
||||
[[package]]
|
||||
name = "sized-chunks"
|
||||
version = "0.6.5"
|
||||
|
@ -2557,6 +2728,15 @@ version = "1.0.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
|
||||
|
||||
[[package]]
|
||||
name = "strict-num"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9df65f20698aeed245efdde3628a6b559ea1239bbb871af1b6e3b58c413b2bd1"
|
||||
dependencies = [
|
||||
"float-cmp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string_template"
|
||||
version = "0.2.1"
|
||||
|
@ -2587,6 +2767,25 @@ version = "2.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "svgfilters"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "639abcebc15fdc2df179f37d6f5463d660c1c79cd552c12343a4600827a04bce"
|
||||
dependencies = [
|
||||
"float-cmp",
|
||||
"rgb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "svgtypes"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22975e8a2bac6a76bb54f898a6b18764633b00e780330f0b689f65afb3975564"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
|
@ -2692,6 +2891,31 @@ dependencies = [
|
|||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfef3412c6975196fdfac41ef232f910be2bb37b9dd3313a49a1a6bc815a5bdb"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec 0.7.2",
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"png",
|
||||
"tiny-skia-path",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia-path"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4b5edac058fc98f51c935daea4d805b695b38e2f151241cad125ade2a2ac20d"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bytemuck",
|
||||
"strict-num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.1"
|
||||
|
@ -2851,6 +3075,12 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
|
||||
|
||||
[[package]]
|
||||
name = "type-map"
|
||||
version = "0.4.0"
|
||||
|
@ -2950,24 +3180,86 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524b68aca1d05e03fdf03fcdce2c6c94b6daf6d16861ddaa7e4f2b6638a9052c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi-mirroring"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ccc"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-general-category"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-script"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d817255e1bed6dfd4ca47258685d14d2bdcfbc64fdc9e3819bd5848057b8ecc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-vo"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "usvg"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "585bb2d87c8fd6041a479dea01479dcf9094e61b5f9af221606927e61a2bd939"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"data-url",
|
||||
"flate2",
|
||||
"fontdb",
|
||||
"kurbo 0.8.3",
|
||||
"log",
|
||||
"pico-args",
|
||||
"rctree",
|
||||
"roxmltree 0.15.1",
|
||||
"rustybuzz",
|
||||
"simplecss",
|
||||
"siphasher",
|
||||
"strict-num",
|
||||
"svgtypes",
|
||||
"unicode-bidi",
|
||||
"unicode-script",
|
||||
"unicode-vo",
|
||||
"xmlwriter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf16_lit"
|
||||
version = "2.0.2"
|
||||
|
@ -3100,6 +3392,12 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -3245,6 +3543,18 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a"
|
||||
|
||||
[[package]]
|
||||
name = "xmlparser"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd"
|
||||
|
||||
[[package]]
|
||||
name = "xmlwriter"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.4"
|
||||
|
|
|
@ -10,7 +10,7 @@ bitflags = "1.3.2"
|
|||
clap = { version = "4.0.15", features = ["color", "derive", "std", "cargo", "string", "unicode"] }
|
||||
color-eyre = "0.6.2"
|
||||
confy = "0.5.1"
|
||||
druid = { git = "https://github.com/linebender/druid.git", features = ["im", "serde", "image", "png", "jpeg", "bmp", "webp"] }
|
||||
druid = { git = "https://github.com/linebender/druid.git", features = ["im", "serde", "image", "png", "jpeg", "bmp", "webp", "svg"] }
|
||||
dtmt-shared = { path = "../../lib/dtmt-shared", version = "*" }
|
||||
futures = "0.3.25"
|
||||
oodle-sys = { path = "../../lib/oodle-sys", version = "*" }
|
||||
|
@ -27,3 +27,4 @@ path-slash = "0.2.1"
|
|||
time = { version = "0.3.20", features = ["serde", "serde-well-known", "local-offset"] }
|
||||
strip-ansi-escapes = "0.1.1"
|
||||
lazy_static = "1.4.0"
|
||||
colors-transform = "0.2.11"
|
||||
|
|
1
crates/dtmm/assets/icons
Submodule
1
crates/dtmm/assets/icons
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 74838ded9980b6f134bb6f7edcf916cca4a2d97f
|
|
@ -20,6 +20,7 @@ use crate::controller::app::load_mods;
|
|||
use crate::controller::worker::work_thread;
|
||||
use crate::state::ACTION_SHOW_ERROR_DIALOG;
|
||||
use crate::state::{Delegate, State};
|
||||
use crate::ui::theme;
|
||||
|
||||
mod controller;
|
||||
mod state;
|
||||
|
@ -64,7 +65,9 @@ fn main() -> Result<()> {
|
|||
let (action_tx, action_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
let delegate = Delegate::new(action_tx);
|
||||
|
||||
let launcher = AppLauncher::with_window(ui::window::main::new()).delegate(delegate);
|
||||
let launcher = AppLauncher::with_window(ui::window::main::new())
|
||||
.delegate(delegate)
|
||||
.configure_env(theme::set_theme_env);
|
||||
|
||||
let event_sink = launcher.get_external_handle();
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
use druid::{Color, Insets};
|
||||
|
||||
pub const TOP_BAR_BACKGROUND_COLOR: Color = Color::rgba8(255, 255, 255, 50);
|
||||
pub const TOP_BAR_INSETS: Insets = Insets::uniform(5.0);
|
99
crates/dtmm/src/ui/theme/colors.rs
Normal file
99
crates/dtmm/src/ui/theme/colors.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
use colors_transform::Color as _;
|
||||
use colors_transform::Rgb;
|
||||
use druid::Color;
|
||||
|
||||
pub use gruvbox_dark::*;
|
||||
|
||||
macro_rules! make_color {
|
||||
($name:ident, $r:literal, $g:literal, $b:literal, $a:literal) => {
|
||||
pub const $name: Color = Color::rgba8($r, $g, $b, $a);
|
||||
};
|
||||
($name:ident, $r:literal, $g:literal, $b:literal) => {
|
||||
pub const $name: Color = Color::rgb8($r, $g, $b);
|
||||
};
|
||||
($name:ident, $col:expr) => {
|
||||
pub const $name: Color = $col;
|
||||
};
|
||||
}
|
||||
|
||||
make_color!(TOP_BAR_BACKGROUND_COLOR, COLOR_BG1);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub mod gruvbox_dark {
|
||||
use druid::Color;
|
||||
|
||||
make_color!(COLOR_BG0_H, 0x1d, 0x20, 0x21);
|
||||
make_color!(COLOR_BG0_S, 0x32, 0x20, 0x2f);
|
||||
make_color!(COLOR_BG0, 0x28, 0x28, 0x28);
|
||||
make_color!(COLOR_BG1, 0x3c, 0x38, 0x36);
|
||||
make_color!(COLOR_BG2, 0x50, 0x49, 0x45);
|
||||
make_color!(COLOR_BG3, 0x66, 0x5c, 0x54);
|
||||
make_color!(COLOR_BG4, 0x7c, 0x6f, 0x64);
|
||||
|
||||
make_color!(COLOR_FG0, 0xfb, 0xf1, 0xc7);
|
||||
make_color!(COLOR_FG1, 0xeb, 0xdb, 0xb2);
|
||||
make_color!(COLOR_FG2, 0xd5, 0xc4, 0xa1);
|
||||
make_color!(COLOR_FG3, 0xbd, 0xae, 0x93);
|
||||
make_color!(COLOR_FG4, 0xa8, 0x99, 0x84);
|
||||
|
||||
make_color!(COLOR_BG, COLOR_BG0);
|
||||
make_color!(COLOR_GRAY_LIGHT, 0x92, 0x83, 0x74);
|
||||
|
||||
make_color!(COLOR_RED_DARK, 0xcc, 0x24, 0x1d);
|
||||
make_color!(COLOR_RED_LIGHT, 0xfb, 0x49, 0x34);
|
||||
|
||||
make_color!(COLOR_GREEN_DARK, 0x98, 0x97, 0x1a);
|
||||
make_color!(COLOR_GREEN_LIGHT, 0xb8, 0xbb, 0x26);
|
||||
|
||||
make_color!(COLOR_YELLOW_DARK, 0xd7, 0x99, 0x21);
|
||||
make_color!(COLOR_YELLOW_LIGHT, 0xfa, 0xbd, 0x2f);
|
||||
|
||||
make_color!(COLOR_BLUE_DARK, 0x45, 0x85, 0x88);
|
||||
make_color!(COLOR_BLUE_LIGHT, 0x83, 0xa5, 0x98);
|
||||
|
||||
make_color!(COLOR_PURPLE_DARK, 0xb1, 0x26, 0x86);
|
||||
make_color!(COLOR_PURPLE_LIGHT, 0xd3, 0x86, 0x9b);
|
||||
|
||||
make_color!(COLOR_AQUA_DARK, 0x68, 0x9d, 0x6a);
|
||||
make_color!(COLOR_AQUA_LIGHT, 0x8e, 0xc0, 0x7c);
|
||||
|
||||
make_color!(COLOR_GRAY_DARK, 0xa8, 0x99, 0x84);
|
||||
make_color!(COLOR_FG, COLOR_FG1);
|
||||
|
||||
make_color!(COLOR_ORANGE_DARK, 0xd6, 0x5d, 0x0e);
|
||||
make_color!(COLOR_ORANGE_LIGHT, 0xfe, 0x80, 0x19);
|
||||
|
||||
make_color!(COLOR_ACCENT, COLOR_RED_LIGHT);
|
||||
make_color!(COLOR_ACCENT_FG, COLOR_BG0_H);
|
||||
}
|
||||
|
||||
pub trait ColorExt {
|
||||
fn lighten(&self, fac: f32) -> Self;
|
||||
fn darken(&self, fac: f32) -> Self;
|
||||
}
|
||||
|
||||
impl ColorExt for Color {
|
||||
fn lighten(&self, fac: f32) -> Self {
|
||||
let (r, g, b, a) = self.as_rgba();
|
||||
let rgb = Rgb::from(r as f32, g as f32, b as f32);
|
||||
let rgb = rgb.lighten(fac);
|
||||
Self::rgba(
|
||||
rgb.get_red() as f64,
|
||||
rgb.get_green() as f64,
|
||||
rgb.get_blue() as f64,
|
||||
a,
|
||||
)
|
||||
}
|
||||
|
||||
fn darken(&self, fac: f32) -> Self {
|
||||
let (r, g, b, a) = self.as_rgba();
|
||||
let rgb = Rgb::from(r as f32, g as f32, b as f32);
|
||||
let rgb = rgb.lighten(-1. * fac);
|
||||
Self::rgba(
|
||||
rgb.get_red() as f64,
|
||||
rgb.get_green() as f64,
|
||||
rgb.get_blue() as f64,
|
||||
a,
|
||||
)
|
||||
}
|
||||
}
|
1
crates/dtmm/src/ui/theme/icons.rs
Normal file
1
crates/dtmm/src/ui/theme/icons.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub static ALERT_CIRCLE: &str = include_str!("../../../assets/icons/icons/alert-circle.svg");
|
13
crates/dtmm/src/ui/theme/keys.rs
Normal file
13
crates/dtmm/src/ui/theme/keys.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use druid::{Color, Insets, Key};
|
||||
|
||||
pub const KEY_BUTTON_BG: Key<Color> = Key::new("dtmm.button.bg");
|
||||
pub const KEY_BUTTON_BG_HOT: Key<Color> = Key::new("dtmm.button.bg-hot");
|
||||
pub const KEY_BUTTON_BG_ACTIVE: Key<Color> = Key::new("dtmm.button.bg-active");
|
||||
pub const KEY_BUTTON_BG_DISABLED: Key<Color> = Key::new("dtmm.button.bg-disabled");
|
||||
|
||||
pub const KEY_BUTTON_FG: Key<Color> = Key::new("dtmm.button.fg");
|
||||
pub const KEY_BUTTON_FG_DISABLED: Key<Color> = Key::new("dtmm.button.fg-disabled");
|
||||
|
||||
pub const KEY_BUTTON_PADDING: Key<Insets> = Key::new("dtmm.button.padding");
|
||||
|
||||
pub const KEY_MOD_LIST_ITEM_BG_COLOR: Key<Color> = Key::new("dtmm.mod-list.item.background-color");
|
33
crates/dtmm/src/ui/theme/mod.rs
Normal file
33
crates/dtmm/src/ui/theme/mod.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use druid::{Env, Insets};
|
||||
|
||||
use crate::state::State;
|
||||
|
||||
mod colors;
|
||||
pub mod icons;
|
||||
pub mod keys;
|
||||
|
||||
pub use colors::*;
|
||||
|
||||
pub const TOP_BAR_INSETS: Insets = Insets::uniform(5.0);
|
||||
pub const DISABLED_ALPHA: f64 = 0.65;
|
||||
|
||||
pub(crate) fn set_theme_env(env: &mut Env, _: &State) {
|
||||
env.set(druid::theme::TEXT_COLOR, COLOR_FG);
|
||||
env.set(druid::theme::SCROLLBAR_COLOR, COLOR_FG);
|
||||
env.set(druid::theme::BORDER_LIGHT, COLOR_FG);
|
||||
env.set(druid::theme::BUTTON_BORDER_RADIUS, 2.);
|
||||
|
||||
env.set(keys::KEY_BUTTON_BG, COLOR_ACCENT);
|
||||
env.set(keys::KEY_BUTTON_BG_HOT, COLOR_ACCENT.darken(0.03));
|
||||
env.set(keys::KEY_BUTTON_BG_ACTIVE, COLOR_ACCENT.darken(0.1));
|
||||
env.set(
|
||||
keys::KEY_BUTTON_BG_DISABLED,
|
||||
COLOR_ACCENT.with_alpha(DISABLED_ALPHA),
|
||||
);
|
||||
env.set(keys::KEY_BUTTON_FG, COLOR_ACCENT_FG);
|
||||
env.set(
|
||||
keys::KEY_BUTTON_FG_DISABLED,
|
||||
COLOR_ACCENT_FG.with_alpha(DISABLED_ALPHA),
|
||||
);
|
||||
env.set(keys::KEY_BUTTON_PADDING, Insets::uniform_xy(8., 2.));
|
||||
}
|
197
crates/dtmm/src/ui/widget/border.rs
Normal file
197
crates/dtmm/src/ui/widget/border.rs
Normal file
|
@ -0,0 +1,197 @@
|
|||
use druid::kurbo::Line;
|
||||
use druid::widget::prelude::*;
|
||||
use druid::{Color, KeyOrValue, Point, WidgetPod};
|
||||
|
||||
pub struct Border<T> {
|
||||
inner: WidgetPod<T, Box<dyn Widget<T>>>,
|
||||
color: BorderColor,
|
||||
width: BorderWidths,
|
||||
// corner_radius: KeyOrValue<RoundedRectRadii>,
|
||||
}
|
||||
|
||||
impl<T: Data> Border<T> {
|
||||
pub fn new(inner: impl Widget<T> + 'static) -> Self {
|
||||
let inner = WidgetPod::new(inner).boxed();
|
||||
Self {
|
||||
inner,
|
||||
color: Color::TRANSPARENT.into(),
|
||||
width: 0f64.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_color(&mut self, color: impl Into<KeyOrValue<Color>>) {
|
||||
self.color = BorderColor::Uniform(color.into());
|
||||
}
|
||||
|
||||
pub fn with_color(mut self, color: impl Into<KeyOrValue<Color>>) -> Self {
|
||||
self.set_color(color);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_bottom_border(&mut self, width: impl Into<KeyOrValue<f64>>) {
|
||||
self.width.bottom = width.into();
|
||||
}
|
||||
|
||||
pub fn with_bottom_border(mut self, width: impl Into<KeyOrValue<f64>>) -> Self {
|
||||
self.set_bottom_border(width);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_top_border(&mut self, width: impl Into<KeyOrValue<f64>>) {
|
||||
self.width.top = width.into();
|
||||
}
|
||||
|
||||
pub fn with_top_border(mut self, width: impl Into<KeyOrValue<f64>>) -> Self {
|
||||
self.set_top_border(width);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Data> Widget<T> for Border<T> {
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) {
|
||||
self.inner.event(ctx, event, data, env)
|
||||
}
|
||||
|
||||
fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) {
|
||||
self.inner.lifecycle(ctx, event, data, env);
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _: &T, data: &T, env: &Env) {
|
||||
self.inner.update(ctx, data, env);
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size {
|
||||
bc.debug_check("Border");
|
||||
|
||||
let (left, top, right, bottom) = self.width.resolve(env);
|
||||
|
||||
let inner_bc = bc.shrink((left + right, top + bottom));
|
||||
let inner_size = self.inner.layout(ctx, &inner_bc, data, env);
|
||||
|
||||
let origin = Point::new(left, top);
|
||||
self.inner.set_origin(ctx, origin);
|
||||
|
||||
let size = Size::new(
|
||||
inner_size.width + left + right,
|
||||
inner_size.height + top + bottom,
|
||||
);
|
||||
|
||||
let insets = self.inner.compute_parent_paint_insets(size);
|
||||
ctx.set_paint_insets(insets);
|
||||
|
||||
let baseline_offset = self.inner.baseline_offset();
|
||||
if baseline_offset > 0. {
|
||||
ctx.set_baseline_offset(baseline_offset + bottom);
|
||||
}
|
||||
|
||||
size
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
|
||||
let size = ctx.size();
|
||||
let (left, top, right, bottom) = self.width.resolve(env);
|
||||
let (col_left, col_top, col_right, col_bottom) = self.color.resolve(env);
|
||||
|
||||
self.inner.paint(ctx, data, env);
|
||||
|
||||
// There's probably a more elegant way to create the various `Line`s, but this works for now.
|
||||
// The important bit is to move each line inwards by half each side's border width. Otherwise
|
||||
// it would draw hald of the border outside of the widget's boundary.
|
||||
|
||||
if left > 0. {
|
||||
ctx.stroke(
|
||||
Line::new((left / 2., top / 2.), (left / 2., size.height)),
|
||||
&col_left,
|
||||
left,
|
||||
);
|
||||
}
|
||||
|
||||
if top > 0. {
|
||||
ctx.stroke(
|
||||
Line::new((left / 2., top / 2.), (size.width - (right / 2.), top / 2.)),
|
||||
&col_top,
|
||||
top,
|
||||
);
|
||||
}
|
||||
|
||||
if right > 0. {
|
||||
ctx.stroke(
|
||||
Line::new(
|
||||
(size.width - (right / 2.), top / 2.),
|
||||
(size.width - (right / 2.), size.height - (bottom / 2.)),
|
||||
),
|
||||
&col_right,
|
||||
right,
|
||||
);
|
||||
}
|
||||
|
||||
if bottom > 0. {
|
||||
ctx.stroke(
|
||||
Line::new(
|
||||
(left / 2., size.height - (bottom / 2.)),
|
||||
(size.width - (right / 2.), size.height - (bottom / 2.)),
|
||||
),
|
||||
&col_bottom,
|
||||
bottom,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BorderColor {
|
||||
Uniform(KeyOrValue<Color>),
|
||||
// Individual {
|
||||
// left: KeyOrValue<Color>,
|
||||
// top: KeyOrValue<Color>,
|
||||
// right: KeyOrValue<Color>,
|
||||
// bottom: KeyOrValue<Color>,
|
||||
// },
|
||||
}
|
||||
|
||||
impl BorderColor {
|
||||
pub fn resolve(&self, env: &Env) -> (Color, Color, Color, Color) {
|
||||
match self {
|
||||
Self::Uniform(val) => {
|
||||
let color = val.resolve(env);
|
||||
(color, color, color, color)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Color> for BorderColor {
|
||||
fn from(value: Color) -> Self {
|
||||
Self::Uniform(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BorderWidths {
|
||||
pub left: KeyOrValue<f64>,
|
||||
pub top: KeyOrValue<f64>,
|
||||
pub right: KeyOrValue<f64>,
|
||||
pub bottom: KeyOrValue<f64>,
|
||||
}
|
||||
|
||||
impl From<f64> for BorderWidths {
|
||||
fn from(value: f64) -> Self {
|
||||
Self {
|
||||
left: value.into(),
|
||||
top: value.into(),
|
||||
right: value.into(),
|
||||
bottom: value.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BorderWidths {
|
||||
pub fn resolve(&self, env: &Env) -> (f64, f64, f64, f64) {
|
||||
(
|
||||
self.left.resolve(env),
|
||||
self.top.resolve(env),
|
||||
self.right.resolve(env),
|
||||
self.bottom.resolve(env),
|
||||
)
|
||||
}
|
||||
}
|
113
crates/dtmm/src/ui/widget/button.rs
Normal file
113
crates/dtmm/src/ui/widget/button.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use druid::widget::prelude::*;
|
||||
use druid::widget::{Click, ControllerHost, Label, LabelText};
|
||||
use druid::WidgetPod;
|
||||
use druid::{Affine, WidgetExt};
|
||||
|
||||
use crate::ui::theme;
|
||||
|
||||
pub struct Button<T> {
|
||||
inner: WidgetPod<T, Box<dyn Widget<T>>>,
|
||||
inner_size: Size,
|
||||
}
|
||||
|
||||
impl<T: Data> Button<T> {
|
||||
pub fn new(inner: impl Widget<T> + 'static) -> Self {
|
||||
let inner = inner.env_scope(|env, _| {
|
||||
env.set(
|
||||
druid::theme::TEXT_COLOR,
|
||||
env.get(theme::keys::KEY_BUTTON_FG),
|
||||
);
|
||||
env.set(
|
||||
druid::theme::DISABLED_TEXT_COLOR,
|
||||
env.get(theme::keys::KEY_BUTTON_FG_DISABLED),
|
||||
);
|
||||
});
|
||||
let inner = WidgetPod::new(inner).boxed();
|
||||
Self {
|
||||
inner,
|
||||
inner_size: Size::ZERO,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_label(text: impl Into<LabelText<T>>) -> Self {
|
||||
let inner = Label::new(text);
|
||||
Self::new(inner)
|
||||
}
|
||||
|
||||
pub fn on_click(
|
||||
self,
|
||||
f: impl Fn(&mut EventCtx, &mut T, &Env) + 'static,
|
||||
) -> ControllerHost<Self, Click<T>> {
|
||||
ControllerHost::new(self, Click::new(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Data> Widget<T> for Button<T> {
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: &Event, _: &mut T, _: &Env) {
|
||||
match event {
|
||||
Event::MouseDown(_) if !ctx.is_disabled() => {
|
||||
ctx.set_active(true);
|
||||
ctx.request_paint();
|
||||
}
|
||||
Event::MouseUp(_) => {
|
||||
if ctx.is_active() && !ctx.is_disabled() {
|
||||
ctx.request_paint();
|
||||
}
|
||||
ctx.set_active(false);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) {
|
||||
if let LifeCycle::HotChanged(_) | LifeCycle::DisabledChanged(_) = event {
|
||||
ctx.request_paint();
|
||||
}
|
||||
self.inner.lifecycle(ctx, event, data, env);
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _: &T, data: &T, env: &Env) {
|
||||
self.inner.update(ctx, data, env);
|
||||
}
|
||||
|
||||
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size {
|
||||
bc.debug_check("Button");
|
||||
|
||||
let padding = env.get(theme::keys::KEY_BUTTON_PADDING).size();
|
||||
let inner_bc = bc.shrink(padding).loosen();
|
||||
|
||||
self.inner_size = self.inner.layout(ctx, &inner_bc, data, env);
|
||||
|
||||
bc.constrain(Size::new(
|
||||
self.inner_size.width + padding.width,
|
||||
self.inner_size.height + padding.height,
|
||||
))
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
|
||||
let size = ctx.size();
|
||||
|
||||
let bg_color = if ctx.is_disabled() {
|
||||
env.get(theme::keys::KEY_BUTTON_BG_DISABLED)
|
||||
} else if ctx.is_hot() {
|
||||
env.get(theme::keys::KEY_BUTTON_BG_HOT)
|
||||
} else if ctx.is_active() {
|
||||
env.get(theme::keys::KEY_BUTTON_BG_ACTIVE)
|
||||
} else {
|
||||
env.get(theme::keys::KEY_BUTTON_BG)
|
||||
};
|
||||
|
||||
ctx.fill(
|
||||
size.to_rect()
|
||||
.to_rounded_rect(env.get(druid::theme::BUTTON_BORDER_RADIUS)),
|
||||
&bg_color,
|
||||
);
|
||||
|
||||
let inner_pos = (size.to_vec2() - self.inner_size.to_vec2()) / 2.;
|
||||
|
||||
ctx.with_save(|ctx| {
|
||||
ctx.transform(Affine::translate(inner_pos));
|
||||
self.inner.paint(ctx, data, env);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ use std::sync::Arc;
|
|||
use druid::text::Formatter;
|
||||
use druid::{Data, Widget};
|
||||
|
||||
pub mod border;
|
||||
pub mod button;
|
||||
pub mod controller;
|
||||
|
||||
pub trait ExtraWidgetExt<T: Data>: Widget<T> + Sized + 'static {}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use druid::im::Vector;
|
||||
use druid::widget::{
|
||||
Button, Checkbox, CrossAxisAlignment, Flex, Image, Label, LineBreaking, List,
|
||||
MainAxisAlignment, Maybe, Scroll, SizedBox, Split, TextBox, ViewSwitcher,
|
||||
Checkbox, CrossAxisAlignment, Either, Flex, Image, Label, LineBreaking, List,
|
||||
MainAxisAlignment, Maybe, Scroll, SizedBox, Split, Svg, SvgData, TextBox, ViewSwitcher,
|
||||
};
|
||||
use druid::{lens, Data, ImageBuf, LifeCycleCtx};
|
||||
use druid::{
|
||||
Color, FileDialogOptions, FileSpec, FontDescriptor, FontFamily, Key, LensExt, SingleUse,
|
||||
Widget, WidgetExt, WindowDesc, WindowId,
|
||||
Color, FileDialogOptions, FileSpec, FontDescriptor, FontFamily, LensExt, SingleUse, Widget,
|
||||
WidgetExt, WindowDesc, WindowId,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
|
@ -17,7 +18,9 @@ use crate::state::{
|
|||
ACTION_SELECT_MOD, ACTION_SET_WINDOW_HANDLE, ACTION_START_DELETE_SELECTED_MOD,
|
||||
ACTION_START_DEPLOY, ACTION_START_RESET_DEPLOYMENT,
|
||||
};
|
||||
use crate::ui::theme;
|
||||
use crate::ui::theme::{self, ColorExt};
|
||||
use crate::ui::widget::border::Border;
|
||||
use crate::ui::widget::button::Button;
|
||||
use crate::ui::widget::controller::{
|
||||
AutoScrollController, DirtyStateController, ImageLensController,
|
||||
};
|
||||
|
@ -31,8 +34,6 @@ const TITLE: &str = "Darktide Mod Manager";
|
|||
const WINDOW_SIZE: (f64, f64) = (1080., 720.);
|
||||
const MOD_DETAILS_MIN_WIDTH: f64 = 325.;
|
||||
|
||||
const KEY_MOD_LIST_ITEM_BG_COLOR: Key<Color> = Key::new("dtmm.mod-list.item.background-color");
|
||||
|
||||
pub(crate) fn new() -> WindowDesc<State> {
|
||||
WindowDesc::new(build_window())
|
||||
.title(TITLE)
|
||||
|
@ -40,35 +41,40 @@ pub(crate) fn new() -> WindowDesc<State> {
|
|||
}
|
||||
|
||||
fn build_top_bar() -> impl Widget<State> {
|
||||
let mods_button = Button::new("Mods")
|
||||
let mods_button = Button::with_label("Mods")
|
||||
.on_click(|_ctx, state: &mut State, _env| state.current_view = View::Mods);
|
||||
|
||||
let settings_button = Button::new("Settings").on_click(|_ctx, state: &mut State, _env| {
|
||||
let settings_button =
|
||||
Button::with_label("Settings").on_click(|_ctx, state: &mut State, _env| {
|
||||
state.current_view = View::Settings;
|
||||
});
|
||||
|
||||
let deploy_button = {
|
||||
Button::dynamic(|state: &State, _| {
|
||||
let mut s = String::new();
|
||||
if state.dirty {
|
||||
s.push_str("! ");
|
||||
}
|
||||
s.push_str("Deploy Mods");
|
||||
s
|
||||
})
|
||||
let icon = Svg::new(SvgData::from_str(theme::icons::ALERT_CIRCLE).expect("invalid SVG"))
|
||||
.fix_height(druid::theme::TEXT_SIZE_NORMAL);
|
||||
|
||||
let inner = Either::new(
|
||||
|state: &State, _| state.dirty,
|
||||
Flex::row()
|
||||
.with_child(icon)
|
||||
.with_spacer(3.)
|
||||
.with_child(Label::new("Deploy Mods")),
|
||||
Label::new("Deploy Mods"),
|
||||
);
|
||||
Button::new(inner)
|
||||
.on_click(|ctx, _state: &mut State, _env| {
|
||||
ctx.submit_command(ACTION_START_DEPLOY);
|
||||
})
|
||||
.disabled_if(|data, _| data.is_deployment_in_progress || data.is_reset_in_progress)
|
||||
};
|
||||
|
||||
let reset_button = Button::new("Reset Game")
|
||||
let reset_button = Button::with_label("Reset Game")
|
||||
.on_click(|ctx, _state: &mut State, _env| {
|
||||
ctx.submit_command(ACTION_START_RESET_DEPLOYMENT);
|
||||
})
|
||||
.disabled_if(|data, _| data.is_deployment_in_progress || data.is_reset_in_progress);
|
||||
|
||||
Flex::row()
|
||||
let bar = Flex::row()
|
||||
.must_fill_main_axis(true)
|
||||
.main_axis_alignment(MainAxisAlignment::SpaceBetween)
|
||||
.with_child(
|
||||
|
@ -84,14 +90,29 @@ fn build_top_bar() -> impl Widget<State> {
|
|||
.with_child(reset_button),
|
||||
)
|
||||
.padding(theme::TOP_BAR_INSETS)
|
||||
.background(theme::TOP_BAR_BACKGROUND_COLOR)
|
||||
// TODO: Add bottom border. Need a custom widget for that, as the built-in only provides
|
||||
// uniform borders on all sides
|
||||
.background(theme::TOP_BAR_BACKGROUND_COLOR);
|
||||
|
||||
Border::new(bar)
|
||||
.with_color(theme::COLOR_FG2)
|
||||
.with_bottom_border(1.)
|
||||
}
|
||||
|
||||
fn build_mod_list() -> impl Widget<State> {
|
||||
let list = List::new(|| {
|
||||
let checkbox = Checkbox::new("")
|
||||
.env_scope(|env, selected| {
|
||||
env.set(druid::theme::BORDER_DARK, theme::COLOR_BG3);
|
||||
env.set(druid::theme::BORDER_LIGHT, theme::COLOR_BG3);
|
||||
env.set(druid::theme::TEXT_COLOR, theme::COLOR_ACCENT_FG);
|
||||
|
||||
if *selected {
|
||||
env.set(druid::theme::BACKGROUND_DARK, theme::COLOR_ACCENT);
|
||||
env.set(druid::theme::BACKGROUND_LIGHT, theme::COLOR_ACCENT);
|
||||
} else {
|
||||
env.set(druid::theme::BACKGROUND_DARK, Color::TRANSPARENT);
|
||||
env.set(druid::theme::BACKGROUND_LIGHT, Color::TRANSPARENT);
|
||||
}
|
||||
})
|
||||
.lens(lens!((usize, Arc<ModInfo>, bool), 1).then(ModInfo::enabled.in_arc()));
|
||||
|
||||
let name =
|
||||
|
@ -102,15 +123,23 @@ fn build_mod_list() -> impl Widget<State> {
|
|||
.with_child(checkbox)
|
||||
.with_child(name)
|
||||
.padding((5.0, 4.0))
|
||||
.background(KEY_MOD_LIST_ITEM_BG_COLOR)
|
||||
.background(theme::keys::KEY_MOD_LIST_ITEM_BG_COLOR)
|
||||
.on_click(|ctx, (i, _, _), _env| ctx.submit_command(ACTION_SELECT_MOD.with(*i)))
|
||||
.env_scope(|env, (i, _, selected)| {
|
||||
if *selected {
|
||||
env.set(KEY_MOD_LIST_ITEM_BG_COLOR, Color::NAVY);
|
||||
} else if (i % 2) == 1 {
|
||||
env.set(KEY_MOD_LIST_ITEM_BG_COLOR, Color::WHITE.with_alpha(0.05));
|
||||
env.set(theme::keys::KEY_MOD_LIST_ITEM_BG_COLOR, theme::COLOR_ACCENT);
|
||||
env.set(
|
||||
druid::theme::TEXT_COLOR,
|
||||
theme::COLOR_ACCENT_FG.darken(0.05),
|
||||
);
|
||||
} else {
|
||||
env.set(KEY_MOD_LIST_ITEM_BG_COLOR, Color::TRANSPARENT);
|
||||
env.set(druid::theme::TEXT_COLOR, theme::COLOR_FG);
|
||||
|
||||
if (i % 2) == 1 {
|
||||
env.set(theme::keys::KEY_MOD_LIST_ITEM_BG_COLOR, theme::COLOR_BG1);
|
||||
} else {
|
||||
env.set(theme::keys::KEY_MOD_LIST_ITEM_BG_COLOR, theme::COLOR_BG);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -140,35 +169,36 @@ fn build_mod_list() -> impl Widget<State> {
|
|||
}
|
||||
|
||||
fn build_mod_details_buttons() -> impl Widget<State> {
|
||||
let button_move_up = Button::new("Move Up")
|
||||
let button_move_up = Button::with_label("Move Up")
|
||||
.on_click(|ctx, _state, _env| ctx.submit_command(ACTION_SELECTED_MOD_UP))
|
||||
.disabled_if(|state: &State, _env: &druid::Env| !state.can_move_mod_up());
|
||||
|
||||
let button_move_down = Button::new("Move Down")
|
||||
let button_move_down = Button::with_label("Move Down")
|
||||
.on_click(|ctx, _state, _env| ctx.submit_command(ACTION_SELECTED_MOD_DOWN))
|
||||
.disabled_if(|state: &State, _env: &druid::Env| !state.can_move_mod_down());
|
||||
|
||||
let button_toggle_mod = Maybe::new(
|
||||
|| {
|
||||
Button::dynamic(|enabled, _env| {
|
||||
let inner = Label::dynamic(|enabled, _env| {
|
||||
if *enabled {
|
||||
"Disable Mod".into()
|
||||
} else {
|
||||
"Enable Mod".into()
|
||||
}
|
||||
})
|
||||
});
|
||||
Button::new(inner)
|
||||
.on_click(|_ctx, enabled: &mut bool, _env| {
|
||||
*enabled = !(*enabled);
|
||||
})
|
||||
.lens(ModInfo::enabled.in_arc())
|
||||
},
|
||||
// TODO: Gray out
|
||||
|| Button::new("Enable Mod"),
|
||||
|| Button::with_label("Enable Mod"),
|
||||
)
|
||||
.disabled_if(|info: &Option<Arc<ModInfo>>, _env: &druid::Env| info.is_none())
|
||||
.lens(State::selected_mod);
|
||||
|
||||
let button_add_mod = Button::new("Add Mod").on_click(|ctx, _state: &mut State, _env| {
|
||||
let button_add_mod = Button::with_label("Add Mod").on_click(|ctx, _state: &mut State, _env| {
|
||||
let zip = FileSpec::new("Zip file", &["zip"]);
|
||||
let opts = FileDialogOptions::new()
|
||||
.allowed_types(vec![zip])
|
||||
|
@ -179,7 +209,7 @@ fn build_mod_details_buttons() -> impl Widget<State> {
|
|||
ctx.submit_command(druid::commands::SHOW_OPEN_PANEL.with(opts))
|
||||
});
|
||||
|
||||
let button_delete_mod = Button::new("Delete Mod")
|
||||
let button_delete_mod = Button::with_label("Delete Mod")
|
||||
.on_click(|ctx, data: &mut Option<Arc<ModInfo>>, _env| {
|
||||
if let Some(info) = data {
|
||||
ctx.submit_command(
|
||||
|
@ -288,7 +318,7 @@ fn build_mod_details() -> impl Widget<State> {
|
|||
.cross_axis_alignment(CrossAxisAlignment::Start)
|
||||
.main_axis_alignment(MainAxisAlignment::SpaceBetween)
|
||||
.with_flex_child(build_mod_details_info(), 1.0)
|
||||
.with_child(build_mod_details_buttons().padding(4.))
|
||||
.with_child(build_mod_details_buttons().padding((4., 4., 4., 8.)))
|
||||
}
|
||||
|
||||
fn build_view_mods() -> impl Widget<State> {
|
||||
|
@ -363,7 +393,11 @@ fn build_log_view() -> impl Widget<State> {
|
|||
.vertical()
|
||||
.controller(AutoScrollController);
|
||||
|
||||
SizedBox::new(label).expand_width().height(128.0)
|
||||
let inner = Border::new(label)
|
||||
.with_color(theme::COLOR_FG2)
|
||||
.with_top_border(1.);
|
||||
|
||||
SizedBox::new(inner).expand_width().height(128.0)
|
||||
}
|
||||
|
||||
fn build_window() -> impl Widget<State> {
|
||||
|
|
Loading…
Add table
Reference in a new issue