use crate::compat::{HashMap, Vec};
use crate::core::{ObjectId, Rect};
use std::collections::HashSet;
#[derive(Debug)]
pub struct WidgetDirtyState {
dirty_widgets: HashSet<ObjectId>,
dirty_rects: HashMap<ObjectId, Rect>,
}
impl WidgetDirtyState {
pub fn new() -> Self {
Self { dirty_widgets: HashSet::new(), dirty_rects: HashMap::new() }
}
pub fn mark_dirty(&mut self, id: ObjectId, rect: Rect) {
self.dirty_widgets.insert(id);
self.dirty_rects
.entry(id)
.and_modify(|existing| *existing = existing.union(&rect))
.or_insert(rect);
}
pub fn mark_clean(&mut self, id: ObjectId) {
self.dirty_widgets.remove(&id);
self.dirty_rects.remove(&id);
}
pub fn is_dirty(&self, id: ObjectId) -> bool {
self.dirty_widgets.contains(&id)
}
pub fn get_dirty_rect(&self, id: ObjectId) -> Option<&Rect> {
self.dirty_rects.get(&id)
}
pub fn dirty_widgets(&self) -> &HashSet<ObjectId> {
&self.dirty_widgets
}
pub fn clear(&mut self) {
self.dirty_widgets.clear();
self.dirty_rects.clear();
}
pub fn is_empty(&self) -> bool {
self.dirty_widgets.is_empty()
}
pub fn len(&self) -> usize {
self.dirty_widgets.len()
}
pub fn get_all_rects(&self) -> Vec<Rect> {
self.dirty_rects.values().copied().collect()
}
}
crate::impl_default_via_new!(WidgetDirtyState);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mark_dirty_unions_reports_for_the_same_widget() {
let mut state = WidgetDirtyState::new();
state.mark_dirty(7, Rect::new(10, 10, 20, 20));
state.mark_dirty(7, Rect::new(25, 25, 10, 10));
assert_eq!(state.get_dirty_rect(7), Some(&Rect::new(10, 10, 25, 25)));
assert_eq!(state.len(), 1, "a repeated mark still counts as one dirty widget");
state.mark_clean(7);
assert_eq!(state.get_dirty_rect(7), None);
}
}