1use crate::component::ChatComponent;
2
3#[cfg(feature = "serde")]
4use serde::Deserialize;
5#[cfg(feature = "serde")]
6mod serde_support;
7
8pub const VERSION_1_7: u32 = 4;
10pub const VERSION_1_8: u32 = 47;
12pub const VERSION_1_15: u32 = 573;
14pub const VERSION_1_16: u32 = 735;
16
17#[derive(Clone, Debug)]
19#[cfg_attr(feature = "serde", derive(Deserialize))]
20pub struct ComponentStyle {
21 #[cfg_attr(
22 feature = "serde",
23 serde(skip, default = "serde_support::default_style_version")
24 )]
25 version: u32,
26 bold: Option<bool>,
27 italic: Option<bool>,
28 underlined: Option<bool>,
29 strikethrough: Option<bool>,
30 obfuscated: Option<bool>,
31 color: Option<ChatColor>,
32 insertion: Option<String>,
34 font: Option<String>,
36 #[cfg_attr(feature = "serde", serde(rename = "clickEvent"))]
37 click_event: Option<ClickEvent>,
38 #[cfg_attr(feature = "serde", serde(rename = "hoverEvent"))]
39 hover_event: Option<HoverEvent>,
40}
41
42impl ComponentStyle {
43 pub fn v1_7() -> Self {
44 ComponentStyle::with_version(4)
45 }
46
47 pub fn v1_8() -> Self {
48 ComponentStyle::with_version(47)
49 }
50
51 pub fn v1_15() -> Self {
52 ComponentStyle::with_version(573)
53 }
54
55 pub fn v1_16() -> Self {
56 ComponentStyle::with_version(735)
57 }
58
59 pub fn with_version(version: u32) -> Self {
60 ComponentStyle {
61 version,
62 bold: None,
63 italic: None,
64 underlined: None,
65 strikethrough: None,
66 obfuscated: None,
67 color: None,
68 insertion: None,
69 font: None,
70 click_event: None,
71 hover_event: None,
72 }
73 }
74
75 pub fn set_color(&mut self, color: Option<ChatColor>) {
76 self.color = color;
77 }
78
79 pub fn color(mut self, color: Option<ChatColor>) -> Self {
80 self.set_color(color);
81 self
82 }
83
84 pub fn set_color_if_absent(&mut self, color: ChatColor) {
85 if self.color.is_none() {
86 self.color = Some(color);
87 }
88 }
89
90 pub fn color_if_absent(mut self, color: ChatColor) -> Self {
91 self.set_color_if_absent(color);
92 self
93 }
94
95 pub fn set_bold(&mut self, bold: bool) {
96 self.bold = Some(bold);
97 }
98
99 pub fn bold(mut self, bold: bool) -> Self {
100 self.set_bold(bold);
101 self
102 }
103
104 pub fn set_italic(&mut self, italic: bool) {
105 self.italic = Some(italic);
106 }
107
108 pub fn italic(mut self, italic: bool) -> Self {
109 self.set_italic(italic);
110 self
111 }
112
113 pub fn set_underlined(&mut self, underlined: bool) {
114 self.underlined = Some(underlined);
115 }
116
117 pub fn underlined(mut self, underlined: bool) -> Self {
118 self.set_underlined(underlined);
119 self
120 }
121
122 pub fn set_strikethrough(&mut self, strikethrough: bool) {
123 self.strikethrough = Some(strikethrough);
124 }
125
126 pub fn strikethrough(mut self, strikethrough: bool) -> Self {
127 self.set_strikethrough(strikethrough);
128 self
129 }
130
131 pub fn set_obfuscated(&mut self, obfuscated: bool) {
132 self.obfuscated = Some(obfuscated);
133 }
134
135 pub fn obfuscated(mut self, obfuscated: bool) -> Self {
136 self.set_obfuscated(obfuscated);
137 self
138 }
139
140 pub fn set_font<T: Into<String>>(&mut self, font: Option<T>) {
141 self.font = font.map(|font| font.into());
142 }
143
144 pub fn font<T: Into<String>>(mut self, font: Option<T>) -> Self {
145 self.set_font(font);
146 self
147 }
148
149 pub fn set_insertion<T: Into<String>>(&mut self, insertion: Option<T>) {
150 self.insertion = insertion.map(|insertion| insertion.into());
151 }
152
153 pub fn insertion<T: Into<String>>(mut self, insertion: Option<T>) -> Self {
154 self.set_insertion(insertion);
155 self
156 }
157
158 pub fn set_click_event(&mut self, click_event: Option<ClickEvent>) {
159 self.click_event = click_event;
160 }
161
162 pub fn click_event(mut self, click_event: Option<ClickEvent>) -> Self {
163 self.set_click_event(click_event);
164 self
165 }
166
167 pub fn set_hover_event(&mut self, hover_event: Option<HoverEvent>) {
168 self.hover_event = hover_event;
169 }
170
171 pub fn hover_event(mut self, hover_event: Option<HoverEvent>) -> Self {
172 self.set_hover_event(hover_event);
173 self
174 }
175
176 pub fn get_color(&self) -> Option<&ChatColor> {
177 self.color.as_ref()
178 }
179
180 pub fn get_bold(&self) -> Option<bool> {
181 self.bold
182 }
183
184 pub fn get_italic(&self) -> Option<bool> {
185 self.italic
186 }
187
188 pub fn get_underlined(&self) -> Option<bool> {
189 self.underlined
190 }
191
192 pub fn get_strikethrough(&self) -> Option<bool> {
193 self.strikethrough
194 }
195
196 pub fn get_obfuscated(&self) -> Option<bool> {
197 self.obfuscated
198 }
199
200 pub fn get_font(&self) -> Option<&String> {
201 if self.version >= 713 {
202 self.font.as_ref()
203 } else {
204 None
205 }
206 }
207
208 pub fn get_insertion(&self) -> Option<&String> {
209 if self.version >= 5 {
210 self.insertion.as_ref()
211 } else {
212 None
213 }
214 }
215
216 pub fn get_click_event(&self) -> Option<&ClickEvent> {
217 self.click_event.as_ref()
218 }
219
220 pub fn get_hover_event(&self) -> Option<&HoverEvent> {
221 self.hover_event.as_ref()
222 }
223
224 pub fn change_version(&mut self, to: u32) {
225 self.version = to;
226 }
227
228 pub fn reset(&mut self) {
230 self.bold = None;
231 self.italic = None;
232 self.underlined = None;
233 self.strikethrough = None;
234 self.obfuscated = None;
235 self.color = None;
236 self.insertion = None;
237 self.font = None;
238 self.click_event = None;
239 self.hover_event = None;
240 }
241}
242
243#[derive(Clone, Debug)]
247pub enum ChatColor {
248 Black,
249 DarkBlue,
250 DarkGreen,
251 DarkCyan,
252 DarkRed,
253 Purple,
254 Gold,
255 Gray,
256 DarkGray,
257 Blue,
258 Green,
259 Cyan,
260 Red,
261 Pink,
262 Yellow,
263 White,
264 Custom(String),
268 Reset,
269}
270
271impl ChatColor {
272 pub fn custom<T: Into<String>>(color: T) -> ChatColor {
273 ChatColor::Custom(color.into())
274 }
275}
276
277#[derive(Clone, Debug)]
279#[cfg_attr(feature = "serde", derive(Deserialize))]
280#[cfg_attr(feature = "serde", serde(try_from = "serde_support::ClickEventData"))]
281pub enum ClickEvent {
282 OpenUrl(String),
283 RunCommand(String),
284 SuggestCommand(String),
285 ChangePage(u32),
286 CopyToClipBoard(String),
288}
289
290impl ClickEvent {
291 pub fn url<T: Into<String>>(url: T) -> Self {
292 Self::OpenUrl(url.into())
293 }
294
295 pub fn run_command<T: Into<String>>(cmd: T) -> Self {
296 Self::RunCommand(cmd.into())
297 }
298
299 pub fn suggest_command<T: Into<String>>(cmd: T) -> Self {
300 Self::SuggestCommand(cmd.into())
301 }
302
303 pub fn page<T: Into<u32>>(page: T) -> Self {
304 Self::ChangePage(page.into())
305 }
306
307 pub fn clipboard<T: Into<String>>(str: T) -> Self {
308 Self::CopyToClipBoard(str.into())
309 }
310}
311
312#[derive(Clone, Debug)]
317#[cfg_attr(feature = "serde", derive(Deserialize))]
318#[cfg_attr(feature = "serde", serde(try_from = "serde_support::HoverEventData"))]
319pub enum HoverEvent {
320 ShowText(Box<ChatComponent>),
321 ShowItem(String),
322 ShowEntity(String),
323}