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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use crate::{Color, Command, Led, OpenRgbError, OpenRgbResult, Zone, data::SegmentData};
/// A segment in a zone, which can contain multiple LEDs.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Segment<'c> {
zone: &'c Zone<'c>,
segment_data: &'c SegmentData,
}
impl<'c> Segment<'c> {
pub(crate) fn new(zone: &'c Zone<'c>, segment_data: &'c SegmentData) -> Self {
Self { zone, segment_data }
}
/// Returns the ID of this segment.
pub fn segment_id(&self) -> usize {
self.segment_data.id()
}
/// Returns the ID of the the controller this segment's zone belongs to.
pub fn controller_id(&self) -> usize {
self.zone.controller_id()
}
/// Returns the ID of the zone this segment belongs to.
pub fn zone_id(&self) -> usize {
self.zone.zone_id()
}
/// Returns the name of this segment.
pub fn name(&self) -> &str {
self.segment_data.name()
}
/// Returns the number of LEDs in this segment.
///
/// `Zone.leds[offset()..offset() + num_leds()]` will return the LEDs in this segment.
pub fn num_leds(&self) -> usize {
self.segment_data.led_count() as usize
}
/// Returns the index offset of this segment in the zone.
///
/// `Zone.leds[offset()..offset() + num_leds()]` will return the LEDs in this segment.
pub fn offset(&self) -> usize {
self.segment_data.offset() as usize
}
/// Returns an iterator over the Leds of this segment
pub fn led_iter(&self) -> impl Iterator<Item = Led<'c>> {
self.zone
.led_iter()
.skip(self.offset())
.take(self.num_leds())
}
/// Sets a single LED in this segment to the given `color`.
///
/// # Errors
///
/// Returns an error if the index is out of bounds for this zone.
pub async fn set_led<C: Into<Color>>(&self, idx: usize, color: C) -> OpenRgbResult<()> {
if idx >= self.num_leds() {
return Err(OpenRgbError::CommandError(format!(
"Index {idx} out of bounds for zone {} with {} LEDs",
self.name(),
self.num_leds()
)));
}
let idx = self.offset() + idx;
self.zone.set_led(idx, color).await
}
/// Sets all LEDs in this segment to the given `color`.
///
/// # Limitation
///
/// This will set every other LED in the zone to black, as those colors are not specified.
/// To get around this, use `[Self::cmd()]` instead and specify the zone color.
/// See the `segment.rs` example for an example
pub async fn set_all_leds<C: Into<Color>>(&self, color: C) -> OpenRgbResult<()> {
let color = color.into();
let colors = (0..self.num_leds()).map(|_| color);
let seg_colors = self.prepend_colors(colors);
self.zone.set_leds(seg_colors).await
}
/// Sets the LEDs in this segment to the given colors.
///
/// # Limitation
///
/// This will set every other LED in the zone to black, as those colors are not specified.
/// To get around this, use `[Self::cmd()]` instead and specify the zone color.
/// See the `segment.rs` example for an example
pub async fn set_leds<C: Into<Color>>(
&self,
colors: impl IntoIterator<Item = C>,
) -> OpenRgbResult<()> {
let color_v = colors.into_iter().map(Into::into).collect::<Vec<_>>();
if color_v.len() != self.num_leds() {
tracing::warn!(
"Segment {} for zone {} was given {} colors, while its length is {}. This might become a hard error in the future.",
self.name(),
self.zone.name(),
color_v.len(),
self.num_leds()
)
}
let seg_colors = self.prepend_colors(color_v);
self.zone.set_leds(seg_colors).await
}
fn prepend_colors<C: Into<Color>>(
&self,
colors: impl IntoIterator<Item = C>,
) -> impl Iterator<Item = Color> {
let color_v = colors.into_iter().map(Into::into);
(0..self.offset()).map(|_| Color::default()).chain(color_v)
}
/// Creates a new [`Command`] for the controller of this segment's zone.
#[must_use]
pub fn cmd(&'c self) -> Command<'c> {
self.zone.cmd()
}
/// Creates a new [`Command`] for the controller of this segment
/// and sets the LED colors using the provided closure.
pub fn cmd_with_leds<F>(&'c self, led_cld: F) -> Command<'c>
where
F: Fn(Led<'c>) -> Color,
{
let mut cmd = self.cmd();
for led in self.led_iter() {
cmd.set_led(led.id(), led_cld(led))
.expect("Failed to set LED color");
}
cmd
}
/// Returns a command to update the LEDs for this Zone to `colors`.
///
/// The command must be executed by calling `.execute()`
pub fn cmd_with_set_leds<C: Into<Color>>(
&'c self,
colors: impl IntoIterator<Item = C>,
) -> OpenRgbResult<Command<'c>> {
let mut cmd = self.cmd();
cmd.set_segment_leds(self.zone_id(), self.segment_id(), colors)?;
Ok(cmd)
}
}