players.rs

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