1#![allow(missing_docs)]
2
3use gpui::Hsla;
4use serde_derive::Deserialize;
5
6use crate::{PlayerColorContent, default::default_dark_theme, try_parse_color};
7
8#[derive(Debug, Clone, Copy, Deserialize, Default, PartialEq)]
9pub struct PlayerColor {
10 pub cursor: Hsla,
11 pub background: Hsla,
12 pub selection: Hsla,
13}
14
15/// A collection of colors that are used to color players in the editor.
16///
17/// The first color is always the local player's color, usually a blue.
18///
19/// The rest of the default colors crisscross back and forth on the
20/// color wheel so that the colors are as distinct as possible.
21#[derive(Clone, Debug, Deserialize, PartialEq)]
22pub struct PlayerColors(pub Vec<PlayerColor>);
23
24impl Default for PlayerColors {
25 /// Don't use this!
26 /// We have to have a default to be `[refineable::Refinable]`.
27 /// TODO "Find a way to not need this for Refinable"
28 fn default() -> Self {
29 default_dark_theme().players().clone()
30 }
31}
32
33impl PlayerColors {
34 pub fn local(&self) -> PlayerColor {
35 *self.0.first().unwrap()
36 }
37
38 pub fn agent(&self) -> PlayerColor {
39 *self.0.last().unwrap()
40 }
41
42 pub fn absent(&self) -> PlayerColor {
43 *self.0.last().unwrap()
44 }
45
46 pub fn read_only(&self) -> PlayerColor {
47 let local = self.local();
48 PlayerColor {
49 cursor: local.cursor.grayscale(),
50 background: local.background.grayscale(),
51 selection: local.selection.grayscale(),
52 }
53 }
54
55 pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
56 let len = self.0.len() - 1;
57 self.0[(participant_index as usize % len) + 1]
58 }
59
60 /// Merges the given player colors into this [`PlayerColors`] instance.
61 pub fn merge(&mut self, user_player_colors: &[PlayerColorContent]) {
62 if user_player_colors.is_empty() {
63 return;
64 }
65
66 for (idx, player) in user_player_colors.iter().enumerate() {
67 let cursor = player
68 .cursor
69 .as_ref()
70 .and_then(|color| try_parse_color(color).ok());
71 let background = player
72 .background
73 .as_ref()
74 .and_then(|color| try_parse_color(color).ok());
75 let selection = player
76 .selection
77 .as_ref()
78 .and_then(|color| try_parse_color(color).ok());
79
80 if let Some(player_color) = self.0.get_mut(idx) {
81 *player_color = PlayerColor {
82 cursor: cursor.unwrap_or(player_color.cursor),
83 background: background.unwrap_or(player_color.background),
84 selection: selection.unwrap_or(player_color.selection),
85 };
86 } else {
87 self.0.push(PlayerColor {
88 cursor: cursor.unwrap_or_default(),
89 background: background.unwrap_or_default(),
90 selection: selection.unwrap_or_default(),
91 });
92 }
93 }
94 }
95}