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}