1use crate::config::SharedConfig;
2use crate::errors::*;
3use crate::formatting::{Format, Fragment, Values};
4use crate::protocol::i3bar_block::I3BarBlock;
5use serde::Deserialize;
6use smart_default::SmartDefault;
7
8#[derive(Debug, Clone, Default)]
9pub struct Widget {
10 pub state: State,
11 source: Source,
12 values: Values,
13}
14
15impl Widget {
16 pub fn new() -> Self {
17 Self::default()
18 }
19
20 pub fn with_text(mut self, text: String) -> Self {
25 self.set_text(text);
26 self
27 }
28
29 pub fn with_state(mut self, state: State) -> Self {
30 self.state = state;
31 self
32 }
33
34 pub fn with_format(mut self, format: Format) -> Self {
35 self.set_format(format);
36 self
37 }
38
39 pub fn set_text(&mut self, text: String) {
44 if text.is_empty() {
45 self.source = Source::None;
46 } else {
47 self.source = Source::Text(text);
48 }
49 }
50
51 pub fn set_format(&mut self, format: Format) {
52 self.source = Source::Format(format);
53 }
54
55 pub fn set_values(&mut self, new_values: Values) {
56 self.values = new_values;
57 }
58
59 pub fn intervals(&self) -> Vec<u64> {
60 match &self.source {
61 Source::Format(f) => f.intervals(),
62 _ => Vec::new(),
63 }
64 }
65
66 pub fn get_data(&self, shared_config: &SharedConfig, id: usize) -> Result<Vec<I3BarBlock>> {
68 let (key_bg, key_fg) = shared_config.theme.get_colors(self.state);
70 let (full, short) = self.source.render(shared_config, &self.values)?;
71 let mut template = I3BarBlock {
72 instance: format!("{id}:"),
73 background: key_bg,
74 color: key_fg,
75 ..I3BarBlock::default()
76 };
77
78 let mut parts = Vec::new();
80
81 if full.is_empty() {
82 return Ok(parts);
83 }
84
85 if !short.is_empty() {
90 template.short_text = "<span/>".into();
91 }
92
93 parts.extend(full.into_iter().map(|w| {
94 let mut data = template.clone();
95 data.full_text = w.formatted_text();
96 if let Some(i) = &w.metadata.instance {
97 data.instance.push_str(i);
98 }
99 data
100 }));
101
102 template.full_text = "<span/>".into();
103 parts.extend(short.into_iter().map(|w| {
104 let mut data = template.clone();
105 data.short_text = w.formatted_text();
106 if let Some(i) = &w.metadata.instance {
107 data.instance.push_str(i);
108 }
109 data
110 }));
111
112 Ok(parts)
113 }
114}
115
116#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq, SmartDefault)]
118pub enum State {
119 #[default]
120 #[serde(alias = "idle")]
121 Idle,
122 #[serde(alias = "info")]
123 Info,
124 #[serde(alias = "good")]
125 Good,
126 #[serde(alias = "warning")]
127 Warning,
128 #[serde(alias = "critical")]
129 Critical,
130}
131
132#[derive(Debug, Clone, SmartDefault)]
134enum Source {
135 #[default]
137 None,
138 Text(String),
140 Format(Format),
142}
143
144impl Source {
145 fn render(
146 &self,
147 config: &SharedConfig,
148 values: &Values,
149 ) -> Result<(Vec<Fragment>, Vec<Fragment>)> {
150 match self {
151 Self::Text(text) => Ok((vec![text.clone().into()], vec![])),
152 Self::Format(format) => format.render(values, config),
153 Self::None => Ok((vec![], vec![])),
154 }
155 }
156}