players.rs

  1#![allow(missing_docs)]
  2
  3use gpui::Hsla;
  4use serde_derive::Deserialize;
  5
  6use crate::{
  7    PlayerColorContent, amber, blue, jade, lime, orange, pink, purple, red, try_parse_color,
  8};
  9
 10#[derive(Debug, Clone, Copy, Deserialize, Default, PartialEq)]
 11pub struct PlayerColor {
 12    pub cursor: Hsla,
 13    pub background: Hsla,
 14    pub selection: Hsla,
 15}
 16
 17/// A collection of colors that are used to color players in the editor.
 18///
 19/// The first color is always the local player's color, usually a blue.
 20///
 21/// The rest of the default colors crisscross back and forth on the
 22/// color wheel so that the colors are as distinct as possible.
 23#[derive(Clone, Deserialize, PartialEq)]
 24pub struct PlayerColors(pub Vec<PlayerColor>);
 25
 26impl Default for PlayerColors {
 27    /// Don't use this!
 28    /// We have to have a default to be `[refineable::Refinable]`.
 29    /// TODO "Find a way to not need this for Refinable"
 30    fn default() -> Self {
 31        Self::dark()
 32    }
 33}
 34
 35impl PlayerColors {
 36    pub fn dark() -> Self {
 37        Self(vec![
 38            PlayerColor {
 39                cursor: blue().dark().step_9(),
 40                background: blue().dark().step_5(),
 41                selection: blue().dark().step_3(),
 42            },
 43            PlayerColor {
 44                cursor: orange().dark().step_9(),
 45                background: orange().dark().step_5(),
 46                selection: orange().dark().step_3(),
 47            },
 48            PlayerColor {
 49                cursor: pink().dark().step_9(),
 50                background: pink().dark().step_5(),
 51                selection: pink().dark().step_3(),
 52            },
 53            PlayerColor {
 54                cursor: lime().dark().step_9(),
 55                background: lime().dark().step_5(),
 56                selection: lime().dark().step_3(),
 57            },
 58            PlayerColor {
 59                cursor: purple().dark().step_9(),
 60                background: purple().dark().step_5(),
 61                selection: purple().dark().step_3(),
 62            },
 63            PlayerColor {
 64                cursor: amber().dark().step_9(),
 65                background: amber().dark().step_5(),
 66                selection: amber().dark().step_3(),
 67            },
 68            PlayerColor {
 69                cursor: jade().dark().step_9(),
 70                background: jade().dark().step_5(),
 71                selection: jade().dark().step_3(),
 72            },
 73            PlayerColor {
 74                cursor: red().dark().step_9(),
 75                background: red().dark().step_5(),
 76                selection: red().dark().step_3(),
 77            },
 78        ])
 79    }
 80
 81    pub fn light() -> Self {
 82        Self(vec![
 83            PlayerColor {
 84                cursor: blue().light().step_9(),
 85                background: blue().light().step_4(),
 86                selection: blue().light().step_3(),
 87            },
 88            PlayerColor {
 89                cursor: orange().light().step_9(),
 90                background: orange().light().step_4(),
 91                selection: orange().light().step_3(),
 92            },
 93            PlayerColor {
 94                cursor: pink().light().step_9(),
 95                background: pink().light().step_4(),
 96                selection: pink().light().step_3(),
 97            },
 98            PlayerColor {
 99                cursor: lime().light().step_9(),
100                background: lime().light().step_4(),
101                selection: lime().light().step_3(),
102            },
103            PlayerColor {
104                cursor: purple().light().step_9(),
105                background: purple().light().step_4(),
106                selection: purple().light().step_3(),
107            },
108            PlayerColor {
109                cursor: amber().light().step_9(),
110                background: amber().light().step_4(),
111                selection: amber().light().step_3(),
112            },
113            PlayerColor {
114                cursor: jade().light().step_9(),
115                background: jade().light().step_4(),
116                selection: jade().light().step_3(),
117            },
118            PlayerColor {
119                cursor: red().light().step_9(),
120                background: red().light().step_4(),
121                selection: red().light().step_3(),
122            },
123        ])
124    }
125}
126
127impl PlayerColors {
128    pub fn local(&self) -> PlayerColor {
129        *self.0.first().unwrap()
130    }
131
132    pub fn absent(&self) -> PlayerColor {
133        *self.0.last().unwrap()
134    }
135
136    pub fn read_only(&self) -> PlayerColor {
137        let local = self.local();
138        PlayerColor {
139            cursor: local.cursor.grayscale(),
140            background: local.background.grayscale(),
141            selection: local.selection.grayscale(),
142        }
143    }
144
145    pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
146        let len = self.0.len() - 1;
147        self.0[(participant_index as usize % len) + 1]
148    }
149
150    /// Merges the given player colors into this [`PlayerColors`] instance.
151    pub fn merge(&mut self, user_player_colors: &[PlayerColorContent]) {
152        if user_player_colors.is_empty() {
153            return;
154        }
155
156        for (idx, player) in user_player_colors.iter().enumerate() {
157            let cursor = player
158                .cursor
159                .as_ref()
160                .and_then(|color| try_parse_color(color).ok());
161            let background = player
162                .background
163                .as_ref()
164                .and_then(|color| try_parse_color(color).ok());
165            let selection = player
166                .selection
167                .as_ref()
168                .and_then(|color| try_parse_color(color).ok());
169
170            if let Some(player_color) = self.0.get_mut(idx) {
171                *player_color = PlayerColor {
172                    cursor: cursor.unwrap_or(player_color.cursor),
173                    background: background.unwrap_or(player_color.background),
174                    selection: selection.unwrap_or(player_color.selection),
175                };
176            } else {
177                self.0.push(PlayerColor {
178                    cursor: cursor.unwrap_or_default(),
179                    background: background.unwrap_or_default(),
180                    selection: selection.unwrap_or_default(),
181                });
182            }
183        }
184    }
185}