Skip to content

Commit 74a0511

Browse files
authored
feat(rect): add Rect::positions iterator (#928)
Useful for performing some action on all the cells in a particular area. E.g., ```rust fn render(area: Rect, buf: &mut Buffer) { for position in area.positions() { buf.get_mut(position.x, position.y).set_symbol("x"); } } ```
1 parent c3fb258 commit 74a0511

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

src/layout/rect.rs

+18
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,24 @@ impl Rect {
265265
Columns::new(self)
266266
}
267267

268+
/// An iterator over the positions within the `Rect`.
269+
///
270+
/// The positions are returned in a row-major order (left-to-right, top-to-bottom).
271+
///
272+
/// # Example
273+
///
274+
/// ```
275+
/// # use ratatui::prelude::*;
276+
/// fn render(area: Rect, buf: &mut Buffer) {
277+
/// for position in area.positions() {
278+
/// buf.get_mut(position.x, position.y).set_symbol("x");
279+
/// }
280+
/// }
281+
/// ```
282+
pub fn positions(self) -> Positions {
283+
Positions::new(self)
284+
}
285+
268286
/// Returns a [`Position`] with the same coordinates as this rect.
269287
///
270288
/// # Examples

src/layout/rect/iter.rs

+53
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use self::layout::Position;
12
use crate::prelude::*;
23

34
/// An iterator over rows within a `Rect`.
@@ -68,9 +69,50 @@ impl Iterator for Columns {
6869
}
6970
}
7071

72+
/// An iterator over positions within a `Rect`.
73+
///
74+
/// The iterator will yield all positions within the `Rect` in a row-major order.
75+
pub struct Positions {
76+
/// The `Rect` associated with the positions.
77+
pub rect: Rect,
78+
/// The current position within the `Rect`.
79+
pub current_position: Position,
80+
}
81+
82+
impl Positions {
83+
/// Creates a new `Positions` iterator.
84+
pub fn new(rect: Rect) -> Self {
85+
Self {
86+
rect,
87+
current_position: Position::new(rect.x, rect.y),
88+
}
89+
}
90+
}
91+
92+
impl Iterator for Positions {
93+
type Item = Position;
94+
95+
/// Retrieves the next position within the `Rect`.
96+
///
97+
/// Returns `None` when there are no more positions to iterate through.
98+
fn next(&mut self) -> Option<Self::Item> {
99+
if self.current_position.y >= self.rect.bottom() {
100+
return None;
101+
}
102+
let position = self.current_position;
103+
self.current_position.x += 1;
104+
if self.current_position.x >= self.rect.right() {
105+
self.current_position.x = self.rect.x;
106+
self.current_position.y += 1;
107+
}
108+
Some(position)
109+
}
110+
}
111+
71112
#[cfg(test)]
72113
mod tests {
73114
use super::*;
115+
use crate::layout::Position;
74116

75117
#[test]
76118
fn rows() {
@@ -89,4 +131,15 @@ mod tests {
89131
assert_eq!(columns.next(), Some(Rect::new(1, 0, 1, 2)));
90132
assert_eq!(columns.next(), None);
91133
}
134+
135+
#[test]
136+
fn positions() {
137+
let rect = Rect::new(0, 0, 2, 2);
138+
let mut positions = Positions::new(rect);
139+
assert_eq!(positions.next(), Some(Position::new(0, 0)));
140+
assert_eq!(positions.next(), Some(Position::new(1, 0)));
141+
assert_eq!(positions.next(), Some(Position::new(0, 1)));
142+
assert_eq!(positions.next(), Some(Position::new(1, 1)));
143+
assert_eq!(positions.next(), None);
144+
}
92145
}

0 commit comments

Comments
 (0)