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}