From 4c33741b037e0c38fbe63507ade1c030606dfe00 Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Tue, 14 Mar 2023 17:25:09 +0100 Subject: [PATCH 1/3] feat(dtmm): Implement gruvbox dark theme --- .gitmodules | 3 + Cargo.lock | 312 +++++++++++++++++++++++++++- crates/dtmm/Cargo.toml | 3 +- crates/dtmm/assets/icons | 1 + crates/dtmm/src/main.rs | 5 +- crates/dtmm/src/ui/theme.rs | 4 - crates/dtmm/src/ui/theme/colors.rs | 99 +++++++++ crates/dtmm/src/ui/theme/icons.rs | 1 + crates/dtmm/src/ui/theme/keys.rs | 13 ++ crates/dtmm/src/ui/theme/mod.rs | 30 +++ crates/dtmm/src/ui/widget/button.rs | 113 ++++++++++ crates/dtmm/src/ui/widget/mod.rs | 1 + crates/dtmm/src/ui/window/main.rs | 88 ++++---- 13 files changed, 627 insertions(+), 46 deletions(-) create mode 160000 crates/dtmm/assets/icons delete mode 100644 crates/dtmm/src/ui/theme.rs create mode 100644 crates/dtmm/src/ui/theme/colors.rs create mode 100644 crates/dtmm/src/ui/theme/icons.rs create mode 100644 crates/dtmm/src/ui/theme/keys.rs create mode 100644 crates/dtmm/src/ui/theme/mod.rs create mode 100644 crates/dtmm/src/ui/widget/button.rs diff --git a/.gitmodules b/.gitmodules index 5741e15..1c9c3c2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/Cargo.lock b/Cargo.lock index dfce5a3..a029489 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/crates/dtmm/Cargo.toml b/crates/dtmm/Cargo.toml index 05db4e0..2265229 100644 --- a/crates/dtmm/Cargo.toml +++ b/crates/dtmm/Cargo.toml @@ -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" diff --git a/crates/dtmm/assets/icons b/crates/dtmm/assets/icons new file mode 160000 index 0000000..74838de --- /dev/null +++ b/crates/dtmm/assets/icons @@ -0,0 +1 @@ +Subproject commit 74838ded9980b6f134bb6f7edcf916cca4a2d97f diff --git a/crates/dtmm/src/main.rs b/crates/dtmm/src/main.rs index c3b8cb5..ce8c67f 100644 --- a/crates/dtmm/src/main.rs +++ b/crates/dtmm/src/main.rs @@ -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(); diff --git a/crates/dtmm/src/ui/theme.rs b/crates/dtmm/src/ui/theme.rs deleted file mode 100644 index 7658f3f..0000000 --- a/crates/dtmm/src/ui/theme.rs +++ /dev/null @@ -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); diff --git a/crates/dtmm/src/ui/theme/colors.rs b/crates/dtmm/src/ui/theme/colors.rs new file mode 100644 index 0000000..cc86781 --- /dev/null +++ b/crates/dtmm/src/ui/theme/colors.rs @@ -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, + ) + } +} diff --git a/crates/dtmm/src/ui/theme/icons.rs b/crates/dtmm/src/ui/theme/icons.rs new file mode 100644 index 0000000..a947871 --- /dev/null +++ b/crates/dtmm/src/ui/theme/icons.rs @@ -0,0 +1 @@ +pub static ALERT_CIRCLE: &str = include_str!("../../../assets/icons/icons/alert-circle.svg"); diff --git a/crates/dtmm/src/ui/theme/keys.rs b/crates/dtmm/src/ui/theme/keys.rs new file mode 100644 index 0000000..9d4120b --- /dev/null +++ b/crates/dtmm/src/ui/theme/keys.rs @@ -0,0 +1,13 @@ +use druid::{Color, Insets, Key}; + +pub const KEY_BUTTON_BG: Key = Key::new("dtmm.button.bg"); +pub const KEY_BUTTON_BG_HOT: Key = Key::new("dtmm.button.bg-hot"); +pub const KEY_BUTTON_BG_ACTIVE: Key = Key::new("dtmm.button.bg-active"); +pub const KEY_BUTTON_BG_DISABLED: Key = Key::new("dtmm.button.bg-disabled"); + +pub const KEY_BUTTON_FG: Key = Key::new("dtmm.button.fg"); +pub const KEY_BUTTON_FG_DISABLED: Key = Key::new("dtmm.button.fg-disabled"); + +pub const KEY_BUTTON_PADDING: Key = Key::new("dtmm.button.padding"); + +pub const KEY_MOD_LIST_ITEM_BG_COLOR: Key = Key::new("dtmm.mod-list.item.background-color"); diff --git a/crates/dtmm/src/ui/theme/mod.rs b/crates/dtmm/src/ui/theme/mod.rs new file mode 100644 index 0000000..45a7c3a --- /dev/null +++ b/crates/dtmm/src/ui/theme/mod.rs @@ -0,0 +1,30 @@ +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::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.)); +} diff --git a/crates/dtmm/src/ui/widget/button.rs b/crates/dtmm/src/ui/widget/button.rs new file mode 100644 index 0000000..08e1dec --- /dev/null +++ b/crates/dtmm/src/ui/widget/button.rs @@ -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 { + inner: WidgetPod>>, + inner_size: Size, +} + +impl Button { + pub fn new(inner: impl Widget + '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>) -> Self { + let inner = Label::new(text); + Self::new(inner) + } + + pub fn on_click( + self, + f: impl Fn(&mut EventCtx, &mut T, &Env) + 'static, + ) -> ControllerHost> { + ControllerHost::new(self, Click::new(f)) + } +} + +impl Widget for Button { + 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); + }); + } +} diff --git a/crates/dtmm/src/ui/widget/mod.rs b/crates/dtmm/src/ui/widget/mod.rs index ebb634e..3c8c08c 100644 --- a/crates/dtmm/src/ui/widget/mod.rs +++ b/crates/dtmm/src/ui/widget/mod.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use druid::text::Formatter; use druid::{Data, Widget}; +pub mod button; pub mod controller; pub trait ExtraWidgetExt: Widget + Sized + 'static {} diff --git a/crates/dtmm/src/ui/window/main.rs b/crates/dtmm/src/ui/window/main.rs index 2b5d42f..4a72f02 100644 --- a/crates/dtmm/src/ui/window/main.rs +++ b/crates/dtmm/src/ui/window/main.rs @@ -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; @@ -18,6 +19,7 @@ use crate::state::{ ACTION_START_DEPLOY, ACTION_START_RESET_DEPLOYMENT, }; use crate::ui::theme; +use crate::ui::widget::button::Button; use crate::ui::widget::controller::{ AutoScrollController, DirtyStateController, ImageLensController, }; @@ -31,8 +33,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 = Key::new("dtmm.mod-list.item.background-color"); - pub(crate) fn new() -> WindowDesc { WindowDesc::new(build_window()) .title(TITLE) @@ -40,29 +40,34 @@ pub(crate) fn new() -> WindowDesc { } fn build_top_bar() -> impl Widget { - 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| { - state.current_view = View::Settings; - }); + 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 - }) - .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 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(1.) + .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); }) @@ -102,15 +107,19 @@ fn build_mod_list() -> impl Widget { .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); } 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, Color::TRANSPARENT); + } } }) }); @@ -140,35 +149,36 @@ fn build_mod_list() -> impl Widget { } fn build_mod_details_buttons() -> impl Widget { - 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() } - }) - .on_click(|_ctx, enabled: &mut bool, _env| { - *enabled = !(*enabled); - }) - .lens(ModInfo::enabled.in_arc()) + }); + 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>, _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 +189,7 @@ fn build_mod_details_buttons() -> impl Widget { 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>, _env| { if let Some(info) = data { ctx.submit_command( -- 2.45.3 From c38909db22d163d9a8a1539286de560c2d63a9a6 Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Wed, 15 Mar 2023 16:24:08 +0100 Subject: [PATCH 2/3] feat(dtmm): Add section borders This implements a new container widget that allows separate widths and colors for each border side. --- crates/dtmm/src/ui/theme/mod.rs | 3 + crates/dtmm/src/ui/widget/border.rs | 197 ++++++++++++++++++++++++++++ crates/dtmm/src/ui/widget/mod.rs | 1 + crates/dtmm/src/ui/window/main.rs | 42 ++++-- 4 files changed, 234 insertions(+), 9 deletions(-) create mode 100644 crates/dtmm/src/ui/widget/border.rs diff --git a/crates/dtmm/src/ui/theme/mod.rs b/crates/dtmm/src/ui/theme/mod.rs index 45a7c3a..7f93524 100644 --- a/crates/dtmm/src/ui/theme/mod.rs +++ b/crates/dtmm/src/ui/theme/mod.rs @@ -13,7 +13,10 @@ 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)); diff --git a/crates/dtmm/src/ui/widget/border.rs b/crates/dtmm/src/ui/widget/border.rs new file mode 100644 index 0000000..2ca7cdb --- /dev/null +++ b/crates/dtmm/src/ui/widget/border.rs @@ -0,0 +1,197 @@ +use druid::kurbo::Line; +use druid::widget::prelude::*; +use druid::{Color, KeyOrValue, Point, WidgetPod}; + +pub struct Border { + inner: WidgetPod>>, + color: BorderColor, + width: BorderWidths, + // corner_radius: KeyOrValue, +} + +impl Border { + pub fn new(inner: impl Widget + '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>) { + self.color = BorderColor::Uniform(color.into()); + } + + pub fn with_color(mut self, color: impl Into>) -> Self { + self.set_color(color); + self + } + + pub fn set_bottom_border(&mut self, width: impl Into>) { + self.width.bottom = width.into(); + } + + pub fn with_bottom_border(mut self, width: impl Into>) -> Self { + self.set_bottom_border(width); + self + } + + pub fn set_top_border(&mut self, width: impl Into>) { + self.width.top = width.into(); + } + + pub fn with_top_border(mut self, width: impl Into>) -> Self { + self.set_top_border(width); + self + } +} + +impl Widget for Border { + 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), + // Individual { + // left: KeyOrValue, + // top: KeyOrValue, + // right: KeyOrValue, + // bottom: KeyOrValue, + // }, +} + +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 for BorderColor { + fn from(value: Color) -> Self { + Self::Uniform(value.into()) + } +} + +#[derive(Clone, Debug)] +pub struct BorderWidths { + pub left: KeyOrValue, + pub top: KeyOrValue, + pub right: KeyOrValue, + pub bottom: KeyOrValue, +} + +impl From 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), + ) + } +} diff --git a/crates/dtmm/src/ui/widget/mod.rs b/crates/dtmm/src/ui/widget/mod.rs index 3c8c08c..05c91c7 100644 --- a/crates/dtmm/src/ui/widget/mod.rs +++ b/crates/dtmm/src/ui/widget/mod.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use druid::text::Formatter; use druid::{Data, Widget}; +pub mod border; pub mod button; pub mod controller; diff --git a/crates/dtmm/src/ui/window/main.rs b/crates/dtmm/src/ui/window/main.rs index 4a72f02..8fe62d4 100644 --- a/crates/dtmm/src/ui/window/main.rs +++ b/crates/dtmm/src/ui/window/main.rs @@ -18,7 +18,8 @@ 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, @@ -73,7 +74,7 @@ fn build_top_bar() -> impl Widget { }) .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( @@ -89,14 +90,29 @@ fn build_top_bar() -> impl Widget { .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 { 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, bool), 1).then(ModInfo::enabled.in_arc())); let name = @@ -112,13 +128,17 @@ fn build_mod_list() -> impl Widget { .env_scope(|env, (i, _, selected)| { if *selected { env.set(theme::keys::KEY_MOD_LIST_ITEM_BG_COLOR, theme::COLOR_ACCENT); - env.set(druid::theme::TEXT_COLOR, theme::COLOR_ACCENT_FG); + env.set( + druid::theme::TEXT_COLOR, + theme::COLOR_ACCENT_FG.darken(0.05), + ); } else { 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, Color::TRANSPARENT); + env.set(theme::keys::KEY_MOD_LIST_ITEM_BG_COLOR, theme::COLOR_BG); } } }) @@ -298,7 +318,7 @@ fn build_mod_details() -> impl Widget { .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 { @@ -373,7 +393,11 @@ fn build_log_view() -> impl Widget { .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 { -- 2.45.3 From 01f1e1724af29d944d9d13686ec2a01b0d9ff2ec Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Wed, 15 Mar 2023 16:45:13 +0100 Subject: [PATCH 3/3] feat(dtmm): Adjust icon spacing --- crates/dtmm/src/ui/window/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/dtmm/src/ui/window/main.rs b/crates/dtmm/src/ui/window/main.rs index 8fe62d4..d4244fe 100644 --- a/crates/dtmm/src/ui/window/main.rs +++ b/crates/dtmm/src/ui/window/main.rs @@ -57,7 +57,7 @@ fn build_top_bar() -> impl Widget { |state: &State, _| state.dirty, Flex::row() .with_child(icon) - .with_spacer(1.) + .with_spacer(3.) .with_child(Label::new("Deploy Mods")), Label::new("Deploy Mods"), ); -- 2.45.3