players.rs

  1use gpui::Hsla;
  2use serde_derive::Deserialize;
  3
  4use crate::{
  5    amber, blue, jade, lime, orange, pink, purple, red, try_parse_color, PlayerColorContent,
  6};
  7
  8#[derive(Debug, Clone, Copy, Deserialize, Default)]
  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, Deserialize)]
 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        Self::dark()
 30    }
 31}
 32
 33impl PlayerColors {
 34    pub fn dark() -> Self {
 35        Self(vec![
 36            PlayerColor {
 37                cursor: blue().dark().step_9(),
 38                background: blue().dark().step_5(),
 39                selection: blue().dark().step_3(),
 40            },
 41            PlayerColor {
 42                cursor: orange().dark().step_9(),
 43                background: orange().dark().step_5(),
 44                selection: orange().dark().step_3(),
 45            },
 46            PlayerColor {
 47                cursor: pink().dark().step_9(),
 48                background: pink().dark().step_5(),
 49                selection: pink().dark().step_3(),
 50            },
 51            PlayerColor {
 52                cursor: lime().dark().step_9(),
 53                background: lime().dark().step_5(),
 54                selection: lime().dark().step_3(),
 55            },
 56            PlayerColor {
 57                cursor: purple().dark().step_9(),
 58                background: purple().dark().step_5(),
 59                selection: purple().dark().step_3(),
 60            },
 61            PlayerColor {
 62                cursor: amber().dark().step_9(),
 63                background: amber().dark().step_5(),
 64                selection: amber().dark().step_3(),
 65            },
 66            PlayerColor {
 67                cursor: jade().dark().step_9(),
 68                background: jade().dark().step_5(),
 69                selection: jade().dark().step_3(),
 70            },
 71            PlayerColor {
 72                cursor: red().dark().step_9(),
 73                background: red().dark().step_5(),
 74                selection: red().dark().step_3(),
 75            },
 76        ])
 77    }
 78
 79    pub fn light() -> Self {
 80        Self(vec![
 81            PlayerColor {
 82                cursor: blue().light().step_9(),
 83                background: blue().light().step_4(),
 84                selection: blue().light().step_3(),
 85            },
 86            PlayerColor {
 87                cursor: orange().light().step_9(),
 88                background: orange().light().step_4(),
 89                selection: orange().light().step_3(),
 90            },
 91            PlayerColor {
 92                cursor: pink().light().step_9(),
 93                background: pink().light().step_4(),
 94                selection: pink().light().step_3(),
 95            },
 96            PlayerColor {
 97                cursor: lime().light().step_9(),
 98                background: lime().light().step_4(),
 99                selection: lime().light().step_3(),
100            },
101            PlayerColor {
102                cursor: purple().light().step_9(),
103                background: purple().light().step_4(),
104                selection: purple().light().step_3(),
105            },
106            PlayerColor {
107                cursor: amber().light().step_9(),
108                background: amber().light().step_4(),
109                selection: amber().light().step_3(),
110            },
111            PlayerColor {
112                cursor: jade().light().step_9(),
113                background: jade().light().step_4(),
114                selection: jade().light().step_3(),
115            },
116            PlayerColor {
117                cursor: red().light().step_9(),
118                background: red().light().step_4(),
119                selection: red().light().step_3(),
120            },
121        ])
122    }
123}
124
125impl PlayerColors {
126    pub fn local(&self) -> PlayerColor {
127        *self.0.first().unwrap()
128    }
129
130    pub fn absent(&self) -> PlayerColor {
131        *self.0.last().unwrap()
132    }
133
134    pub fn read_only(&self) -> PlayerColor {
135        let local = self.local();
136        PlayerColor {
137            cursor: local.cursor.grayscale(),
138            background: local.background.grayscale(),
139            selection: local.selection.grayscale(),
140        }
141    }
142
143    pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
144        let len = self.0.len() - 1;
145        self.0[(participant_index as usize % len) + 1]
146    }
147
148    /// Merges the given player colors into this [`PlayerColors`] instance.
149    pub fn merge(&mut self, user_player_colors: &[PlayerColorContent]) {
150        if user_player_colors.is_empty() {
151            return;
152        }
153
154        for (idx, player) in user_player_colors.iter().enumerate() {
155            let cursor = player
156                .cursor
157                .as_ref()
158                .and_then(|color| try_parse_color(color).ok());
159            let background = player
160                .background
161                .as_ref()
162                .and_then(|color| try_parse_color(color).ok());
163            let selection = player
164                .selection
165                .as_ref()
166                .and_then(|color| try_parse_color(color).ok());
167
168            if let Some(player_color) = self.0.get_mut(idx) {
169                *player_color = PlayerColor {
170                    cursor: cursor.unwrap_or(player_color.cursor),
171                    background: background.unwrap_or(player_color.background),
172                    selection: selection.unwrap_or(player_color.selection),
173                };
174            } else {
175                self.0.push(PlayerColor {
176                    cursor: cursor.unwrap_or_default(),
177                    background: background.unwrap_or_default(),
178                    selection: selection.unwrap_or_default(),
179                });
180            }
181        }
182    }
183}