1use serde::{Serialize, Serializer};
5
6use super::data::MenuEntry;
7
8macro_rules! string_enum {
10 ($(#[$m:meta])* $name:ident { $($(#[$vm:meta])* $var:ident = $s:literal),* $(,)? }) => {
11 $(#[$m])*
12 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
13 pub enum $name {
14 $($(#[$vm])* $var,)*
15 Other(String),
17 }
18
19 impl $name {
20 pub fn as_str(&self) -> &str {
22 match self {
23 $(Self::$var => $s,)*
24 Self::Other(s) => s,
25 }
26 }
27 }
28
29 impl From<&str> for $name {
30 fn from(s: &str) -> Self {
31 match s {
32 $($s => Self::$var,)*
33 _ => Self::Other(s.to_owned()),
34 }
35 }
36 }
37
38 impl From<String> for $name {
39 fn from(s: String) -> Self {
40 Self::from(s.as_str())
41 }
42 }
43
44 impl ::std::fmt::Display for $name {
45 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
46 f.write_str(self.as_str())
47 }
48 }
49
50 impl ::serde::Serialize for $name {
51 fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
52 s.serialize_str(self.as_str())
53 }
54 }
55 };
56}
57
58pub(crate) use string_enum;
59
60string_enum!(
61 Tone {
63 Neutral = "neutral",
65 Accent = "accent",
67 Info = "info",
69 Success = "success",
71 Warning = "warning",
73 Error = "error",
75 Pending = "pending",
77 Muted = "muted",
79 User = "user",
81 }
82);
83
84string_enum!(
85 Status {
87 Pending = "pending",
89 Running = "running",
91 Done = "done",
93 Error = "error",
95 Cancelled = "cancelled",
97 Ask = "ask",
99 }
100);
101
102string_enum!(
103 AgentStatus {
105 Pending = "pending",
107 Running = "running",
109 Done = "done",
111 Failed = "failed",
113 Aborted = "aborted",
115 Idle = "idle",
117 Parked = "parked",
119 }
120);
121
122string_enum!(
123 Mark {
125 Pick = "pick",
127 Drop = "drop",
129 }
130);
131
132string_enum!(
133 Gap {
135 None = "none",
137 Xs = "xs",
139 Sm = "sm",
141 Md = "md",
143 Lg = "lg",
145 }
146);
147
148string_enum!(
149 Align {
151 Start = "start",
153 Center = "center",
155 End = "end",
157 Baseline = "baseline",
159 Stretch = "stretch",
161 }
162);
163
164string_enum!(
165 Justify {
167 Between = "between",
169 End = "end",
171 }
172);
173
174string_enum!(
175 Wrap {
177 Word = "word",
179 Char = "char",
181 None = "none",
183 }
184);
185
186string_enum!(
187 Truncate {
189 End = "end",
191 Start = "start",
193 Middle = "middle",
195 }
196);
197
198string_enum!(
199 TextAlign {
201 Start = "start",
203 Center = "center",
205 End = "end",
207 }
208);
209
210string_enum!(
211 Fx {
213 Shimmer = "shimmer",
215 Pulse = "pulse",
217 None = "none",
219 }
220);
221
222string_enum!(
223 Token {
226 Muted = "muted",
228 Dim = "dim",
230 Strong = "strong",
232 Em = "em",
234 Accent = "accent",
236 Success = "success",
238 Warning = "warning",
240 Error = "error",
242 Info = "info",
244 Pending = "pending",
246 Code = "code",
248 Mono = "mono",
250 Path = "path",
252 Key = "key",
254 Link = "link",
256 Num = "num",
258 Ins = "ins",
260 Del = "del",
262 Mark = "mark",
264 Typo = "typo",
266 Icon = "icon",
268 Hide = "hide",
270 Title = "title",
272 }
273);
274
275string_enum!(
276 SpinnerStyle {
278 Braille = "braille",
280 Dots = "dots",
282 Starburst = "starburst",
284 Orbit = "orbit",
286 }
287);
288
289string_enum!(
290 ShimmerMode {
292 Classic = "classic",
294 Kitt = "kitt",
296 }
297);
298
299string_enum!(
300 ElapsedFormat {
302 Short = "short",
304 Clock = "clock",
306 }
307);
308
309string_enum!(
310 MeterStyle {
312 Bar = "bar",
314 Ring = "ring",
316 Blocks = "blocks",
318 }
319);
320
321string_enum!(
322 Size {
324 Sm = "sm",
326 Md = "md",
328 Lg = "lg",
330 }
331);
332
333string_enum!(
334 ChartKind {
336 Heatmap = "heatmap",
338 Bars = "bars",
340 Spark = "spark",
342 Line = "line",
344 Area = "area",
346 Donut = "donut",
348 }
349);
350
351string_enum!(
352 EffortLevel {
354 Off = "off",
356 Minimal = "minimal",
358 Low = "low",
360 Medium = "medium",
362 High = "high",
364 Xhigh = "xhigh",
366 Max = "max",
368 }
369);
370
371string_enum!(
372 DiffMode {
374 Unified = "unified",
376 Split = "split",
378 Auto = "auto",
380 }
381);
382
383string_enum!(
384 KvLayout {
386 Grid = "grid",
388 Inline = "inline",
390 }
391);
392
393string_enum!(
394 Measure {
396 Prose = "prose",
398 }
399);
400
401string_enum!(
402 CardVariant {
404 Bare = "bare",
406 }
407);
408
409string_enum!(
410 ButtonVariant {
412 Default = "default",
414 Primary = "primary",
416 Quiet = "quiet",
418 Danger = "danger",
420 }
421);
422
423string_enum!(
424 ButtonSize {
426 Sm = "sm",
428 Md = "md",
430 }
431);
432
433string_enum!(
434 TabsVariant {
436 Underline = "underline",
438 Segmented = "segmented",
440 }
441);
442
443#[derive(Clone, Debug, PartialEq, Eq)]
446pub enum Disabled {
447 Flag(bool),
449 Reason(String),
451}
452
453impl Serialize for Disabled {
454 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
455 match self {
456 Self::Flag(b) => s.serialize_bool(*b),
457 Self::Reason(r) => s.serialize_str(r),
458 }
459 }
460}
461
462impl From<bool> for Disabled {
463 fn from(b: bool) -> Self {
464 Self::Flag(b)
465 }
466}
467
468impl From<&str> for Disabled {
469 fn from(r: &str) -> Self {
470 Self::Reason(r.to_owned())
471 }
472}
473
474impl From<String> for Disabled {
475 fn from(r: String) -> Self {
476 Self::Reason(r)
477 }
478}
479
480string_enum!(
481 PickerSize {
483 Md = "md",
485 Lg = "lg",
487 Screen = "screen",
489 }
490);
491
492string_enum!(
493 PickerLayout {
495 Rows = "rows",
497 Cards = "cards",
499 Timeline = "timeline",
501 Tree = "tree",
503 }
504);
505
506string_enum!(
507 PickerPreview {
509 Side = "side",
511 Below = "below",
513 None = "none",
515 }
516);
517
518string_enum!(
519 PickerFocus {
521 List = "list",
523 Scopes = "scopes",
525 Tabs = "tabs",
527 Strip = "strip",
529 Preview = "preview",
531 }
532);
533
534string_enum!(
535 PickerState {
537 Ready = "ready",
539 Loading = "loading",
541 Error = "error",
543 }
544);
545
546string_enum!(
547 TargetKind {
549 Command = "command",
551 Path = "path",
553 Pattern = "pattern",
555 Query = "query",
557 Text = "text",
559 }
560);
561
562string_enum!(
563 ToolFrame {
565 Card = "card",
567 Inline = "inline",
569 }
570);
571
572string_enum!(
573 ChecklistMode {
575 Full = "full",
577 Hud = "hud",
579 Reminder = "reminder",
581 }
582);
583
584string_enum!(
585 ItemStatus {
587 Pending = "pending",
589 Active = "active",
591 Done = "done",
593 Dropped = "dropped",
595 Blocked = "blocked",
597 }
598);
599
600string_enum!(
601 OverlaySize {
603 Sm = "sm",
605 Md = "md",
607 Lg = "lg",
609 Full = "full",
611 }
612);
613
614string_enum!(
615 Side {
617 Right = "right",
619 }
620);
621
622string_enum!(
623 ColumnFormat {
625 Text = "text",
627 Num = "num",
629 Price = "price",
631 Bar = "bar",
633 Time = "time",
635 Elapsed = "elapsed",
637 Dim = "dim",
639 }
640);
641
642string_enum!(
643 ChoiceStyle {
645 Auto = "auto",
647 Segmented = "segmented",
649 Menu = "menu",
651 }
652);
653
654string_enum!(
655 InputType {
657 Checkbox = "checkbox",
659 Radio = "radio",
661 }
662);
663
664string_enum!(
665 InputVariant {
667 Well = "well",
669 Field = "field",
671 }
672);
673
674string_enum!(
675 OverlaySide {
677 Right = "right",
679 Left = "left",
681 Bottom = "bottom",
683 }
684);
685
686string_enum!(
687 OverlayVariant {
689 Edge = "edge",
691 Inset = "inset",
693 }
694);
695
696string_enum!(
697 RuleVariant {
699 Line = "line",
701 Note = "note",
703 Pin = "pin",
705 }
706);
707
708string_enum!(
709 CiteStyle {
711 Chip = "chip",
713 Pill = "pill",
715 Note = "note",
717 }
718);
719
720string_enum!(
721 SortDir {
723 Asc = "asc",
725 Desc = "desc",
727 }
728);
729
730string_enum!(
731 TableVariant {
733 Check = "check",
735 Bar = "bar",
737 }
738);
739
740string_enum!(
741 ToolConfirm {
743 Card = "card",
745 Strip = "strip",
747 Scopes = "scopes",
749 }
750);
751
752string_enum!(
753 Approved {
755 Once = "once",
757 Session = "session",
759 Always = "always",
761 Denied = "denied",
763 }
764);
765
766string_enum!(
767 SelectVariant {
769 Field = "field",
771 Quiet = "quiet",
773 }
774);
775
776string_enum!(
777 SwitchVariant {
779 Default = "default",
781 Compact = "compact",
783 Segment = "segment",
785 }
786);
787
788string_enum!(
789 SliderVariant {
791 Default = "default",
793 Accent = "accent",
795 }
796);
797
798string_enum!(
799 SliderFormat {
801 Number = "number",
803 Percent = "percent",
805 Duration = "duration",
807 }
808);
809
810string_enum!(
811 FieldVariant {
813 Stacked = "stacked",
815 Row = "row",
817 Grid = "grid",
819 }
820);
821
822string_enum!(
823 OtpVariant {
825 Cells = "cells",
827 Joined = "joined",
829 Underline = "underline",
831 }
832);
833
834string_enum!(
835 OtpState {
837 Error = "error",
839 Success = "success",
841 }
842);
843
844string_enum!(
845 ButtonsVariant {
847 Joined = "joined",
849 Split = "split",
851 Toolbar = "toolbar",
853 }
854);
855
856string_enum!(
857 AvatarVariant {
859 Circle = "circle",
861 Square = "square",
863 }
864);
865
866string_enum!(
867 AvatarSize {
869 Xs = "xs",
871 Sm = "sm",
873 Md = "md",
875 Lg = "lg",
877 }
878);
879
880string_enum!(
881 BreadcrumbVariant {
883 Chevron = "chevron",
885 Path = "path",
887 }
888);
889
890string_enum!(
891 PagerVariant {
893 Range = "range",
895 Pages = "pages",
897 More = "more",
899 }
900);
901
902string_enum!(
903 EmptyVariant {
905 Center = "center",
907 Inline = "inline",
909 Drop = "drop",
911 }
912);
913
914string_enum!(
915 SkeletonVariant {
917 Shimmer = "shimmer",
919 Pulse = "pulse",
921 Wire = "wire",
923 }
924);
925
926string_enum!(
927 SkeletonShape {
929 Text = "text",
931 Avatar = "avatar",
933 Rows = "rows",
935 Card = "card",
937 Block = "block",
939 }
940);
941
942string_enum!(
943 CalendarVariant {
945 Month = "month",
947 Week = "week",
949 }
950);
951
952string_enum!(
953 WeekStart {
955 Mon = "mon",
957 Sun = "sun",
959 }
960);
961
962string_enum!(
963 MenuVariant {
965 Default = "default",
967 Dense = "dense",
969 }
970);
971
972string_enum!(
973 MenuAlign {
975 Start = "start",
977 End = "end",
979 }
980);
981
982string_enum!(
983 MenubarVariant {
985 Strip = "strip",
987 Pill = "pill",
989 }
990);
991
992string_enum!(
993 NavVariant {
995 Pills = "pills",
997 Links = "links",
999 }
1000);
1001
1002string_enum!(
1003 SplitVariant {
1005 Hairline = "hairline",
1007 Gutter = "gutter",
1009 Tiles = "tiles",
1011 }
1012);
1013
1014string_enum!(
1015 SplitDir {
1017 Row = "row",
1019 Col = "col",
1021 }
1022);
1023
1024string_enum!(
1025 ScrollVariant {
1027 Bar = "bar",
1029 Fade = "fade",
1031 }
1032);
1033
1034string_enum!(
1035 Stick {
1037 End = "end",
1039 }
1040);
1041
1042string_enum!(
1043 ScrollBar {
1045 Auto = "auto",
1047 Always = "always",
1049 }
1050);
1051
1052string_enum!(
1053 CarouselVariant {
1055 Peek = "peek",
1057 Arrows = "arrows",
1059 Strip = "strip",
1061 }
1062);
1063
1064string_enum!(
1065 MessageVariant {
1067 Auto = "auto",
1070 Bubble = "bubble",
1072 Flat = "flat",
1074 }
1075);
1076
1077string_enum!(
1078 MessageSide {
1080 Start = "start",
1082 End = "end",
1084 }
1085);
1086
1087string_enum!(
1088 Reveal {
1090 Hover = "hover",
1092 Always = "always",
1094 }
1095);
1096
1097string_enum!(
1098 AttachmentVariant {
1100 Chip = "chip",
1102 Tile = "tile",
1104 Pill = "pill",
1106 }
1107);
1108
1109string_enum!(
1110 AttachmentState {
1112 Idle = "idle",
1114 Uploading = "uploading",
1116 Processing = "processing",
1118 Error = "error",
1120 Done = "done",
1122 }
1123);
1124
1125string_enum!(
1126 TraceVariant {
1128 Rail = "rail",
1130 Summary = "summary",
1132 Card = "card",
1134 }
1135);
1136
1137string_enum!(
1138 StacktraceVariant {
1140 Frames = "frames",
1142 Split = "split",
1144 Mono = "mono",
1146 }
1147);
1148
1149string_enum!(
1150 SuggestionsVariant {
1152 Chips = "chips",
1154 Rows = "rows",
1156 Cards = "cards",
1158 }
1159);
1160
1161string_enum!(
1162 QuestionsVariant {
1164 Steps = "steps",
1166 Inline = "inline",
1168 List = "list",
1170 }
1171);
1172
1173#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1175pub struct Span {
1176 pub t: String,
1178 #[serde(skip_serializing_if = "Option::is_none")]
1180 pub s: Option<String>,
1181 #[serde(skip_serializing_if = "Option::is_none")]
1183 pub fx: Option<Fx>,
1184 #[serde(skip_serializing_if = "Option::is_none")]
1186 pub href: Option<String>,
1187 #[serde(skip_serializing_if = "Vec::is_empty")]
1190 pub cite: Vec<Cite>,
1191}
1192
1193#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1195pub struct Cite {
1196 pub href: String,
1198 #[serde(skip_serializing_if = "Option::is_none")]
1200 pub title: Option<String>,
1201 #[serde(skip_serializing_if = "Option::is_none")]
1203 pub n: Option<u32>,
1204 #[serde(skip_serializing_if = "Option::is_none")]
1206 pub site: Option<String>,
1207 #[serde(skip_serializing_if = "Option::is_none")]
1209 pub snippet: Option<String>,
1210}
1211
1212impl Cite {
1213 pub fn new(href: impl Into<String>) -> Self {
1215 Self { href: href.into(), ..Self::default() }
1216 }
1217
1218 pub fn title(mut self, title: impl Into<String>) -> Self {
1220 self.title = Some(title.into());
1221 self
1222 }
1223
1224 pub const fn n(mut self, n: u32) -> Self {
1226 self.n = Some(n);
1227 self
1228 }
1229
1230 pub fn site(mut self, site: impl Into<String>) -> Self {
1232 self.site = Some(site.into());
1233 self
1234 }
1235
1236 pub fn snippet(mut self, snippet: impl Into<String>) -> Self {
1238 self.snippet = Some(snippet.into());
1239 self
1240 }
1241}
1242
1243impl Span {
1244 pub fn new(t: impl Into<String>) -> Self {
1246 Self { t: t.into(), ..Self::default() }
1247 }
1248
1249 pub fn style(mut self, token: impl Into<Token>) -> Self {
1251 let token = token.into();
1252 self.s = Some(match self.s.take() {
1253 Some(s) if !s.is_empty() => format!("{s} {token}"),
1254 _ => token.to_string(),
1255 });
1256 self
1257 }
1258
1259 pub fn fx(mut self, fx: impl Into<Fx>) -> Self {
1261 self.fx = Some(fx.into());
1262 self
1263 }
1264
1265 pub fn href(mut self, href: impl Into<String>) -> Self {
1267 self.href = Some(href.into());
1268 self
1269 }
1270
1271 pub fn cite(mut self, cite: Cite) -> Self {
1273 self.cite.push(cite);
1274 self
1275 }
1276}
1277
1278impl From<&str> for Span {
1279 fn from(t: &str) -> Self {
1280 Self::new(t)
1281 }
1282}
1283
1284impl From<String> for Span {
1285 fn from(t: String) -> Self {
1286 Self::new(t)
1287 }
1288}
1289
1290#[derive(Clone, Debug, PartialEq, Eq)]
1292pub enum Text {
1293 Plain(String),
1295 Spans(Vec<Span>),
1297}
1298
1299impl Text {
1300 pub fn plain(&self) -> String {
1302 match self {
1303 Self::Plain(s) => s.clone(),
1304 Self::Spans(spans) => spans.iter().map(|s| s.t.as_str()).collect(),
1305 }
1306 }
1307}
1308
1309impl Default for Text {
1310 fn default() -> Self {
1311 Self::Plain(String::new())
1312 }
1313}
1314
1315impl Serialize for Text {
1316 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1317 match self {
1318 Self::Plain(t) => s.serialize_str(t),
1319 Self::Spans(spans) => spans.serialize(s),
1320 }
1321 }
1322}
1323
1324impl From<&str> for Text {
1325 fn from(t: &str) -> Self {
1326 Self::Plain(t.to_owned())
1327 }
1328}
1329
1330impl From<String> for Text {
1331 fn from(t: String) -> Self {
1332 Self::Plain(t)
1333 }
1334}
1335
1336impl From<&String> for Text {
1337 fn from(t: &String) -> Self {
1338 Self::Plain(t.clone())
1339 }
1340}
1341
1342impl From<Span> for Text {
1343 fn from(span: Span) -> Self {
1344 Self::Spans(vec![span])
1345 }
1346}
1347
1348impl From<Vec<Span>> for Text {
1349 fn from(spans: Vec<Span>) -> Self {
1350 Self::Spans(spans)
1351 }
1352}
1353
1354impl<const N: usize> From<[Span; N]> for Text {
1355 fn from(spans: [Span; N]) -> Self {
1356 Self::Spans(spans.into())
1357 }
1358}
1359
1360#[derive(Clone, Copy, Debug, PartialEq)]
1362pub enum Extent {
1363 Ch(f64),
1365 Lines(f64),
1367 Fraction(f64),
1369}
1370
1371impl Serialize for Extent {
1372 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1373 match *self {
1374 Self::Ch(n) => s.collect_str(&format_args!("{n}ch")),
1375 Self::Lines(n) => s.collect_str(&format_args!("{n}lines")),
1376 Self::Fraction(f) => s.serialize_f64(f),
1377 }
1378 }
1379}
1380
1381#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize)]
1383pub struct Bound {
1384 #[serde(skip_serializing_if = "Option::is_none")]
1386 pub w: Option<Extent>,
1387 #[serde(skip_serializing_if = "Option::is_none")]
1389 pub h: Option<Extent>,
1390}
1391
1392impl Bound {
1393 pub const fn w(w: Extent) -> Self {
1395 Self { w: Some(w), h: None }
1396 }
1397
1398 pub const fn h(h: Extent) -> Self {
1400 Self { w: None, h: Some(h) }
1401 }
1402
1403 pub const fn wh(w: Extent, h: Extent) -> Self {
1405 Self { w: Some(w), h: Some(h) }
1406 }
1407}
1408
1409#[derive(Clone, Copy, Debug, PartialEq)]
1411pub enum Basis {
1412 Fraction(f64),
1414 Content,
1416}
1417
1418impl Serialize for Basis {
1419 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1420 match *self {
1421 Self::Fraction(f) => s.serialize_f64(f),
1422 Self::Content => s.serialize_str("content"),
1423 }
1424 }
1425}
1426
1427impl From<f64> for Basis {
1428 fn from(f: f64) -> Self {
1429 Self::Fraction(f)
1430 }
1431}
1432
1433#[derive(Clone, Copy, Debug, PartialEq)]
1435pub enum Height {
1436 Px(f64),
1438 Ch(f64),
1440 Lines(f64),
1442}
1443
1444impl Serialize for Height {
1445 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1446 match *self {
1447 Self::Px(px) => s.serialize_f64(px),
1448 Self::Ch(n) => s.collect_str(&format_args!("{n}ch")),
1449 Self::Lines(n) => s.collect_str(&format_args!("{n}lines")),
1450 }
1451 }
1452}
1453
1454#[derive(Clone, Debug, PartialEq)]
1456pub enum PaneMin {
1457 All(Extent),
1459 Each(Vec<Option<Extent>>),
1461 Bound(Bound),
1463}
1464
1465impl Serialize for PaneMin {
1466 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1467 match self {
1468 Self::All(extent) => extent.serialize(s),
1469 Self::Each(extents) => extents.serialize(s),
1470 Self::Bound(bound) => bound.serialize(s),
1471 }
1472 }
1473}
1474
1475impl From<Extent> for PaneMin {
1476 fn from(extent: Extent) -> Self {
1477 Self::All(extent)
1478 }
1479}
1480
1481impl From<Vec<Option<Extent>>> for PaneMin {
1482 fn from(extents: Vec<Option<Extent>>) -> Self {
1483 Self::Each(extents)
1484 }
1485}
1486
1487impl From<Bound> for PaneMin {
1488 fn from(bound: Bound) -> Self {
1489 Self::Bound(bound)
1490 }
1491}
1492
1493#[derive(Clone, Debug, PartialEq, Eq)]
1497pub enum TextFlag {
1498 Flag(bool),
1500 Text(Text),
1502}
1503
1504impl Serialize for TextFlag {
1505 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1506 match self {
1507 Self::Flag(b) => s.serialize_bool(*b),
1508 Self::Text(t) => t.serialize(s),
1509 }
1510 }
1511}
1512
1513impl From<bool> for TextFlag {
1514 fn from(b: bool) -> Self {
1515 Self::Flag(b)
1516 }
1517}
1518
1519impl<T: Into<Text>> From<T> for TextFlag {
1520 fn from(t: T) -> Self {
1521 Self::Text(t.into())
1522 }
1523}
1524
1525#[derive(Clone, Copy, Debug, PartialEq)]
1527pub enum SliderValue {
1528 One(f64),
1530 Range(f64, f64),
1532}
1533
1534impl Serialize for SliderValue {
1535 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1536 match *self {
1537 Self::One(v) => s.serialize_f64(v),
1538 Self::Range(lo, hi) => [lo, hi].serialize(s),
1539 }
1540 }
1541}
1542
1543impl From<f64> for SliderValue {
1544 fn from(v: f64) -> Self {
1545 Self::One(v)
1546 }
1547}
1548
1549impl From<(f64, f64)> for SliderValue {
1550 fn from((lo, hi): (f64, f64)) -> Self {
1551 Self::Range(lo, hi)
1552 }
1553}
1554
1555#[derive(Clone, Debug, PartialEq)]
1557pub enum Ticks {
1558 Steps(bool),
1560 Parts(u32),
1562 At(Vec<f64>),
1564}
1565
1566impl Serialize for Ticks {
1567 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1568 match self {
1569 Self::Steps(b) => s.serialize_bool(*b),
1570 Self::Parts(n) => s.serialize_u32(*n),
1571 Self::At(values) => values.serialize(s),
1572 }
1573 }
1574}
1575
1576impl From<bool> for Ticks {
1577 fn from(b: bool) -> Self {
1578 Self::Steps(b)
1579 }
1580}
1581
1582impl From<u32> for Ticks {
1583 fn from(n: u32) -> Self {
1584 Self::Parts(n)
1585 }
1586}
1587
1588impl From<Vec<f64>> for Ticks {
1589 fn from(values: Vec<f64>) -> Self {
1590 Self::At(values)
1591 }
1592}
1593
1594#[derive(Clone, Debug, PartialEq, Eq)]
1596pub enum OtpMask {
1597 Dots(bool),
1599 Char(String),
1601}
1602
1603impl Serialize for OtpMask {
1604 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1605 match self {
1606 Self::Dots(b) => s.serialize_bool(*b),
1607 Self::Char(c) => s.serialize_str(c),
1608 }
1609 }
1610}
1611
1612impl From<bool> for OtpMask {
1613 fn from(b: bool) -> Self {
1614 Self::Dots(b)
1615 }
1616}
1617
1618impl From<&str> for OtpMask {
1619 fn from(c: &str) -> Self {
1620 Self::Char(c.to_owned())
1621 }
1622}
1623
1624impl From<char> for OtpMask {
1625 fn from(c: char) -> Self {
1626 Self::Char(c.to_string())
1627 }
1628}
1629
1630#[derive(Clone, Debug, PartialEq, Eq)]
1633pub enum Noun {
1634 Word(String),
1636 Forms(String, String),
1638}
1639
1640impl Serialize for Noun {
1641 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1642 match self {
1643 Self::Word(w) => s.serialize_str(w),
1644 Self::Forms(one, many) => [one, many].serialize(s),
1645 }
1646 }
1647}
1648
1649impl From<&str> for Noun {
1650 fn from(w: &str) -> Self {
1651 Self::Word(w.to_owned())
1652 }
1653}
1654
1655impl From<String> for Noun {
1656 fn from(w: String) -> Self {
1657 Self::Word(w)
1658 }
1659}
1660
1661impl From<(&str, &str)> for Noun {
1662 fn from((one, many): (&str, &str)) -> Self {
1663 Self::Forms(one.to_owned(), many.to_owned())
1664 }
1665}
1666
1667#[derive(Clone, Debug, PartialEq, Eq)]
1670pub enum DateValue {
1671 Day(String),
1673 Range(String, Option<String>),
1675}
1676
1677impl Serialize for DateValue {
1678 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1679 match self {
1680 Self::Day(day) => s.serialize_str(day),
1681 Self::Range(from, to) => (from, to).serialize(s),
1682 }
1683 }
1684}
1685
1686impl From<&str> for DateValue {
1687 fn from(day: &str) -> Self {
1688 Self::Day(day.to_owned())
1689 }
1690}
1691
1692impl From<String> for DateValue {
1693 fn from(day: String) -> Self {
1694 Self::Day(day)
1695 }
1696}
1697
1698impl From<(&str, &str)> for DateValue {
1699 fn from((from, to): (&str, &str)) -> Self {
1700 Self::Range(from.to_owned(), Some(to.to_owned()))
1701 }
1702}
1703
1704#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1706pub enum NodeKey {
1707 Str(String),
1709 Int(i64),
1711}
1712
1713impl Serialize for NodeKey {
1714 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1715 match self {
1716 Self::Str(k) => s.serialize_str(k),
1717 Self::Int(n) => s.serialize_i64(*n),
1718 }
1719 }
1720}
1721
1722impl From<&str> for NodeKey {
1723 fn from(k: &str) -> Self {
1724 Self::Str(k.to_owned())
1725 }
1726}
1727
1728impl From<String> for NodeKey {
1729 fn from(k: String) -> Self {
1730 Self::Str(k)
1731 }
1732}
1733
1734impl From<&String> for NodeKey {
1735 fn from(k: &String) -> Self {
1736 Self::Str(k.clone())
1737 }
1738}
1739
1740macro_rules! int_key {
1742 ($($t:ty),*) => {
1743 $(impl From<$t> for NodeKey {
1744 fn from(n: $t) -> Self {
1745 Self::Int(n as i64)
1746 }
1747 })*
1748 };
1749}
1750
1751int_key!(i32, i64, u32, u64, usize);
1752
1753#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
1755pub struct Actions {
1756 #[serde(skip_serializing_if = "Option::is_none")]
1758 pub click: Option<String>,
1759 #[serde(skip_serializing_if = "Option::is_none")]
1761 pub dblclick: Option<String>,
1762 #[serde(skip_serializing_if = "Vec::is_empty")]
1765 pub menu: Vec<MenuEntry>,
1766}
1767
1768impl Actions {
1769 pub fn new() -> Self {
1771 Self::default()
1772 }
1773
1774 pub fn click(mut self, act: impl Into<String>) -> Self {
1776 self.click = Some(act.into());
1777 self
1778 }
1779
1780 pub fn dblclick(mut self, act: impl Into<String>) -> Self {
1782 self.dblclick = Some(act.into());
1783 self
1784 }
1785
1786 pub fn menu(mut self, entry: impl Into<MenuEntry>) -> Self {
1788 self.menu.push(entry.into());
1789 self
1790 }
1791}