players.rs

 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}