From 77f5d5c7ce2996d15cf5dc0eba6f9a486452155a Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 11 Nov 2022 23:56:48 -0500 Subject: [PATCH 01/39] added dependency check for rg --- check_licenses.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/check_licenses.sh b/check_licenses.sh index c02b162..099ee23 100755 --- a/check_licenses.sh +++ b/check_licenses.sh @@ -1,4 +1,12 @@ #!/bin/sh -# Depends on: `rg` (ripgrep) -! rg --multiline --files-without-match --glob '*.rs' --pcre2 '(?/dev/null 2>&1; then + printf "%s: Missing dependency: rg(1)\n" "$0" 1>&2 + exit 71 # sysexits(3) EX_OSERR +else + rg --multiline --files-without-match --glob '*.rs' --pcre2 \ + '(? Date: Fri, 11 Nov 2022 23:59:40 -0500 Subject: [PATCH 02/39] exit code --- check_licenses.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check_licenses.sh b/check_licenses.sh index 099ee23..b0b9d32 100755 --- a/check_licenses.sh +++ b/check_licenses.sh @@ -5,7 +5,7 @@ set -e # check if we have rg(1) if ! command -v rg >/dev/null 2>&1; then printf "%s: Missing dependency: rg(1)\n" "$0" 1>&2 - exit 71 # sysexits(3) EX_OSERR + exit 69 # sysexits(3) EX_UNAVAILABLE else rg --multiline --files-without-match --glob '*.rs' --pcre2 \ '(? Date: Sat, 12 Nov 2022 01:22:37 -0500 Subject: [PATCH 03/39] usage --- check_licenses.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/check_licenses.sh b/check_licenses.sh index b0b9d32..3dada87 100755 --- a/check_licenses.sh +++ b/check_licenses.sh @@ -2,11 +2,17 @@ set -e +# check usage +if ! test -n "$1"; then + printf "Usage: %s [path...]\n" "$0" 1>&2 + exit 64 # sysexits(3) EX_USAGE +fi + # check if we have rg(1) if ! command -v rg >/dev/null 2>&1; then printf "%s: Missing dependency: rg(1)\n" "$0" 1>&2 exit 69 # sysexits(3) EX_UNAVAILABLE else - rg --multiline --files-without-match --glob '*.rs' --pcre2 \ + rg --multiline --files-without-match --glob "$1" --pcre2 \ '(? Date: Sat, 12 Nov 2022 01:29:09 -0500 Subject: [PATCH 04/39] file, not path --- check_licenses.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check_licenses.sh b/check_licenses.sh index 3dada87..a23408c 100755 --- a/check_licenses.sh +++ b/check_licenses.sh @@ -4,7 +4,7 @@ set -e # check usage if ! test -n "$1"; then - printf "Usage: %s [path...]\n" "$0" 1>&2 + printf "Usage: %s [file...]\n" "$0" 1>&2 exit 64 # sysexits(3) EX_USAGE fi From 31d8bb1fd6ce44013887bfe9c61d75127a787f68 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 12 Nov 2022 03:11:20 -0500 Subject: [PATCH 05/39] portability B) --- "\\" | 26 ++++++++++++++++++++++++++ check_licenses.sh | 12 +++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 "\\" diff --git "a/\\" "b/\\" new file mode 100644 index 0000000..5250114 --- /dev/null +++ "b/\\" @@ -0,0 +1,26 @@ +#!/bin/sh + +set -e + +# check usage +if ! test -n "$1"; then + printf "Usage: %s [file...]\n" "$0" 1>&2 + exit 64 # sysexits(3) EX_USAGE +fi + +# check if we have rg(1); if not, use find(1) and sed(1) instead +if ! command -v rg >/dev/null 2>&1; then + files="$(find "$PWD" -name "$1")" + for file in $files; do + if ! test -n \ + "$(sed -n \ + '\|Copyright\|p' \ + <"$file")" + then + ! test "$file" = "$1" && printf "%s\n" "$file" + fi + done +else + rg --multiline --files-without-match --glob "$1" --pcre2 \ + '(?/dev/null 2>&1; then - printf "%s: Missing dependency: rg(1)\n" "$0" 1>&2 - exit 69 # sysexits(3) EX_UNAVAILABLE + files="$(find "$PWD" -name "$1")" + for file in $files; do + if ! test -n \ + "$(sed -n '\|// SPDX-License-Identifier: .*|p' <"$file")" + then + ! test "$file" = "$1" && printf "%s\n" "$file" + fi + done else rg --multiline --files-without-match --glob "$1" --pcre2 \ '(? Date: Sat, 12 Nov 2022 03:17:40 -0500 Subject: [PATCH 06/39] pattern, not file --- "\\" | 26 -------------------------- check_licenses.sh | 2 +- 2 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 "\\" diff --git "a/\\" "b/\\" deleted file mode 100644 index 5250114..0000000 --- "a/\\" +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -set -e - -# check usage -if ! test -n "$1"; then - printf "Usage: %s [file...]\n" "$0" 1>&2 - exit 64 # sysexits(3) EX_USAGE -fi - -# check if we have rg(1); if not, use find(1) and sed(1) instead -if ! command -v rg >/dev/null 2>&1; then - files="$(find "$PWD" -name "$1")" - for file in $files; do - if ! test -n \ - "$(sed -n \ - '\|Copyright\|p' \ - <"$file")" - then - ! test "$file" = "$1" && printf "%s\n" "$file" - fi - done -else - rg --multiline --files-without-match --glob "$1" --pcre2 \ - '(?&2 + printf "Usage: %s [pattern...]\n" "$0" 1>&2 exit 64 # sysexits(3) EX_USAGE fi From 5670793f90b4c0637fad7587dec3a12ebf9d125d Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 16 Nov 2022 00:50:39 -0500 Subject: [PATCH 07/39] checks for license information parity between Cargo.toml and source files --- check_licenses.sh | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/check_licenses.sh b/check_licenses.sh index 7eac853..5e7caa8 100755 --- a/check_licenses.sh +++ b/check_licenses.sh @@ -2,23 +2,30 @@ set -e -# check usage -if ! test -n "$1"; then - printf "Usage: %s [pattern...]\n" "$0" 1>&2 - exit 64 # sysexits(3) EX_USAGE +# check if we have tomcat(1) +if ! command -v tomcat >/dev/null 2>&1; then + printf "%s: Missing dependency: tomcat(1)\n" + exit 69 # sysexits(3) EX_UNAVAILABLE fi -# check if we have rg(1); if not, use find(1) and sed(1) instead -if ! command -v rg >/dev/null 2>&1; then - files="$(find "$PWD" -name "$1")" - for file in $files; do - if ! test -n \ - "$(sed -n '\|// SPDX-License-Identifier: .*|p' <"$file")" +for toml in $(find "$PWD" -name "Cargo.toml"); do + printf "Project: %s\n" "$(tomcat package.name "$toml")" + for file in $(find "$(printf "%s\n" "$toml" | sed 's/Cargo\.toml/src/g')" -name "*.rs"); do + info="$(head -n 2 "$file")" + toml_lic="$(tomcat package.license "$toml")" + if ! test -n "$toml_lic"; then + printf "%s: Missing license information\n" "$toml" + continue 2 + fi + if ! [ "$toml_lic" = "$(printf "%s\n" "$info" | tail -n 1 |\ + sed -n 's/\/\/ SPDX-License-Identifier: //p')" ] then - ! test "$file" = "$1" && printf "%s\n" "$file" + printf "%s: Missing or malformed license information\n" "$file" + fi + if ! test -n "$(printf "%s\n" "$info" | head -n 1 |\ + sed -n '/\/\/ Copyright (c) .\+/p')" + then + printf "%s: Missing or malformed copyright holder information\n" "$file" fi done -else - rg --multiline --files-without-match --glob "$1" --pcre2 \ - '(? Date: Wed, 16 Nov 2022 01:25:08 -0500 Subject: [PATCH 08/39] clipped absolute paths --- check_licenses.sh | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/check_licenses.sh b/check_licenses.sh index 5e7caa8..aad8cd3 100755 --- a/check_licenses.sh +++ b/check_licenses.sh @@ -8,24 +8,31 @@ if ! command -v tomcat >/dev/null 2>&1; then exit 69 # sysexits(3) EX_UNAVAILABLE fi +dir="$(pwd | sed 's/\//\n/g' | tail -n 1)" + for toml in $(find "$PWD" -name "Cargo.toml"); do printf "Project: %s\n" "$(tomcat package.name "$toml")" - for file in $(find "$(printf "%s\n" "$toml" | sed 's/Cargo\.toml/src/g')" -name "*.rs"); do + for file in $(find "$(printf "%s\n" "$toml" |\ + sed 's/Cargo\.toml/src/g')" -name "*.rs") + do info="$(head -n 2 "$file")" toml_lic="$(tomcat package.license "$toml")" if ! test -n "$toml_lic"; then - printf "%s: Missing license information\n" "$toml" + printf "%s: Missing license information\n" "$(printf "%s\n" "$toml" |\ + sed "s/^.\+$dir\///g")" continue 2 fi if ! [ "$toml_lic" = "$(printf "%s\n" "$info" | tail -n 1 |\ sed -n 's/\/\/ SPDX-License-Identifier: //p')" ] then - printf "%s: Missing or malformed license information\n" "$file" + printf "%s: Missing or malformed license information\n" \ + "$(printf "%s\n" "$file" | sed "s/^.\+$dir\///g")" fi if ! test -n "$(printf "%s\n" "$info" | head -n 1 |\ sed -n '/\/\/ Copyright (c) .\+/p')" then - printf "%s: Missing or malformed copyright holder information\n" "$file" + printf "%s: Missing or malformed copyright holder information\n" \ + "$(printf "%s\n" "$file" | sed "s/^.\+$dir\///g")" fi done done From 2aadd0d57ae72b1d1cd84dd3b5d8df3ed6d2e382 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 12:43:10 -0700 Subject: [PATCH 09/39] Make Color alpha functions const --- crates/script/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index c2ada0e..58c0266 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -173,13 +173,13 @@ impl Color { ) } - pub fn alpha_multiply(&self, mul: u8) -> Self { + pub const fn alpha_multiply(&self, mul: u8) -> Self { let a = self.0 as u8 as u16; let multiplied = ((a * (mul as u16)) >> 8) as u8; self.with_alpha(multiplied) } - pub fn with_alpha(&self, alpha: u8) -> Self { + pub const fn with_alpha(&self, alpha: u8) -> Self { Self(self.0 & 0xffffff00 | alpha as u32) } From f33100cfa8cede12cc3542f751ea01093259e89a Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 12:43:23 -0700 Subject: [PATCH 10/39] Add SAO UI style module --- scripts/sao-ui/src/lib.rs | 1 + scripts/sao-ui/src/style.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 scripts/sao-ui/src/style.rs diff --git a/scripts/sao-ui/src/lib.rs b/scripts/sao-ui/src/lib.rs index b558d3f..3293e8e 100644 --- a/scripts/sao-ui/src/lib.rs +++ b/scripts/sao-ui/src/lib.rs @@ -7,6 +7,7 @@ static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; pub mod anim; pub mod main_menu; pub mod music_player; +pub mod style; pub mod widgets; use api::*; diff --git a/scripts/sao-ui/src/style.rs b/scripts/sao-ui/src/style.rs new file mode 100644 index 0000000..9318ae9 --- /dev/null +++ b/scripts/sao-ui/src/style.rs @@ -0,0 +1,28 @@ +use canary_script::Color; + +/// A reusable set of colors. Used by default widget styles. +pub struct Palette { + pub base: Color, + pub surface: Color, + pub overlay: Color, + pub text: Color, +} + +/// Sword Art Online color palette. +pub const SAO_PALETTE: Palette = Palette { + base: Color::WHITE.with_alpha(0xc0), + surface: Color::WHITE, + overlay: Color::WHITE, + text: Color::BLACK, +}; + +/// Rose Pine color palette. +pub const ROSE_PINE_PALETTE: Palette = Palette { + base: Color(0x191724ff), + surface: Color(0x1f1d2eff), + overlay: Color(0x26233aff), + text: Color(0xe0def4ff), +}; + +/// The global palette. +pub const PALETTE: Palette = ROSE_PINE_PALETTE; From 218e2fde741a520548ee3c5a3a56ab188b2d61a8 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 13:07:37 -0700 Subject: [PATCH 11/39] Add wip-dialog protocol to display ConfirmationDialogPanel --- scripts/sao-ui/src/lib.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scripts/sao-ui/src/lib.rs b/scripts/sao-ui/src/lib.rs index 3293e8e..948c2e9 100644 --- a/scripts/sao-ui/src/lib.rs +++ b/scripts/sao-ui/src/lib.rs @@ -24,6 +24,7 @@ fn bind_panel_impl(panel: Panel, protocol: Message, msg: Message) -> Box MusicPlayerPanel::bind(panel, msg), + "wip-dialog" => ConfirmationDialogPanel::bind(panel, msg), _ => MainMenuPanel::bind(panel, msg), } } @@ -51,15 +52,23 @@ impl PanelImpl for ConfirmationDialogPanel { self.dialog.on_cursor_event(kind, at.into()); } - fn on_resize(&mut self, _size: Vec2) {} + fn on_resize(&mut self, size: Vec2) { + self.dialog.resize(size); + } fn on_message(&mut self, _msg: Message) {} } impl ConfirmationDialogPanel { pub fn bind(panel: Panel, msg: Message) -> Box { - let msg = msg.to_vec(); - let info: DialogInfo = serde_json::from_slice(&msg).unwrap(); + // let msg = msg.to_vec(); + // let info: DialogInfo = serde_json::from_slice(&msg).unwrap(); + + let info = DialogInfo { + title: "Hello world!".to_string(), + content: "Testing, testing...".to_string(), + responses: vec![DialogResponse::Yes, DialogResponse::No], + }; use widgets::dialog::*; let style = DialogStyle::default(); From 2f5d25a3f4fa46c002d580edb66fcf050aee4643 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 13:08:01 -0700 Subject: [PATCH 12/39] Add Metrics and Theme consts --- scripts/sao-ui/src/style.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/scripts/sao-ui/src/style.rs b/scripts/sao-ui/src/style.rs index 9318ae9..f6deea5 100644 --- a/scripts/sao-ui/src/style.rs +++ b/scripts/sao-ui/src/style.rs @@ -1,4 +1,4 @@ -use canary_script::Color; +use canary_script::{api::Font, Color}; /// A reusable set of colors. Used by default widget styles. pub struct Palette { @@ -10,7 +10,7 @@ pub struct Palette { /// Sword Art Online color palette. pub const SAO_PALETTE: Palette = Palette { - base: Color::WHITE.with_alpha(0xc0), + base: Color::WHITE.with_alpha(0xa0), surface: Color::WHITE, overlay: Color::WHITE, text: Color::BLACK, @@ -24,5 +24,21 @@ pub const ROSE_PINE_PALETTE: Palette = Palette { text: Color(0xe0def4ff), }; -/// The global palette. -pub const PALETTE: Palette = ROSE_PINE_PALETTE; +/// Common measurements for widget shapes. +pub struct Metrics { + pub surface_rounding: f32, +} + +/// Common default parameters for widget styles. +pub struct Theme { + pub palette: Palette, + pub metrics: Metrics, +} + +/// The global theme. +pub const THEME: Theme = Theme { + palette: ROSE_PINE_PALETTE, + metrics: Metrics { + surface_rounding: 5.0, + }, +}; From 948dfa77c4b6b43090b09b4cb69118d299d852e7 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 13:08:17 -0700 Subject: [PATCH 13/39] Add style and THEME to widget prelude --- scripts/sao-ui/src/widgets/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/sao-ui/src/widgets/mod.rs b/scripts/sao-ui/src/widgets/mod.rs index a9968df..fee8899 100644 --- a/scripts/sao-ui/src/widgets/mod.rs +++ b/scripts/sao-ui/src/widgets/mod.rs @@ -75,6 +75,7 @@ impl Widget for T { pub mod prelude { pub use super::*; pub use crate::anim::Animation; + pub use crate::style::{self, THEME}; pub use canary_script::{*, api::*}; pub use keyframe::functions::*; } From 1ac70e653b0bffb1516beb435e282591b0ddb420 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 13:08:28 -0700 Subject: [PATCH 14/39] Use THEME in dialog style defaults --- scripts/sao-ui/src/widgets/dialog.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/sao-ui/src/widgets/dialog.rs b/scripts/sao-ui/src/widgets/dialog.rs index f8dea23..6f7aabb 100644 --- a/scripts/sao-ui/src/widgets/dialog.rs +++ b/scripts/sao-ui/src/widgets/dialog.rs @@ -40,7 +40,7 @@ pub struct DialogStyle { impl Default for DialogStyle { fn default() -> Self { Self { - rounding: 5.0, + rounding: THEME.metrics.surface_rounding, header: Default::default(), body: Default::default(), footer: Default::default(), @@ -61,10 +61,10 @@ pub struct DialogHeaderStyle { impl Default for DialogHeaderStyle { fn default() -> Self { Self { - color: Color::WHITE, + color: THEME.palette.surface, height: 20.0, text_font: Font::new(crate::DISPLAY_FONT), - text_color: Color::BLACK, + text_color: THEME.palette.text, text_scale_factor: 0.65, text_baseline: 0.25, } @@ -82,9 +82,9 @@ pub struct DialogBodyStyle { impl Default for DialogBodyStyle { fn default() -> Self { Self { - color: Color::WHITE.with_alpha(0xb0), + color: THEME.palette.base, text_font: Font::new(crate::CONTENT_FONT), - text_color: Color::BLACK, + text_color: THEME.palette.text, text_size: 5.0, } } @@ -103,7 +103,7 @@ impl Default for DialogFooterStyle { Self { icon_font: Font::new(crate::ICON_FONT), button_radius: 7.5, - color: Color::WHITE, + color: THEME.palette.surface, height: 15.0, } } From 6db0c72f4d752d11e74fe56506e5d5415b2615d9 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 13:15:22 -0700 Subject: [PATCH 15/39] Add terminal colors to style --- scripts/sao-ui/src/style.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/scripts/sao-ui/src/style.rs b/scripts/sao-ui/src/style.rs index f6deea5..7a410ca 100644 --- a/scripts/sao-ui/src/style.rs +++ b/scripts/sao-ui/src/style.rs @@ -6,6 +6,14 @@ pub struct Palette { pub surface: Color, pub overlay: Color, pub text: Color, + pub black: Color, + pub red: Color, + pub green: Color, + pub yellow: Color, + pub blue: Color, + pub magenta: Color, + pub cyan: Color, + pub white: Color, } /// Sword Art Online color palette. @@ -14,6 +22,14 @@ pub const SAO_PALETTE: Palette = Palette { surface: Color::WHITE, overlay: Color::WHITE, text: Color::BLACK, + black: Color::BLACK, + red: Color::RED, + green: Color::GREEN, + yellow: Color::YELLOW, + blue: Color::BLUE, + magenta: Color::MAGENTA, + cyan: Color::CYAN, + white: Color::WHITE, }; /// Rose Pine color palette. @@ -22,6 +38,14 @@ pub const ROSE_PINE_PALETTE: Palette = Palette { surface: Color(0x1f1d2eff), overlay: Color(0x26233aff), text: Color(0xe0def4ff), + black: Color(0x6e6a86ff), + red: Color(0xeb6f92ff), + green: Color(0x7fb59fff), + yellow: Color(0xf6c177ff), + blue: Color(0x31748fff), + magenta: Color(0xc4a7e7ff), + cyan: Color(0x9ccfd8ff), + white: Color(0xe0def4ff), }; /// Common measurements for widget shapes. From 85e1fbd6b6bbb771551232fb1daf2a606a200ab2 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 13:15:34 -0700 Subject: [PATCH 16/39] Use terminal colors for dialog buttons --- scripts/sao-ui/src/widgets/dialog.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/sao-ui/src/widgets/dialog.rs b/scripts/sao-ui/src/widgets/dialog.rs index 6f7aabb..f954984 100644 --- a/scripts/sao-ui/src/widgets/dialog.rs +++ b/scripts/sao-ui/src/widgets/dialog.rs @@ -23,8 +23,8 @@ impl DialogResponse { pub fn get_color(&self) -> Color { match self { - DialogResponse::Yes => Color::BLUE, - DialogResponse::No => Color::RED, + DialogResponse::Yes => THEME.palette.blue, + DialogResponse::No => THEME.palette.red, } } } @@ -95,6 +95,7 @@ pub struct DialogFooterStyle { pub icon_font: Font, pub button_radius: f32, pub color: Color, + pub button_fg: Color, pub height: f32, } @@ -104,6 +105,7 @@ impl Default for DialogFooterStyle { icon_font: Font::new(crate::ICON_FONT), button_radius: 7.5, color: THEME.palette.surface, + button_fg: THEME.palette.white, height: 15.0, } } @@ -136,7 +138,7 @@ impl Dialog { thickness: radius * 0.05, body_color: color, ring_color: color, - icon_color: Color::WHITE, + icon_color: style.footer.button_fg, }; let text = LabelText { From a477c3c385bedaf7eea6fe248e69f7f20641d807 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 13:33:21 -0700 Subject: [PATCH 17/39] Add panel background color edit in sandbox --- apps/sandbox/src/main.rs | 154 +++++++++++++++++++++------------------ 1 file changed, 85 insertions(+), 69 deletions(-) diff --git a/apps/sandbox/src/main.rs b/apps/sandbox/src/main.rs index 9ec1f57..5b54f7b 100644 --- a/apps/sandbox/src/main.rs +++ b/apps/sandbox/src/main.rs @@ -33,6 +33,7 @@ struct App { last_update: Instant, protocol_buf: String, bind_message_buf: String, + panel_bg: egui::Color32, } impl App { @@ -49,6 +50,7 @@ impl App { last_update: Instant::now(), protocol_buf: String::new(), bind_message_buf: String::new(), + panel_bg: egui::Color32::TRANSPARENT, } } } @@ -58,6 +60,8 @@ impl eframe::App for App { ctx.request_repaint(); egui::SidePanel::left("left_panel").show(ctx, |ui| { + ui.heading("New Panel"); + ui.label("Protocol name:"); ui.text_edit_singleline(&mut self.protocol_buf); @@ -81,6 +85,14 @@ impl eframe::App for App { self.panels.push(panel); } + + ui.separator(); + ui.heading("Global Settings"); + + ui.horizontal(|ui| { + ui.label("Panel background color: "); + ui.color_edit_button_srgba(&mut self.panel_bg); + }); }); let dt = self.last_update.elapsed().as_secs_f32(); @@ -88,7 +100,7 @@ impl eframe::App for App { for panel in self.panels.iter_mut() { panel.panel.update(dt); - panel.show(ctx); + panel.show(self.panel_bg, ctx); } } } @@ -102,83 +114,87 @@ pub struct PanelWindow { } impl PanelWindow { - pub fn show(&mut self, ctx: &egui::Context) { + pub fn show(&mut self, bg: egui::Color32, ctx: &egui::Context) { + let frame = egui::Frame::window(&ctx.style()).fill(bg); let window_id = egui::Id::new(format!("panel_{}", self.index)); - egui::Window::new("Panel").id(window_id).show(ctx, |ui| { - egui::menu::bar(ui, |ui| { - ui.checkbox(&mut self.show_msg, "Show Message Editor"); - }); + egui::Window::new("Panel") + .frame(frame) + .id(window_id) + .show(ctx, |ui| { + egui::menu::bar(ui, |ui| { + ui.checkbox(&mut self.show_msg, "Show Message Editor"); + }); - let sense = egui::Sense { - click: true, - drag: true, - focusable: true, - }; - - let desired_size = ui.available_size(); - let response = ui.allocate_response(desired_size, sense); - let rect = response.rect; - - if rect.size() != self.current_size { - let size = rect.size(); - self.current_size = size; - - let size = canary::Vec2::new(size.x, size.y); - self.panel.on_resize(size * PX_PER_MM); - } - - if let Some(hover_pos) = response.hover_pos() { - let local = (hover_pos - rect.left_top()) * PX_PER_MM; - let pos = canary::Vec2::new(local.x, local.y); - - let kind = if response.drag_started() { - CursorEventKind::Select - } else if response.drag_released() { - CursorEventKind::Deselect - } else if response.dragged() { - CursorEventKind::Drag - } else { - CursorEventKind::Hover + let sense = egui::Sense { + click: true, + drag: true, + focusable: true, }; - self.panel.on_cursor_event(kind, pos); - } + let desired_size = ui.available_size(); + let response = ui.allocate_response(desired_size, sense); + let rect = response.rect; - let texture = egui::TextureId::Managed(0); - let uv = egui::pos2(0.0, 0.0); - let mut mesh = egui::Mesh::with_texture(texture); + if rect.size() != self.current_size { + let size = rect.size(); + self.current_size = size; - let commands = self.panel.draw(); - for command in commands.into_iter() { - let voff = mesh.vertices.len() as u32; - - match command { - canary::DrawCommand::Mesh { vertices, indices } => { - for v in vertices.iter() { - use egui::epaint::Vertex; - let pos = v.position / PX_PER_MM; - let pos = egui::pos2(pos.x, pos.y); - let pos = pos + rect.left_top().to_vec2(); - let (r, g, b, a) = v.color.to_rgba_unmultiplied(); - let color = egui::Color32::from_rgba_unmultiplied(r, g, b, a); - let v = Vertex { pos, uv, color }; - mesh.vertices.push(v); - } - - for i in indices.iter() { - mesh.indices.push(i + voff); - } - } - _ => unimplemented!(), + let size = canary::Vec2::new(size.x, size.y); + self.panel.on_resize(size * PX_PER_MM); } - } - let painter = ui.painter_at(rect); - let shape = egui::Shape::mesh(mesh); - painter.add(shape); + if let Some(hover_pos) = response.hover_pos() { + let local = (hover_pos - rect.left_top()) * PX_PER_MM; + let pos = canary::Vec2::new(local.x, local.y); - response - }); + let kind = if response.drag_started() { + CursorEventKind::Select + } else if response.drag_released() { + CursorEventKind::Deselect + } else if response.dragged() { + CursorEventKind::Drag + } else { + CursorEventKind::Hover + }; + + self.panel.on_cursor_event(kind, pos); + } + + let texture = egui::TextureId::Managed(0); + let uv = egui::pos2(0.0, 0.0); + let mut mesh = egui::Mesh::with_texture(texture); + + let commands = self.panel.draw(); + for command in commands.into_iter() { + let voff = mesh.vertices.len() as u32; + + match command { + canary::DrawCommand::Mesh { vertices, indices } => { + for v in vertices.iter() { + use egui::epaint::Vertex; + let pos = v.position / PX_PER_MM; + let pos = egui::pos2(pos.x, pos.y); + let pos = pos + rect.left_top().to_vec2(); + let (r, g, b, a) = v.color.to_rgba_unmultiplied(); + let color = egui::Color32::from_rgba_unmultiplied(r, g, b, a); + let v = Vertex { pos, uv, color }; + mesh.vertices.push(v); + } + + for i in indices.iter() { + mesh.indices.push(i + voff); + } + } + _ => unimplemented!(), + } + } + + let painter = ui.painter_at(rect); + let shape = egui::Shape::mesh(mesh); + painter.add(shape); + + response + }); let msg_edit_id = egui::Id::new(format!("msg_edit_{}", self.index)); egui::Window::new("Message Editor") From 3f7ebeaf7e5cfe9c9be37be036fae7f4a0eb7f79 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 13:42:06 -0700 Subject: [PATCH 18/39] Use theme in main menu --- scripts/sao-ui/src/main_menu.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/sao-ui/src/main_menu.rs b/scripts/sao-ui/src/main_menu.rs index 87bbbb0..8ae2206 100644 --- a/scripts/sao-ui/src/main_menu.rs +++ b/scripts/sao-ui/src/main_menu.rs @@ -64,9 +64,9 @@ impl Default for MainMenu { radius: 7.5, spacing: 1.5, thickness: 0.4, - body_color: Color::WHITE, - ring_color: Color::WHITE, - icon_color: Color::BLACK, + body_color: THEME.palette.surface, + ring_color: THEME.palette.surface, + icon_color: THEME.palette.text, }; let mut buttons = Vec::new(); @@ -150,6 +150,7 @@ pub struct PlayerInfo { width: f32, height: f32, rounding: f32, + color: Color, } impl PlayerInfo { @@ -158,6 +159,7 @@ impl PlayerInfo { width: 70.0, height: 120.0, rounding: 5.0, + color: THEME.palette.surface, } } } @@ -170,7 +172,7 @@ impl RectBounds for PlayerInfo { impl Widget for PlayerInfo { fn draw(&mut self, ctx: &DrawContext) { - ctx.draw_rounded_rect(self.get_bounds(), self.rounding, Color::WHITE); + ctx.draw_rounded_rect(self.get_bounds(), self.rounding, self.color); } } From ce7d641795b10b643007bb8ccc760e13c851c479 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 13:42:18 -0700 Subject: [PATCH 19/39] Use theme in TabMenu --- scripts/sao-ui/src/widgets/menu.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/scripts/sao-ui/src/widgets/menu.rs b/scripts/sao-ui/src/widgets/menu.rs index 5c0a022..36f0ba7 100644 --- a/scripts/sao-ui/src/widgets/menu.rs +++ b/scripts/sao-ui/src/widgets/menu.rs @@ -224,6 +224,7 @@ pub struct TabMenu { impl TabMenu { const HEAD_RADIUS: f32 = 5.0; const HEAD_HEIGHT: f32 = 15.0; + const HEAD_COLOR: Color = THEME.palette.surface; const TAB_WIDTH: f32 = 15.0; const TAB_HEIGHT: f32 = 25.0; const TAB_NUM: usize = 6; @@ -235,9 +236,9 @@ impl TabMenu { radius: Self::HEAD_HEIGHT * 0.25, spacing: Self::HEAD_HEIGHT * 0.1, thickness: Self::HEAD_HEIGHT * 0.05, - body_color: Color::WHITE, - ring_color: Color::BLACK, - icon_color: Color::BLACK, + body_color: Self::HEAD_COLOR, + ring_color: THEME.palette.black, + icon_color: THEME.palette.black, }; const HEAD_BUTTON_MARGIN: f32 = Self::HEAD_HEIGHT / 2.0; @@ -348,20 +349,18 @@ impl Container for TabMenu { } fn draw(&mut self, ctx: &DrawContext) { - let head_color = Color::WHITE; - ctx.draw_partially_rounded_rect( CornerFlags::BOTTOM_RIGHT, self.separator_rect, Self::INNER_RADIUS, - head_color, + Self::HEAD_COLOR, ); ctx.draw_partially_rounded_rect( CornerFlags::TOP, self.head_rect, Self::HEAD_RADIUS, - head_color, + Self::HEAD_COLOR, ); } } From 59a673128ccdae9fb175770115881346fc82b43c Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 14:00:16 -0700 Subject: [PATCH 20/39] Add base_hover and base_active colors --- scripts/sao-ui/src/style.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/sao-ui/src/style.rs b/scripts/sao-ui/src/style.rs index 7a410ca..01d6f56 100644 --- a/scripts/sao-ui/src/style.rs +++ b/scripts/sao-ui/src/style.rs @@ -1,8 +1,10 @@ -use canary_script::{api::Font, Color}; +use canary_script::Color; /// A reusable set of colors. Used by default widget styles. pub struct Palette { pub base: Color, + pub base_hover: Color, + pub base_active: Color, pub surface: Color, pub overlay: Color, pub text: Color, @@ -19,6 +21,8 @@ pub struct Palette { /// Sword Art Online color palette. pub const SAO_PALETTE: Palette = Palette { base: Color::WHITE.with_alpha(0xa0), + base_hover: Color::WHITE.with_alpha(0xd0), + base_active: Color::YELLOW, surface: Color::WHITE, overlay: Color::WHITE, text: Color::BLACK, @@ -35,6 +39,8 @@ pub const SAO_PALETTE: Palette = Palette { /// Rose Pine color palette. pub const ROSE_PINE_PALETTE: Palette = Palette { base: Color(0x191724ff), + base_hover: Color(0x21202eff), // Rose Pine Highlight Low + base_active: Color(0x403d52ff), // Rose Pine Highlight Med surface: Color(0x1f1d2eff), overlay: Color(0x26233aff), text: Color(0xe0def4ff), From e8c908832799f4143a73bafe122379157944047f Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 14:01:20 -0700 Subject: [PATCH 21/39] Use THEME in RectButtonStyle --- scripts/sao-ui/src/widgets/button.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/sao-ui/src/widgets/button.rs b/scripts/sao-ui/src/widgets/button.rs index d2b8859..846eae5 100644 --- a/scripts/sao-ui/src/widgets/button.rs +++ b/scripts/sao-ui/src/widgets/button.rs @@ -118,6 +118,8 @@ pub struct RectButtonStyle { pub inactive_color: Color, pub hover_color: Color, pub selected_color: Color, + pub icon_color: Color, + pub label_color: Color, } impl Default for RectButtonStyle { @@ -129,9 +131,11 @@ impl Default for RectButtonStyle { label_baseline: 0.25, icon_scale_factor: 0.8, icon_margin_factor: 1.1, - inactive_color: Color::WHITE.with_alpha(0x40), - hover_color: Color::WHITE.with_alpha(0xb0), - selected_color: Color::YELLOW, + inactive_color: THEME.palette.base, + hover_color: THEME.palette.base_hover, + selected_color: THEME.palette.base_active, + icon_color: THEME.palette.black, + label_color: THEME.palette.text, } } } @@ -168,7 +172,7 @@ impl RectButton { label_left += margin; alignment = HorizontalAlignment::Left; let scale = rect.height() * style.icon_scale_factor; - let color = Color::BLACK; + let color = style.icon_color; let cx = rect.tl.x + margin / 2.0; let cy = rect.tl.y + rect.height() / 2.0; let center = Vec2::new(cx, cy); @@ -182,7 +186,7 @@ impl RectButton { let right = rect.br.x; let baseline = rect.tl.y; let baseline = (rect.height() * (1.0 - style.label_baseline)) + baseline; - let color = Color::BLACK; + let color = style.label_color; Label::new(text, alignment, scale, color, left, right, baseline) }); From bc8032aaaffadaad04b8a93b9fbb2758c1c469c7 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 14:01:31 -0700 Subject: [PATCH 22/39] Use THEME in ScrollBarStyle --- scripts/sao-ui/src/widgets/scroll.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/sao-ui/src/widgets/scroll.rs b/scripts/sao-ui/src/widgets/scroll.rs index 130cbc5..0925313 100644 --- a/scripts/sao-ui/src/widgets/scroll.rs +++ b/scripts/sao-ui/src/widgets/scroll.rs @@ -21,11 +21,11 @@ impl Default for ScrollBarStyle { margin: Vec2::splat(2.0), body_radius: 1.0, body_width: 3.0, - body_idle_color: Color(0x7f7f7fff), - body_hover_color: Color(0xb0b0b0ff), - body_selected_color: Color::WHITE, + body_idle_color: THEME.palette.base, + body_hover_color: THEME.palette.base_hover, + body_selected_color: THEME.palette.base_active, rail_width: 1.0, - rail_color: Color(0xa0a0a07f), + rail_color: THEME.palette.base, } } } From ef6a81e1420df977765b4a8ba2ad88dcfb2d86ed Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 14:13:50 -0700 Subject: [PATCH 23/39] Add Rose Pine Moon color palette --- scripts/sao-ui/src/style.rs | 40 +++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/scripts/sao-ui/src/style.rs b/scripts/sao-ui/src/style.rs index 01d6f56..b111dad 100644 --- a/scripts/sao-ui/src/style.rs +++ b/scripts/sao-ui/src/style.rs @@ -39,19 +39,37 @@ pub const SAO_PALETTE: Palette = Palette { /// Rose Pine color palette. pub const ROSE_PINE_PALETTE: Palette = Palette { base: Color(0x191724ff), - base_hover: Color(0x21202eff), // Rose Pine Highlight Low - base_active: Color(0x403d52ff), // Rose Pine Highlight Med + base_hover: Color(0x21202eff), // Highlight Low + base_active: Color(0x403d52ff), // Highlight Med surface: Color(0x1f1d2eff), overlay: Color(0x26233aff), text: Color(0xe0def4ff), - black: Color(0x6e6a86ff), - red: Color(0xeb6f92ff), - green: Color(0x7fb59fff), - yellow: Color(0xf6c177ff), - blue: Color(0x31748fff), - magenta: Color(0xc4a7e7ff), - cyan: Color(0x9ccfd8ff), - white: Color(0xe0def4ff), + black: Color(0x6e6a86ff), // Muted + red: Color(0xeb6f92ff), // Love + green: Color(0x7fb59fff), // ??? (not in Rose Pine?) + yellow: Color(0xf6c177ff), // Gold + blue: Color(0x31748fff), // Pine + magenta: Color(0xc4a7e7ff), // Iris + cyan: Color(0x9ccfd8ff), // Foam + white: Color(0xe0def4ff), // Text +}; + +/// Rose Pine Moon color palette. +pub const ROSE_PINE_MOON_PALETTE: Palette = Palette { + base: Color(0x232136ff), + base_hover: Color(0x2a283eff), // Highlight Low + base_active: Color(0x44415aff), // Highlight Med + surface: Color(0x2a273fff), + overlay: Color(0x393552), + text: Color(0xe0def4ff), + black: Color(0x6e6a86ff), // Muted + red: Color(0xeb6f92ff), // Love + green: Color(0x7fb59fff), // ??? (not in Rose Pine?) + yellow: Color(0xf6c177ff), // Gold + blue: Color(0x3e8fb0ff), // Pine + magenta: Color(0xc4a7e7ff), // Iris + cyan: Color(0x9ccfd8ff), // Foam + white: Color(0xe0def4ff), // Text }; /// Common measurements for widget shapes. @@ -67,7 +85,7 @@ pub struct Theme { /// The global theme. pub const THEME: Theme = Theme { - palette: ROSE_PINE_PALETTE, + palette: ROSE_PINE_MOON_PALETTE, metrics: Metrics { surface_rounding: 5.0, }, From 25532f4f9e87623e399418a6acf6737f08e6eafd Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 14:30:26 -0700 Subject: [PATCH 24/39] Use theme in MusicPlayerWidget --- scripts/sao-ui/src/music_player.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/sao-ui/src/music_player.rs b/scripts/sao-ui/src/music_player.rs index 9eab50e..f0e190c 100644 --- a/scripts/sao-ui/src/music_player.rs +++ b/scripts/sao-ui/src/music_player.rs @@ -179,7 +179,8 @@ impl MusicPlayerWidget { text: content.to_string(), }; - let label = Label::new_centered(text, 10.0, Color::BLACK); + let color = style.body.text_color; + let label = Label::new_centered(text, 10.0, color); Offset::new(label, Vec2::ZERO) }; @@ -196,7 +197,7 @@ impl MusicPlayerWidget { text, HorizontalAlignment::Center, scale, - Color::BLACK, + THEME.palette.text, 0.0, 0.0, baseline, @@ -225,18 +226,18 @@ impl MusicPlayerWidget { radius: style.footer.height * 0.3, spacing: style.footer.height * 0.1, thickness: style.footer.height * 0.025, - body_color: Color(0xf1b841ff), - ring_color: Color(0xf1b841ff), - icon_color: Color::BLACK, + body_color: THEME.palette.yellow, + ring_color: THEME.palette.yellow, + icon_color: THEME.palette.black, }; let secondary_button = RoundButtonStyle { radius: style.footer.height * 0.25, spacing: style.footer.height * 0.05, thickness: style.footer.height * 0.025, - body_color: Color::WHITE, - ring_color: Color::BLACK, - icon_color: Color::BLACK, + body_color: style.footer.color, + ring_color: THEME.palette.black, + icon_color: THEME.palette.black, }; let prev = RoundButton::new(secondary_button.clone(), Some(prev_text)); From e924a170736359b3eeab07853f7bbc7286271807 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 16:48:17 -0700 Subject: [PATCH 25/39] Disable Magpie glium gamma-correction --- apps/magpie/src/service/gl.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/magpie/src/service/gl.rs b/apps/magpie/src/service/gl.rs index 689b340..38396ec 100644 --- a/apps/magpie/src/service/gl.rs +++ b/apps/magpie/src/service/gl.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later use canary::{DrawCommand, Vec2, PX_PER_MM}; -use glium::Surface; +use glium::{program::ProgramCreationInput, Surface}; #[derive(Copy, Clone)] pub struct Vertex { @@ -59,9 +59,21 @@ pub struct Graphics { impl Graphics { pub fn new(display: glium::Display) -> Self { - let program = - glium::Program::from_source(&display, VERTEX_SHADER_SRC, FRAGMENT_SHADER_SRC, None) - .unwrap(); + let program = glium::Program::new( + &display, + ProgramCreationInput::SourceCode { + vertex_shader: VERTEX_SHADER_SRC, + tessellation_control_shader: None, + tessellation_evaluation_shader: None, + geometry_shader: None, + fragment_shader: FRAGMENT_SHADER_SRC, + transform_feedback_varyings: None, + outputs_srgb: true, // don't automatically apply gamma correction + uses_point_size: false, + }, + ) + .unwrap(); + Self { display, program } } From e35ee1be4c662872e747bac57a01c80f2f48eea5 Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 17:00:47 -0700 Subject: [PATCH 26/39] Better SAO UI base transparency --- scripts/sao-ui/src/style.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/sao-ui/src/style.rs b/scripts/sao-ui/src/style.rs index b111dad..b0be9df 100644 --- a/scripts/sao-ui/src/style.rs +++ b/scripts/sao-ui/src/style.rs @@ -20,8 +20,8 @@ pub struct Palette { /// Sword Art Online color palette. pub const SAO_PALETTE: Palette = Palette { - base: Color::WHITE.with_alpha(0xa0), - base_hover: Color::WHITE.with_alpha(0xd0), + base: Color::WHITE.with_alpha(0xc0), + base_hover: Color::WHITE.with_alpha(0xe0), base_active: Color::YELLOW, surface: Color::WHITE, overlay: Color::WHITE, @@ -38,8 +38,8 @@ pub const SAO_PALETTE: Palette = Palette { /// Rose Pine color palette. pub const ROSE_PINE_PALETTE: Palette = Palette { - base: Color(0x191724ff), - base_hover: Color(0x21202eff), // Highlight Low + base: Color(0x191724c0), + base_hover: Color(0x21202ee0), // Highlight Low base_active: Color(0x403d52ff), // Highlight Med surface: Color(0x1f1d2eff), overlay: Color(0x26233aff), @@ -56,8 +56,8 @@ pub const ROSE_PINE_PALETTE: Palette = Palette { /// Rose Pine Moon color palette. pub const ROSE_PINE_MOON_PALETTE: Palette = Palette { - base: Color(0x232136ff), - base_hover: Color(0x2a283eff), // Highlight Low + base: Color(0x232136c0), + base_hover: Color(0x2a283ee0), // Highlight Low base_active: Color(0x44415aff), // Highlight Med surface: Color(0x2a273fff), overlay: Color(0x393552), From 4b126ed2cf7bb364afff4ac7d8915f21d9a2ac7d Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 18 Nov 2022 17:15:29 -0700 Subject: [PATCH 27/39] Magpie window transparency + remove window decorations --- apps/magpie/src/service/gl.rs | 2 +- apps/magpie/src/service/window.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/magpie/src/service/gl.rs b/apps/magpie/src/service/gl.rs index 38396ec..e46e11e 100644 --- a/apps/magpie/src/service/gl.rs +++ b/apps/magpie/src/service/gl.rs @@ -117,7 +117,7 @@ impl Graphics { }; let mut target = self.display.draw(); - target.clear_color(0.0, 0.0, 0.0, 1.0); + target.clear_color(0.0, 0.0, 0.0, 0.0); target .draw( &vertex_buffer, diff --git a/apps/magpie/src/service/window.rs b/apps/magpie/src/service/window.rs index 3834224..b028f78 100644 --- a/apps/magpie/src/service/window.rs +++ b/apps/magpie/src/service/window.rs @@ -47,7 +47,9 @@ impl Window { panel: Panel, event_loop: &EventLoopWindowTarget, ) -> Result { - let wb = glutin::window::WindowBuilder::new(); + let wb = glutin::window::WindowBuilder::new() + .with_transparent(true) + .with_decorations(false); let cb = glutin::ContextBuilder::new(); let display = glium::Display::new(wb, cb, &event_loop)?; let graphics = Graphics::new(display); @@ -164,7 +166,11 @@ impl WindowStore { message: WindowMessage, ) -> anyhow::Result { match message { - WindowMessage::OpenWindow { id, protocol, script } => { + WindowMessage::OpenWindow { + id, + protocol, + script, + } => { println!("Opening window {} with script {:?}", id, script); let module = std::fs::read(script)?; let mut script = self.runtime.load_module(&module)?; From 046aede0fab9726df8c33ca568abac9b37b34248 Mon Sep 17 00:00:00 2001 From: mars Date: Sat, 19 Nov 2022 13:06:36 -0700 Subject: [PATCH 28/39] Add Arctica SAO UI theme --- scripts/sao-ui/src/style.rs | 98 ++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 23 deletions(-) diff --git a/scripts/sao-ui/src/style.rs b/scripts/sao-ui/src/style.rs index b0be9df..0030c38 100644 --- a/scripts/sao-ui/src/style.rs +++ b/scripts/sao-ui/src/style.rs @@ -18,10 +18,16 @@ pub struct Palette { pub white: Color, } +/// The common base color alpha shared between all themes. +pub const BASE_ALPHA: u8 = 0xc0; + +/// The common base_hover color alpha shared between all themes. +pub const BASE_HOVER_ALPHA: u8 = 0xe0; + /// Sword Art Online color palette. pub const SAO_PALETTE: Palette = Palette { - base: Color::WHITE.with_alpha(0xc0), - base_hover: Color::WHITE.with_alpha(0xe0), + base: Color::WHITE.with_alpha(BASE_ALPHA), + base_hover: Color::WHITE.with_alpha(BASE_HOVER_ALPHA), base_active: Color::YELLOW, surface: Color::WHITE, overlay: Color::WHITE, @@ -38,38 +44,84 @@ pub const SAO_PALETTE: Palette = Palette { /// Rose Pine color palette. pub const ROSE_PINE_PALETTE: Palette = Palette { - base: Color(0x191724c0), - base_hover: Color(0x21202ee0), // Highlight Low - base_active: Color(0x403d52ff), // Highlight Med + base: Color(0x191724ff).with_alpha(BASE_ALPHA), + base_hover: Color(0x21202ee0).with_alpha(BASE_HOVER_ALPHA), // Highlight Low + base_active: Color(0x403d52ff), // Highlight Med surface: Color(0x1f1d2eff), overlay: Color(0x26233aff), text: Color(0xe0def4ff), - black: Color(0x6e6a86ff), // Muted - red: Color(0xeb6f92ff), // Love - green: Color(0x7fb59fff), // ??? (not in Rose Pine?) - yellow: Color(0xf6c177ff), // Gold - blue: Color(0x31748fff), // Pine + black: Color(0x6e6a86ff), // Muted + red: Color(0xeb6f92ff), // Love + green: Color(0x7fb59fff), // ??? (not in Rose Pine?) + yellow: Color(0xf6c177ff), // Gold + blue: Color(0x31748fff), // Pine magenta: Color(0xc4a7e7ff), // Iris - cyan: Color(0x9ccfd8ff), // Foam - white: Color(0xe0def4ff), // Text + cyan: Color(0x9ccfd8ff), // Foam + white: Color(0xe0def4ff), // Text }; /// Rose Pine Moon color palette. pub const ROSE_PINE_MOON_PALETTE: Palette = Palette { - base: Color(0x232136c0), - base_hover: Color(0x2a283ee0), // Highlight Low - base_active: Color(0x44415aff), // Highlight Med + base: Color(0x232136ff).with_alpha(BASE_ALPHA), + base_hover: Color(0x2a283eff).with_alpha(BASE_HOVER_ALPHA), // Highlight Low + base_active: Color(0x44415aff), // Highlight Med surface: Color(0x2a273fff), overlay: Color(0x393552), text: Color(0xe0def4ff), - black: Color(0x6e6a86ff), // Muted - red: Color(0xeb6f92ff), // Love - green: Color(0x7fb59fff), // ??? (not in Rose Pine?) - yellow: Color(0xf6c177ff), // Gold - blue: Color(0x3e8fb0ff), // Pine + black: Color(0x6e6a86ff), // Muted + red: Color(0xeb6f92ff), // Love + green: Color(0x7fb59fff), // ??? (not in Rose Pine?) + yellow: Color(0xf6c177ff), // Gold + blue: Color(0x3e8fb0ff), // Pine magenta: Color(0xc4a7e7ff), // Iris - cyan: Color(0x9ccfd8ff), // Foam - white: Color(0xe0def4ff), // Text + cyan: Color(0x9ccfd8ff), // Foam + white: Color(0xe0def4ff), // Text +}; + +/// [Arctica](https://github.com/sashakoshka/arctica) indexable color theme. +pub const ARCTICA: [Color; 24] = [ + Color(0x242933ff), + Color(0x2e3440ff), + Color(0x3b4252ff), + Color(0x4c566aff), + Color(0xeceff4ff), + Color(0xd8dee9ff), + Color(0xc2c9d6ff), + Color(0xaeb7c6ff), + Color(0xa8555dff), + Color(0xb77763ff), + Color(0xcdb179ff), + Color(0x8ba277ff), + Color(0x769b9bff), + Color(0x72a1aeff), + Color(0x5e81acff), + Color(0x92738cff), + Color(0xbf616aff), + Color(0xd08770ff), + Color(0xebcb8bff), + Color(0xa3be8cff), + Color(0x8fbcbbff), + Color(0x88c0d0ff), + Color(0x81a1c1ff), + Color(0xb48eadff), +]; + +/// [Arctica](https://github.com/sashakoshka/arctica) color palette. +pub const ARCTICA_PALETTE: Palette = Palette { + base: ARCTICA[0].with_alpha(BASE_ALPHA), + base_hover: ARCTICA[1].with_alpha(BASE_HOVER_ALPHA), + base_active: ARCTICA[13], + surface: ARCTICA[2], + overlay: ARCTICA[3], + text: ARCTICA[5], + black: ARCTICA[3], + red: ARCTICA[8], + green: ARCTICA[11], + yellow: ARCTICA[10], + blue: ARCTICA[14], + magenta: ARCTICA[15], + cyan: ARCTICA[13], + white: ARCTICA[7], }; /// Common measurements for widget shapes. @@ -85,7 +137,7 @@ pub struct Theme { /// The global theme. pub const THEME: Theme = Theme { - palette: ROSE_PINE_MOON_PALETTE, + palette: ARCTICA_PALETTE, metrics: Metrics { surface_rounding: 5.0, }, From 59c34d6aca52c60b9f90a8e17c1bae2572dd9b3a Mon Sep 17 00:00:00 2001 From: mars Date: Sat, 19 Nov 2022 13:09:53 -0700 Subject: [PATCH 29/39] Clean up SAO UI color definitions --- scripts/sao-ui/src/style.rs | 109 +++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/scripts/sao-ui/src/style.rs b/scripts/sao-ui/src/style.rs index 0030c38..c56e702 100644 --- a/scripts/sao-ui/src/style.rs +++ b/scripts/sao-ui/src/style.rs @@ -24,6 +24,11 @@ pub const BASE_ALPHA: u8 = 0xc0; /// The common base_hover color alpha shared between all themes. pub const BASE_HOVER_ALPHA: u8 = 0xe0; +/// Converts 0xrrggbb hex to an opaque [Color]. +pub const fn hex(rgb: u32) -> Color { + Color((rgb << 8) | 0xff) +} + /// Sword Art Online color palette. pub const SAO_PALETTE: Palette = Palette { base: Color::WHITE.with_alpha(BASE_ALPHA), @@ -44,66 +49,66 @@ pub const SAO_PALETTE: Palette = Palette { /// Rose Pine color palette. pub const ROSE_PINE_PALETTE: Palette = Palette { - base: Color(0x191724ff).with_alpha(BASE_ALPHA), - base_hover: Color(0x21202ee0).with_alpha(BASE_HOVER_ALPHA), // Highlight Low - base_active: Color(0x403d52ff), // Highlight Med - surface: Color(0x1f1d2eff), - overlay: Color(0x26233aff), - text: Color(0xe0def4ff), - black: Color(0x6e6a86ff), // Muted - red: Color(0xeb6f92ff), // Love - green: Color(0x7fb59fff), // ??? (not in Rose Pine?) - yellow: Color(0xf6c177ff), // Gold - blue: Color(0x31748fff), // Pine - magenta: Color(0xc4a7e7ff), // Iris - cyan: Color(0x9ccfd8ff), // Foam - white: Color(0xe0def4ff), // Text + base: hex(0x191724).with_alpha(BASE_ALPHA), + base_hover: hex(0x21202ee0).with_alpha(BASE_HOVER_ALPHA), // Highlight Low + base_active: hex(0x403d52), // Highlight Med + surface: hex(0x1f1d2e), + overlay: hex(0x26233a), + text: hex(0xe0def4), + black: hex(0x6e6a86), // Muted + red: hex(0xeb6f92), // Love + green: hex(0x7fb59f), // ??? (not in Rose Pine?) + yellow: hex(0xf6c177), // Gold + blue: hex(0x31748f), // Pine + magenta: hex(0xc4a7e7), // Iris + cyan: hex(0x9ccfd8), // Foam + white: hex(0xe0def4), // Text }; /// Rose Pine Moon color palette. pub const ROSE_PINE_MOON_PALETTE: Palette = Palette { - base: Color(0x232136ff).with_alpha(BASE_ALPHA), - base_hover: Color(0x2a283eff).with_alpha(BASE_HOVER_ALPHA), // Highlight Low - base_active: Color(0x44415aff), // Highlight Med - surface: Color(0x2a273fff), - overlay: Color(0x393552), - text: Color(0xe0def4ff), - black: Color(0x6e6a86ff), // Muted - red: Color(0xeb6f92ff), // Love - green: Color(0x7fb59fff), // ??? (not in Rose Pine?) - yellow: Color(0xf6c177ff), // Gold - blue: Color(0x3e8fb0ff), // Pine - magenta: Color(0xc4a7e7ff), // Iris - cyan: Color(0x9ccfd8ff), // Foam - white: Color(0xe0def4ff), // Text + base: hex(0x232136).with_alpha(BASE_ALPHA), + base_hover: hex(0x2a283e).with_alpha(BASE_HOVER_ALPHA), // Highlight Low + base_active: hex(0x44415a), // Highlight Med + surface: hex(0x2a273f), + overlay: hex(0x393552), + text: hex(0xe0def4), + black: hex(0x6e6a86), // Muted + red: hex(0xeb6f92), // Love + green: hex(0x7fb59f), // ??? (not in Rose Pine?) + yellow: hex(0xf6c177), // Gold + blue: hex(0x3e8fb0), // Pine + magenta: hex(0xc4a7e7), // Iris + cyan: hex(0x9ccfd8), // Foam + white: hex(0xe0def4), // Text }; /// [Arctica](https://github.com/sashakoshka/arctica) indexable color theme. pub const ARCTICA: [Color; 24] = [ - Color(0x242933ff), - Color(0x2e3440ff), - Color(0x3b4252ff), - Color(0x4c566aff), - Color(0xeceff4ff), - Color(0xd8dee9ff), - Color(0xc2c9d6ff), - Color(0xaeb7c6ff), - Color(0xa8555dff), - Color(0xb77763ff), - Color(0xcdb179ff), - Color(0x8ba277ff), - Color(0x769b9bff), - Color(0x72a1aeff), - Color(0x5e81acff), - Color(0x92738cff), - Color(0xbf616aff), - Color(0xd08770ff), - Color(0xebcb8bff), - Color(0xa3be8cff), - Color(0x8fbcbbff), - Color(0x88c0d0ff), - Color(0x81a1c1ff), - Color(0xb48eadff), + hex(0x242933), + hex(0x2e3440), + hex(0x3b4252), + hex(0x4c566a), + hex(0xeceff4), + hex(0xd8dee9), + hex(0xc2c9d6), + hex(0xaeb7c6), + hex(0xa8555d), + hex(0xb77763), + hex(0xcdb179), + hex(0x8ba277), + hex(0x769b9b), + hex(0x72a1ae), + hex(0x5e81ac), + hex(0x92738c), + hex(0xbf616a), + hex(0xd08770), + hex(0xebcb8b), + hex(0xa3be8c), + hex(0x8fbcbb), + hex(0x88c0d0), + hex(0x81a1c1), + hex(0xb48ead), ]; /// [Arctica](https://github.com/sashakoshka/arctica) color palette. From d7323323f8b07a15bf6d291c54ba738b54b7f0d6 Mon Sep 17 00:00:00 2001 From: mars Date: Sat, 19 Nov 2022 15:11:09 -0700 Subject: [PATCH 30/39] Add SAO UI Palette widget --- scripts/sao-ui/src/main_menu.rs | 23 +++++- scripts/sao-ui/src/style.rs | 21 +++++ scripts/sao-ui/src/widgets/mod.rs | 1 + scripts/sao-ui/src/widgets/palette.rs | 106 ++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 scripts/sao-ui/src/widgets/palette.rs diff --git a/scripts/sao-ui/src/main_menu.rs b/scripts/sao-ui/src/main_menu.rs index 8ae2206..b921a46 100644 --- a/scripts/sao-ui/src/main_menu.rs +++ b/scripts/sao-ui/src/main_menu.rs @@ -7,6 +7,7 @@ use crate::{DrawContext, Rect}; use button::{RectButton, RoundButton, RoundButtonStyle}; use dialog::{Dialog, DialogInfo, DialogResponse, DialogStyle}; use menu::{SlotMenu, SlotMenuEvent, TabMenu}; +use palette::Palette; use shell::{Offset, OffsetAlignment, Popup, Reveal}; use text::LabelText; @@ -47,6 +48,7 @@ pub struct MainMenu { pub menu: Offset>, pub player_info: Reveal>, pub inventory: Reveal>, + pub palette: Reveal>, pub settings: Reveal>, } @@ -102,6 +104,15 @@ impl Default for MainMenu { let inventory = Offset::new(inventory, submenu_spacing_right); let inventory = Reveal::new(inventory, reveal_slide, reveal_duration); + let palette = Palette::new(Default::default()); + let palette = Offset::new_aligned( + palette, + submenu_spacing_left, + OffsetAlignment::End, + OffsetAlignment::Center, + ); + let palette = Reveal::new(palette, -reveal_slide, reveal_duration); + let settings = SettingsMenu::new(); let settings = Offset::new(settings, submenu_spacing_right); let settings = Reveal::new(settings, reveal_slide, reveal_duration); @@ -110,6 +121,7 @@ impl Default for MainMenu { menu, player_info, inventory, + palette, settings, } } @@ -120,6 +132,7 @@ impl Container for MainMenu { f(&mut self.menu); f(&mut self.player_info); f(&mut self.inventory); + f(&mut self.palette); f(&mut self.settings); } @@ -139,8 +152,14 @@ impl Container for MainMenu { self.player_info.hide(); self.inventory.hide(); } - SlotMenuEvent::SubmenuOpen(4) => self.settings.show(), - SlotMenuEvent::SubmenuClose(4) => self.settings.hide(), + SlotMenuEvent::SubmenuOpen(4) => { + self.palette.show(); + self.settings.show(); + } + SlotMenuEvent::SubmenuClose(4) => { + self.palette.hide(); + self.settings.hide(); + } _ => {} }; } diff --git a/scripts/sao-ui/src/style.rs b/scripts/sao-ui/src/style.rs index c56e702..afc002f 100644 --- a/scripts/sao-ui/src/style.rs +++ b/scripts/sao-ui/src/style.rs @@ -18,6 +18,27 @@ pub struct Palette { pub white: Color, } +impl Palette { + pub fn make_label_pairs(&self) -> Vec<(&'static str, Color)> { + vec![ + ("Base", self.base), + ("Base Hover", self.base_hover), + ("Base Active", self.base_active), + ("Surface", self.surface), + ("Overlay", self.overlay), + ("Text", self.text), + ("Black", self.black), + ("Red", self.red), + ("Green", self.green), + ("Yellow", self.yellow), + ("Blue", self.blue), + ("Magenta", self.magenta), + ("Cyan", self.cyan), + ("White", self.white), + ] + } +} + /// The common base color alpha shared between all themes. pub const BASE_ALPHA: u8 = 0xc0; diff --git a/scripts/sao-ui/src/widgets/mod.rs b/scripts/sao-ui/src/widgets/mod.rs index fee8899..310bf1a 100644 --- a/scripts/sao-ui/src/widgets/mod.rs +++ b/scripts/sao-ui/src/widgets/mod.rs @@ -8,6 +8,7 @@ pub mod button; pub mod dialog; pub mod flex; pub mod menu; +pub mod palette; pub mod scroll; pub mod shell; pub mod text; diff --git a/scripts/sao-ui/src/widgets/palette.rs b/scripts/sao-ui/src/widgets/palette.rs new file mode 100644 index 0000000..d045feb --- /dev/null +++ b/scripts/sao-ui/src/widgets/palette.rs @@ -0,0 +1,106 @@ +use super::prelude::*; +use shell::Offset; +use text::{HorizontalAlignment, Label, LabelText}; + +pub struct PaletteStyle { + pub bg: Color, + pub text: Color, + pub rounding: f32, + pub text_size: f32, + pub line_spacing: f32, + pub color_radius: f32, + pub margin: Rect, +} + +impl Default for PaletteStyle { + fn default() -> Self { + Self { + bg: THEME.palette.surface, + text: THEME.palette.text, + rounding: THEME.metrics.surface_rounding, + text_size: 5.0, + line_spacing: 8.0, + color_radius: 3.0, + margin: Rect::from_xy_size(Vec2::splat(10.0), Vec2::ZERO), + } + } +} + +/// A widget that displays all the colors in the global palette. +pub struct Palette { + body: Rect, + style: PaletteStyle, + labels: Vec>, + colors: Vec<(Vec2, Color)>, +} + +impl Palette { + pub fn new(style: PaletteStyle) -> Self { + let width = 70.0; + let pairs = THEME.palette.make_label_pairs(); + let label_font = Font::new(crate::CONTENT_FONT); + + let mut label_cursor = Vec2::new(0.0, style.line_spacing) + style.margin.tl; + let mut color_cursor = Vec2::new( + width - style.margin.br.x, + style.line_spacing / 2.0 + style.margin.tl.y, + ); + let mut labels = Vec::new(); + let mut colors = Vec::new(); + + for (text, color) in pairs { + let text = LabelText { + font: label_font, + text: text.to_string(), + }; + + let label = Label::new( + text, + HorizontalAlignment::Left, + style.text_size, + style.text, + 0.0, + 0.0, + 0.0, + ); + + let label = Offset::new(label, label_cursor); + + labels.push(label); + + colors.push((color_cursor, color)); + + label_cursor.y += style.line_spacing; + color_cursor.y += style.line_spacing; + } + + let height = label_cursor.y + style.margin.br.y; + + Self { + body: Rect::from_xy_size(Vec2::ZERO, Vec2::new(width, height)), + style, + labels, + colors, + } + } +} + +impl RectBounds for Palette { + fn get_bounds(&self) -> Rect { + self.body + } +} + +impl Widget for Palette { + fn draw(&mut self, ctx: &DrawContext) { + ctx.draw_rounded_rect(self.body, self.style.rounding, self.style.bg); + + for label in self.labels.iter_mut() { + label.draw(ctx); + } + + for (center, color) in self.colors.iter() { + ctx.draw_circle(*center, self.style.color_radius, *color); + } + } +} From 55859ab5c0508cece2b252f3124470d3b007da4c Mon Sep 17 00:00:00 2001 From: mars Date: Sat, 19 Nov 2022 21:42:16 -0700 Subject: [PATCH 31/39] Super WIP zbus-based music player --- apps/music-player/Cargo.toml | 5 +- apps/music-player/src/main.rs | 88 +++++++++++++++++++++------------- apps/music-player/src/mpris.rs | 25 ++++++++++ 3 files changed, 83 insertions(+), 35 deletions(-) create mode 100644 apps/music-player/src/mpris.rs diff --git a/apps/music-player/Cargo.toml b/apps/music-player/Cargo.toml index 2aed4fe..36582b5 100644 --- a/apps/music-player/Cargo.toml +++ b/apps/music-player/Cargo.toml @@ -11,9 +11,10 @@ required-features = ["bin"] [dependencies] canary-magpie = { path = "../magpie", optional = true } -mpris = { version = "2.0.0-rc3", optional = true } serde = { version = "1", features = ["derive"] } serde_json = "1" +smol = { version = "1.2", optional = true } +zbus = { version = "3.5", optional = true } [features] -bin = ["dep:canary-magpie", "dep:mpris"] +bin = ["dep:canary-magpie", "dep:smol", "dep:zbus"] diff --git a/apps/music-player/src/main.rs b/apps/music-player/src/main.rs index 5f07f12..23ad88e 100644 --- a/apps/music-player/src/main.rs +++ b/apps/music-player/src/main.rs @@ -1,46 +1,52 @@ // Copyright (c) 2022 Marceline Cramer // SPDX-License-Identifier: AGPL-3.0-or-later -use canary_music_player::*; use canary_magpie::client::MagpieClient; use canary_magpie::protocol::{CreatePanel, MagpieServerMsg}; use canary_music_player::*; -use mpris::PlayerFinder; -pub struct MetadataTracker { +pub mod mpris; + +use mpris::*; + +pub struct Metadata { pub album: AlbumInfo, pub track: TrackInfo, } -impl From<&mpris::Metadata> for MetadataTracker { - fn from(metadata: &mpris::Metadata) -> Self { +impl<'a> From<&MetadataMap<'a>> for Metadata { + fn from(map: &MetadataMap<'a>) -> Self { let album = AlbumInfo { - title: metadata.album_name().map(ToString::to_string), - artists: metadata - .album_artists() - .unwrap_or(Vec::new()) - .iter() - .map(ToString::to_string) - .collect(), + title: map + .get("xesam:album") + .and_then(|v| TryFrom::try_from(v).ok()), + artists: map + .get("xesam:albumArtist") + .cloned() + .and_then(|v| TryFrom::try_from(v).ok()) + .unwrap_or(Vec::new()), }; let track = TrackInfo { - title: metadata.title().map(ToString::to_string), - artists: metadata - .artists() - .unwrap_or(Vec::new()) - .iter() - .map(ToString::to_string) - .collect(), - track_number: metadata.track_number(), + title: map + .get("xesam:title") + .and_then(|v| TryFrom::try_from(v).ok()), + artists: map + .get("xesam:artist") + .cloned() + .and_then(|v| TryFrom::try_from(v).ok()) + .unwrap_or(Vec::new()), + track_number: map + .get("xesam:trackNumber") + .and_then(|v| TryFrom::try_from(v).ok()), }; Self { album, track } } } -impl MetadataTracker { - pub fn new(magpie: &mut MagpieClient, metadata: &mpris::Metadata) -> Self { +/*impl MetadataTracker { + pub fn new(magpie: &mut MagpieClient, metadata: &MetadataMap) -> Self { let new: Self = metadata.into(); magpie.send_json_message(0, &InMsg::AlbumChanged(new.album.clone())); magpie.send_json_message(0, &InMsg::TrackChanged(new.track.clone())); @@ -54,7 +60,7 @@ impl MetadataTracker { new } - pub fn update(&mut self, messenger: &mut MagpieClient, metadata: &mpris::Metadata) { + pub fn update(&mut self, messenger: &mut MagpieClient, metadata: &MetadataMap) { let new: Self = metadata.into(); if self.album != new.album { @@ -74,7 +80,7 @@ impl MetadataTracker { *self = new; } -} +}*/ fn main() { let args: Vec = std::env::args().collect(); @@ -83,16 +89,32 @@ fn main() { .expect("Please pass a path to a Canary script!") .to_owned(); - let player_finder = PlayerFinder::new().expect("Could not connect to D-Bus"); - let mut magpie = MagpieClient::new().unwrap(); - let protocol = "tebibyte-media.desktop.music-player-controller".to_string(); - let script = std::path::PathBuf::from(&module_path); - let msg = CreatePanel { id: 0, protocol, script }; - let msg = MagpieServerMsg::CreatePanel(msg); - magpie.messenger.send(&msg).unwrap(); - let mut first_loop = true; + let result: Result<(), Box> = smol::block_on(async { + let dbus = zbus::Connection::session().await?; + let player = PlayerProxy::new(&dbus).await?; + + let protocol = "tebibyte-media.desktop.music-player-controller".to_string(); + let script = std::path::PathBuf::from(&module_path); + let msg = CreatePanel { + id: 0, + protocol, + script, + }; + let msg = MagpieServerMsg::CreatePanel(msg); + magpie.messenger.send(&msg).unwrap(); + + std::future::pending::<()>().await; + + Ok(()) + }); + + if let Err(err) = result { + eprintln!("Music player error: {:?}", err); + } + + /*let mut first_loop = true; let mut connected = false; loop { @@ -183,5 +205,5 @@ fn main() { magpie.send_json_message(0, &msg); } } - } + }*/ } diff --git a/apps/music-player/src/mpris.rs b/apps/music-player/src/mpris.rs new file mode 100644 index 0000000..0402bcd --- /dev/null +++ b/apps/music-player/src/mpris.rs @@ -0,0 +1,25 @@ +use std::collections::HashMap; + +use zbus::zvariant::Value; +use zbus::{dbus_proxy, Result}; + +pub type MetadataMap<'a> = HashMap>; + +#[dbus_proxy(interface = "org.mpris.MediaPlayer2.Player")] +trait Player { + fn next(&self) -> Result<()>; + fn previous(&self) -> Result<()>; + fn pause(&self) -> Result<()>; + fn play_pause(&self) -> Result<()>; + fn stop(&self) -> Result<()>; + fn play(&self) -> Result<()>; + + #[dbus_proxy(property)] + fn playback_status(&self) -> Result; + + #[dbus_proxy(property)] + fn position(&self) -> Result; + + #[dbus_proxy(property)] + fn metadata(&self) -> Result; +} From a2432f77d2fcc94bdc3c6060647e287a49adbcbd Mon Sep 17 00:00:00 2001 From: mars Date: Sat, 19 Nov 2022 22:16:53 -0700 Subject: [PATCH 32/39] Find active player and listen for playback status changes --- apps/music-player/src/main.rs | 10 +++++++++- apps/music-player/src/mpris.rs | 26 ++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/apps/music-player/src/main.rs b/apps/music-player/src/main.rs index 23ad88e..6560590 100644 --- a/apps/music-player/src/main.rs +++ b/apps/music-player/src/main.rs @@ -8,6 +8,7 @@ use canary_music_player::*; pub mod mpris; use mpris::*; +use smol::stream::StreamExt; pub struct Metadata { pub album: AlbumInfo, @@ -93,7 +94,14 @@ fn main() { let result: Result<(), Box> = smol::block_on(async { let dbus = zbus::Connection::session().await?; - let player = PlayerProxy::new(&dbus).await?; + let player = find_player(&dbus).await?.unwrap(); + + let mut playback_status = player.receive_playback_status_changed().await; + while let Some(status) = playback_status.next().await { + println!("Status: {}", status.get().await?); + } + + println!("Done looping."); let protocol = "tebibyte-media.desktop.music-player-controller".to_string(); let script = std::path::PathBuf::from(&module_path); diff --git a/apps/music-player/src/mpris.rs b/apps/music-player/src/mpris.rs index 0402bcd..74e47c2 100644 --- a/apps/music-player/src/mpris.rs +++ b/apps/music-player/src/mpris.rs @@ -1,11 +1,15 @@ use std::collections::HashMap; +use zbus::fdo::DBusProxy; use zbus::zvariant::Value; -use zbus::{dbus_proxy, Result}; +use zbus::{dbus_proxy, Connection, Result}; pub type MetadataMap<'a> = HashMap>; -#[dbus_proxy(interface = "org.mpris.MediaPlayer2.Player")] +#[dbus_proxy( + interface = "org.mpris.MediaPlayer2.Player", + default_path = "/org/mpris/MediaPlayer2" +)] trait Player { fn next(&self) -> Result<()>; fn previous(&self) -> Result<()>; @@ -23,3 +27,21 @@ trait Player { #[dbus_proxy(property)] fn metadata(&self) -> Result; } + +pub async fn find_player(connection: &Connection) -> Result> { + let dbus = DBusProxy::new(connection).await?; + let names = dbus.list_names().await?; + + for name in names { + let name = name.as_str().to_string(); + if name.starts_with("org.mpris.MediaPlayer2") { + let player = PlayerProxy::builder(connection) + .destination(name)? + .build() + .await?; + return Ok(Some(player)); + } + } + + Ok(None) +} From 15f9c7ea992049460ab8aa4691fef1ceff0f2496 Mon Sep 17 00:00:00 2001 From: mars Date: Sat, 19 Nov 2022 22:57:33 -0700 Subject: [PATCH 33/39] Listen for multiple property changes --- apps/music-player/Cargo.toml | 3 ++- apps/music-player/src/main.rs | 29 +++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/apps/music-player/Cargo.toml b/apps/music-player/Cargo.toml index 36582b5..107df85 100644 --- a/apps/music-player/Cargo.toml +++ b/apps/music-player/Cargo.toml @@ -11,10 +11,11 @@ required-features = ["bin"] [dependencies] canary-magpie = { path = "../magpie", optional = true } +futures-util = { version = "0.3", optional = true } serde = { version = "1", features = ["derive"] } serde_json = "1" smol = { version = "1.2", optional = true } zbus = { version = "3.5", optional = true } [features] -bin = ["dep:canary-magpie", "dep:smol", "dep:zbus"] +bin = ["dep:canary-magpie", "dep:futures-util", "dep:smol", "dep:zbus"] diff --git a/apps/music-player/src/main.rs b/apps/music-player/src/main.rs index 6560590..4adce75 100644 --- a/apps/music-player/src/main.rs +++ b/apps/music-player/src/main.rs @@ -8,7 +8,6 @@ use canary_music_player::*; pub mod mpris; use mpris::*; -use smol::stream::StreamExt; pub struct Metadata { pub album: AlbumInfo, @@ -96,12 +95,30 @@ fn main() { let dbus = zbus::Connection::session().await?; let player = find_player(&dbus).await?.unwrap(); - let mut playback_status = player.receive_playback_status_changed().await; - while let Some(status) = playback_status.next().await { - println!("Status: {}", status.get().await?); - } + use futures_util::StreamExt; + let mut playback_status = player.receive_playback_status_changed().await.fuse(); + let mut metadata = player.receive_metadata_changed().await.fuse(); - println!("Done looping."); + loop { + futures_util::select! { + status = playback_status.next() => { + let status = match status { + Some(v) => v, + None => break, + }; + + println!("Status: {}", status.get().await?); + } + metadata = metadata.next() => { + let metadata = match metadata { + Some(v) => v, + None => break, + }; + + println!("Metadata: {:#?}", metadata.get().await?); + } + }; + } let protocol = "tebibyte-media.desktop.music-player-controller".to_string(); let script = std::path::PathBuf::from(&module_path); From 7e4900c59b386922e56dc88c80dcef307bea3422 Mon Sep 17 00:00:00 2001 From: mars Date: Sat, 19 Nov 2022 23:11:17 -0700 Subject: [PATCH 34/39] Parse metadata --- apps/music-player/src/main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/music-player/src/main.rs b/apps/music-player/src/main.rs index 4adce75..9f28d23 100644 --- a/apps/music-player/src/main.rs +++ b/apps/music-player/src/main.rs @@ -9,6 +9,7 @@ pub mod mpris; use mpris::*; +#[derive(Debug)] pub struct Metadata { pub album: AlbumInfo, pub track: TrackInfo, @@ -115,7 +116,10 @@ fn main() { None => break, }; - println!("Metadata: {:#?}", metadata.get().await?); + let map = metadata.get().await?.into(); + let metadata = Metadata::from(&map); + + println!("Metadata: {:#?}", metadata); } }; } From a65164d70b549082e14c8931a5669f2defd6998a Mon Sep 17 00:00:00 2001 From: mars Date: Sat, 19 Nov 2022 23:33:06 -0700 Subject: [PATCH 35/39] Music player lifetime loop --- apps/music-player/src/main.rs | 120 +++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 37 deletions(-) diff --git a/apps/music-player/src/main.rs b/apps/music-player/src/main.rs index 9f28d23..479f211 100644 --- a/apps/music-player/src/main.rs +++ b/apps/music-player/src/main.rs @@ -83,6 +83,41 @@ impl<'a> From<&MetadataMap<'a>> for Metadata { } }*/ +async fn player_main( + player: &PlayerProxy<'_>, + magpie: &mut MagpieClient, +) -> Result<(), Box> { + use futures_util::StreamExt; + let mut playback_status = player.receive_playback_status_changed().await.fuse(); + let mut metadata = player.receive_metadata_changed().await.fuse(); + + loop { + futures_util::select! { + status = playback_status.next() => { + let status = match status { + Some(v) => v, + None => break, + }; + + println!("Status: {}", status.get().await?); + } + metadata = metadata.next() => { + let metadata = match metadata { + Some(v) => v, + None => break, + }; + + let map = metadata.get().await?.into(); + let metadata = Metadata::from(&map); + + println!("Metadata: {:#?}", metadata); + } + }; + } + + Ok(()) +} + fn main() { let args: Vec = std::env::args().collect(); let module_path = args @@ -92,37 +127,8 @@ fn main() { let mut magpie = MagpieClient::new().unwrap(); - let result: Result<(), Box> = smol::block_on(async { - let dbus = zbus::Connection::session().await?; - let player = find_player(&dbus).await?.unwrap(); - - use futures_util::StreamExt; - let mut playback_status = player.receive_playback_status_changed().await.fuse(); - let mut metadata = player.receive_metadata_changed().await.fuse(); - - loop { - futures_util::select! { - status = playback_status.next() => { - let status = match status { - Some(v) => v, - None => break, - }; - - println!("Status: {}", status.get().await?); - } - metadata = metadata.next() => { - let metadata = match metadata { - Some(v) => v, - None => break, - }; - - let map = metadata.get().await?.into(); - let metadata = Metadata::from(&map); - - println!("Metadata: {:#?}", metadata); - } - }; - } + smol::block_on(async { + let dbus = zbus::Connection::session().await.unwrap(); let protocol = "tebibyte-media.desktop.music-player-controller".to_string(); let script = std::path::PathBuf::from(&module_path); @@ -134,15 +140,55 @@ fn main() { let msg = MagpieServerMsg::CreatePanel(msg); magpie.messenger.send(&msg).unwrap(); - std::future::pending::<()>().await; + let mut first_loop = true; + let mut connected = false; - Ok(()) + loop { + if !first_loop { + let wait = std::time::Duration::from_secs(1); + std::thread::sleep(wait); + } + + first_loop = false; + + if connected { + println!("Disconnected from MPRIS"); + let msg = InMsg::Disconnected; + magpie.send_json_message(0, &msg); + connected = false; + } + + println!("Connecting to MPRIS..."); + + let player = match find_player(&dbus).await { + Ok(Some(player)) => player, + Ok(None) => { + eprintln!("Couldn't find player"); + continue; + } + Err(err) => { + eprintln!("D-Bus error while finding player: {:?}", err); + return; + } + }; + + println!( + "Connected to \"{}\" ({})", + player.path().as_str(), + player.destination().as_str() + ); + connected = true; + magpie.send_json_message(0, &InMsg::Connected); + + match player_main(&player, &mut magpie).await { + Ok(()) => {} + Err(err) => { + eprintln!("D-Bus error while connected to player: {:?}", err); + } + } + } }); - if let Err(err) = result { - eprintln!("Music player error: {:?}", err); - } - /*let mut first_loop = true; let mut connected = false; From 13a9735bdcf9ad9c6a3226724d245bbe7c309311 Mon Sep 17 00:00:00 2001 From: mars Date: Sat, 19 Nov 2022 23:51:34 -0700 Subject: [PATCH 36/39] Update script playback status + metadata --- apps/music-player/src/main.rs | 52 ++++++++++++++++------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/apps/music-player/src/main.rs b/apps/music-player/src/main.rs index 479f211..b4a77f1 100644 --- a/apps/music-player/src/main.rs +++ b/apps/music-player/src/main.rs @@ -15,8 +15,8 @@ pub struct Metadata { pub track: TrackInfo, } -impl<'a> From<&MetadataMap<'a>> for Metadata { - fn from(map: &MetadataMap<'a>) -> Self { +impl<'a> From> for Metadata { + fn from(map: MetadataMap<'a>) -> Self { let album = AlbumInfo { title: map .get("xesam:album") @@ -46,22 +46,15 @@ impl<'a> From<&MetadataMap<'a>> for Metadata { } } -/*impl MetadataTracker { - pub fn new(magpie: &mut MagpieClient, metadata: &MetadataMap) -> Self { +impl Metadata { + pub fn new(magpie: &mut MagpieClient, metadata: MetadataMap) -> Self { let new: Self = metadata.into(); magpie.send_json_message(0, &InMsg::AlbumChanged(new.album.clone())); magpie.send_json_message(0, &InMsg::TrackChanged(new.track.clone())); - magpie.send_json_message( - 0, - &InMsg::ProgressChanged(ProgressChanged { - position: 0.0, - length: metadata.length().map(|l| l.as_secs_f32()), - }), - ); new } - pub fn update(&mut self, messenger: &mut MagpieClient, metadata: &MetadataMap) { + pub fn update(&mut self, messenger: &mut MagpieClient, metadata: MetadataMap) { let new: Self = metadata.into(); if self.album != new.album { @@ -70,18 +63,11 @@ impl<'a> From<&MetadataMap<'a>> for Metadata { if self.track != new.track { messenger.send_json_message(0, &InMsg::TrackChanged(new.track.clone())); - messenger.send_json_message( - 0, - &InMsg::ProgressChanged(ProgressChanged { - position: 0.0, - length: metadata.length().map(|l| l.as_secs_f32()), - }), - ); } *self = new; } -}*/ +} async fn player_main( player: &PlayerProxy<'_>, @@ -89,7 +75,9 @@ async fn player_main( ) -> Result<(), Box> { use futures_util::StreamExt; let mut playback_status = player.receive_playback_status_changed().await.fuse(); - let mut metadata = player.receive_metadata_changed().await.fuse(); + let mut metadata_tracker = player.receive_metadata_changed().await.fuse(); + + let mut metadata = Metadata::new(magpie, player.metadata().await?); loop { futures_util::select! { @@ -99,18 +87,26 @@ async fn player_main( None => break, }; - println!("Status: {}", status.get().await?); + let status = status.get().await?; + let status = match status.as_str() { + "Playing" => Some(PlaybackStatus::Playing), + "Paused" => Some(PlaybackStatus::Paused), + "Stopped" => Some(PlaybackStatus::Stopped), + _ => None, + }; + + if let Some(status) = status { + magpie.send_json_message(0, &InMsg::PlaybackStatusChanged(status)); + } } - metadata = metadata.next() => { - let metadata = match metadata { + new_metadata = metadata_tracker.next() => { + let new_metadata = match new_metadata { Some(v) => v, None => break, }; - let map = metadata.get().await?.into(); - let metadata = Metadata::from(&map); - - println!("Metadata: {:#?}", metadata); + let new_metadata = new_metadata.get().await?; + metadata.update(magpie, new_metadata); } }; } From 9eb2c1c4312adead7c81047aec838d9b1024efda Mon Sep 17 00:00:00 2001 From: mars Date: Sat, 19 Nov 2022 23:56:09 -0700 Subject: [PATCH 37/39] Remove old mpris comments --- apps/music-player/src/main.rs | 94 +---------------------------------- 1 file changed, 1 insertion(+), 93 deletions(-) diff --git a/apps/music-player/src/main.rs b/apps/music-player/src/main.rs index b4a77f1..dec15f9 100644 --- a/apps/music-player/src/main.rs +++ b/apps/music-player/src/main.rs @@ -81,6 +81,7 @@ async fn player_main( loop { futures_util::select! { + // TODO also update volume, shuffle status, and loop status status = playback_status.next() => { let status = match status { Some(v) => v, @@ -184,97 +185,4 @@ fn main() { } } }); - - /*let mut first_loop = true; - let mut connected = false; - - loop { - if !first_loop { - let wait = std::time::Duration::from_secs(1); - std::thread::sleep(wait); - } - - first_loop = false; - - if connected { - println!("Disconnected from MPRIS"); - let msg = InMsg::Disconnected; - magpie.send_json_message(0, &msg); - connected = false; - } - - println!("Connecting to MPRIS..."); - - let player = match player_finder.find_active() { - Ok(player) => player, - Err(err) => { - eprintln!("Couldn't find player: {:?}", err); - continue; - } - }; - - println!( - "Connected to \"{}\" ({})", - player.identity(), - player.bus_name() - ); - connected = true; - magpie.send_json_message(0, &InMsg::Connected); - - let metadata = player.get_metadata().unwrap(); - let mut metadata_tracker = MetadataTracker::new(&mut magpie, &metadata); - - let mut events = match player.events() { - Ok(events) => events, - Err(err) => { - eprintln!("Player events D-Bus error: {:?}", err); - continue; - } - }; - - loop { - let event = match events.next() { - None => break, - Some(Ok(e)) => e, - Some(Err(err)) => { - eprintln!("D-Bus error while reading player events: {:?}", err); - continue; - } - }; - - use mpris::Event::*; - let in_msg = match event { - Playing => Some(InMsg::PlaybackStatusChanged(PlaybackStatus::Playing)), - Paused => Some(InMsg::PlaybackStatusChanged(PlaybackStatus::Paused)), - Stopped => Some(InMsg::PlaybackStatusChanged(PlaybackStatus::Stopped)), - LoopingChanged(status) => { - use mpris::LoopStatus::*; - let status = match status { - None => LoopStatus::None, - Track => LoopStatus::Track, - Playlist => LoopStatus::Playlist, - }; - - Some(InMsg::LoopingChanged(status)) - } - ShuffleToggled(shuffle) => Some(InMsg::ShuffleChanged { shuffle }), - VolumeChanged(volume) => Some(InMsg::VolumeChanged { - volume: volume as f32, - }), - PlayerShutDown => None, - TrackChanged(ref metadata) => { - metadata_tracker.update(&mut magpie, metadata); - None - } - _ => { - eprintln!("Unhandled MPRIS message: {:?}", event); - None - } - }; - - if let Some(msg) = in_msg { - magpie.send_json_message(0, &msg); - } - } - }*/ } From 1fe366ce9f043561c43a3c9ea0b95205a414fa27 Mon Sep 17 00:00:00 2001 From: mars Date: Sun, 20 Nov 2022 00:00:21 -0700 Subject: [PATCH 38/39] Move progress length to TrackInfo --- apps/music-player/src/lib.rs | 8 ++++---- apps/music-player/src/main.rs | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/music-player/src/lib.rs b/apps/music-player/src/lib.rs index d3ecabb..e7cdd2b 100644 --- a/apps/music-player/src/lib.rs +++ b/apps/music-player/src/lib.rs @@ -34,9 +34,6 @@ pub enum LoopStatus { pub struct ProgressChanged { /// Current position into the track in seconds. pub position: f32, - - /// Length of the current track in seconds. - pub length: Option, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] @@ -48,7 +45,7 @@ pub struct AlbumInfo { pub artists: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct TrackInfo { /// The title of the current track. pub title: Option, @@ -58,6 +55,9 @@ pub struct TrackInfo { /// The optional track number on the disc the album the track appears on. pub track_number: Option, + + /// Length of the track in seconds. + pub length: Option, } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/apps/music-player/src/main.rs b/apps/music-player/src/main.rs index dec15f9..212cf68 100644 --- a/apps/music-player/src/main.rs +++ b/apps/music-player/src/main.rs @@ -40,6 +40,10 @@ impl<'a> From> for Metadata { track_number: map .get("xesam:trackNumber") .and_then(|v| TryFrom::try_from(v).ok()), + length: map + .get("xesam:length") + .and_then(|v| i64::try_from(v).ok()) + .map(|us| us as f32 / 1_000_000.0), // 1,000,000 microseconds in a second }; Self { album, track } From 2df2bd3f8fb11493443d625d04ac20f3fb74ea67 Mon Sep 17 00:00:00 2001 From: mars Date: Sun, 20 Nov 2022 00:00:43 -0700 Subject: [PATCH 39/39] Use new length position in SAO UI --- scripts/sao-ui/src/music_player.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/sao-ui/src/music_player.rs b/scripts/sao-ui/src/music_player.rs index f0e190c..d154599 100644 --- a/scripts/sao-ui/src/music_player.rs +++ b/scripts/sao-ui/src/music_player.rs @@ -336,17 +336,17 @@ impl MusicPlayerWidget { .map(|s| s.as_str()) .unwrap_or(""), ); + + if let Some(length) = info.length { + self.duration.set_text(&Self::format_time(length)); + } else { + self.duration.set_text("--:--"); + } } pub fn update_progress(&mut self, progress: ProgressChanged) { self.position_secs = progress.position; self.position_dirty = true; - - if let Some(length) = progress.length { - self.duration.set_text(&Self::format_time(length)); - } else { - self.duration.set_text("--:--"); - } } pub fn update_playback_status(&mut self, status: PlaybackStatus) {