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, Debug, 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 agent(&self) -> PlayerColor {
133        *self.0.last().unwrap()
134    }
135
136    pub fn absent(&self) -> PlayerColor {
137        *self.0.last().unwrap()
138    }
139
140    pub fn read_only(&self) -> PlayerColor {
141        let local = self.local();
142        PlayerColor {
143            cursor: local.cursor.grayscale(),
144            background: local.background.grayscale(),
145            selection: local.selection.grayscale(),
146        }
147    }
148
149    pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
150        let len = self.0.len() - 1;
151        self.0[(participant_index as usize % len) + 1]
152    }
153
154    /// Merges the given player colors into this [`PlayerColors`] instance.
155    pub fn merge(&mut self, user_player_colors: &[PlayerColorContent]) {
156        if user_player_colors.is_empty() {
157            return;
158        }
159
160        for (idx, player) in user_player_colors.iter().enumerate() {
161            let cursor = player
162                .cursor
163                .as_ref()
164                .and_then(|color| try_parse_color(color).ok());
165            let background = player
166                .background
167                .as_ref()
168                .and_then(|color| try_parse_color(color).ok());
169            let selection = player
170                .selection
171                .as_ref()
172                .and_then(|color| try_parse_color(color).ok());
173
174            if let Some(player_color) = self.0.get_mut(idx) {
175                *player_color = PlayerColor {
176                    cursor: cursor.unwrap_or(player_color.cursor),
177                    background: background.unwrap_or(player_color.background),
178                    selection: selection.unwrap_or(player_color.selection),
179                };
180            } else {
181                self.0.push(PlayerColor {
182                    cursor: cursor.unwrap_or_default(),
183                    background: background.unwrap_or_default(),
184                    selection: selection.unwrap_or_default(),
185                });
186            }
187        }
188    }
189}