1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
pub mod i3bar_block;
pub mod i3bar_event;

use std::borrow::Borrow;

use crate::config::SharedConfig;
use crate::themes::color::Color;
use crate::themes::separator::Separator;
use crate::RenderedBlock;

use i3bar_block::I3BarBlock;

pub fn init(never_pause: bool) {
    if never_pause {
        println!("{{\"version\": 1, \"click_events\": true, \"stop_signal\": 0}}\n[");
    } else {
        println!("{{\"version\": 1, \"click_events\": true}}\n[");
    }
}

pub(crate) fn print_blocks<B>(blocks: &[B], config: &SharedConfig)
where
    B: Borrow<RenderedBlock>,
{
    let mut prev_last_bg = Color::None;
    let mut rendered_blocks = vec![];

    // The right most block should never be alternated
    let mut alt = blocks
        .iter()
        .map(|x| x.borrow())
        .filter(|x| !x.segments.is_empty() && !x.merge_with_next)
        .count()
        % 2
        == 0;

    let mut logical_block_i = 0;

    let mut prev_merge_with_next = false;

    for (i, widgets) in blocks
        .iter()
        .map(|x| x.borrow())
        .filter(|x| !x.segments.is_empty())
        .cloned()
        .enumerate()
    {
        let RenderedBlock {
            mut segments,
            merge_with_next,
        } = widgets;

        for segment in &mut segments {
            segment.name = Some(logical_block_i.to_string());

            // Apply tint for all widgets of every second block
            // TODO: Allow for other non-additive tints
            if alt {
                segment.background = segment.background + config.theme.alternating_tint_bg;
                segment.color = segment.color + config.theme.alternating_tint_fg;
            }
        }

        if !merge_with_next {
            alt = !alt;
        }

        let separator = match &config.theme.start_separator {
            Separator::Custom(_) if i == 0 => &config.theme.start_separator,
            _ => &config.theme.separator,
        };

        if let Separator::Custom(separator) = separator {
            if !prev_merge_with_next {
                // The first widget's BG is used to get the FG color for the current separator
                let sep_fg = if config.theme.separator_fg == Color::Auto {
                    segments.first().unwrap().background
                } else {
                    config.theme.separator_fg
                };

                // The separator's BG is the last block's last widget's BG
                let sep_bg = if config.theme.separator_bg == Color::Auto {
                    prev_last_bg
                } else {
                    config.theme.separator_bg
                };

                let separator = I3BarBlock {
                    full_text: separator.clone(),
                    background: sep_bg,
                    color: sep_fg,
                    ..Default::default()
                };

                rendered_blocks.push(separator);
            }
        } else if !merge_with_next {
            // Re-add native separator on last widget for native theme
            segments.last_mut().unwrap().separator = None;
            segments.last_mut().unwrap().separator_block_width = None;
        }

        if !merge_with_next {
            logical_block_i += 1;
        }

        prev_merge_with_next = merge_with_next;
        prev_last_bg = segments.last().unwrap().background;

        rendered_blocks.extend(segments);
    }

    if let Separator::Custom(end_separator) = &config.theme.end_separator {
        rendered_blocks.push(I3BarBlock {
            full_text: end_separator.clone(),
            background: Color::None,
            color: prev_last_bg,
            ..Default::default()
        });
    }

    println!("{},", serde_json::to_string(&rendered_blocks).unwrap());
}