ZIm/crates/theme/src/styles/players.rs
2025-03-31 20:55:27 +02:00

185 lines
6.1 KiB
Rust

#![allow(missing_docs)]
use gpui::Hsla;
use serde_derive::Deserialize;
use crate::{
PlayerColorContent, amber, blue, jade, lime, orange, pink, purple, red, try_parse_color,
};
#[derive(Debug, Clone, Copy, Deserialize, Default, PartialEq)]
pub struct PlayerColor {
pub cursor: Hsla,
pub background: Hsla,
pub selection: Hsla,
}
/// A collection of colors that are used to color players in the editor.
///
/// The first color is always the local player's color, usually a blue.
///
/// The rest of the default colors crisscross back and forth on the
/// color wheel so that the colors are as distinct as possible.
#[derive(Clone, Deserialize, PartialEq)]
pub struct PlayerColors(pub Vec<PlayerColor>);
impl Default for PlayerColors {
/// Don't use this!
/// We have to have a default to be `[refineable::Refinable]`.
/// TODO "Find a way to not need this for Refinable"
fn default() -> Self {
Self::dark()
}
}
impl PlayerColors {
pub fn dark() -> Self {
Self(vec![
PlayerColor {
cursor: blue().dark().step_9(),
background: blue().dark().step_5(),
selection: blue().dark().step_3(),
},
PlayerColor {
cursor: orange().dark().step_9(),
background: orange().dark().step_5(),
selection: orange().dark().step_3(),
},
PlayerColor {
cursor: pink().dark().step_9(),
background: pink().dark().step_5(),
selection: pink().dark().step_3(),
},
PlayerColor {
cursor: lime().dark().step_9(),
background: lime().dark().step_5(),
selection: lime().dark().step_3(),
},
PlayerColor {
cursor: purple().dark().step_9(),
background: purple().dark().step_5(),
selection: purple().dark().step_3(),
},
PlayerColor {
cursor: amber().dark().step_9(),
background: amber().dark().step_5(),
selection: amber().dark().step_3(),
},
PlayerColor {
cursor: jade().dark().step_9(),
background: jade().dark().step_5(),
selection: jade().dark().step_3(),
},
PlayerColor {
cursor: red().dark().step_9(),
background: red().dark().step_5(),
selection: red().dark().step_3(),
},
])
}
pub fn light() -> Self {
Self(vec![
PlayerColor {
cursor: blue().light().step_9(),
background: blue().light().step_4(),
selection: blue().light().step_3(),
},
PlayerColor {
cursor: orange().light().step_9(),
background: orange().light().step_4(),
selection: orange().light().step_3(),
},
PlayerColor {
cursor: pink().light().step_9(),
background: pink().light().step_4(),
selection: pink().light().step_3(),
},
PlayerColor {
cursor: lime().light().step_9(),
background: lime().light().step_4(),
selection: lime().light().step_3(),
},
PlayerColor {
cursor: purple().light().step_9(),
background: purple().light().step_4(),
selection: purple().light().step_3(),
},
PlayerColor {
cursor: amber().light().step_9(),
background: amber().light().step_4(),
selection: amber().light().step_3(),
},
PlayerColor {
cursor: jade().light().step_9(),
background: jade().light().step_4(),
selection: jade().light().step_3(),
},
PlayerColor {
cursor: red().light().step_9(),
background: red().light().step_4(),
selection: red().light().step_3(),
},
])
}
}
impl PlayerColors {
pub fn local(&self) -> PlayerColor {
*self.0.first().unwrap()
}
pub fn absent(&self) -> PlayerColor {
*self.0.last().unwrap()
}
pub fn read_only(&self) -> PlayerColor {
let local = self.local();
PlayerColor {
cursor: local.cursor.grayscale(),
background: local.background.grayscale(),
selection: local.selection.grayscale(),
}
}
pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
let len = self.0.len() - 1;
self.0[(participant_index as usize % len) + 1]
}
/// Merges the given player colors into this [`PlayerColors`] instance.
pub fn merge(&mut self, user_player_colors: &[PlayerColorContent]) {
if user_player_colors.is_empty() {
return;
}
for (idx, player) in user_player_colors.iter().enumerate() {
let cursor = player
.cursor
.as_ref()
.and_then(|color| try_parse_color(color).ok());
let background = player
.background
.as_ref()
.and_then(|color| try_parse_color(color).ok());
let selection = player
.selection
.as_ref()
.and_then(|color| try_parse_color(color).ok());
if let Some(player_color) = self.0.get_mut(idx) {
*player_color = PlayerColor {
cursor: cursor.unwrap_or(player_color.cursor),
background: background.unwrap_or(player_color.background),
selection: selection.unwrap_or(player_color.selection),
};
} else {
self.0.push(PlayerColor {
cursor: cursor.unwrap_or_default(),
background: background.unwrap_or_default(),
selection: selection.unwrap_or_default(),
});
}
}
}
}