Tweak github draw

This commit is contained in:
FliegendeWurst 2024-12-02 21:37:29 +01:00
parent beee5fe970
commit 8ffaf1f809
2 changed files with 90 additions and 12 deletions

View File

@ -1,13 +1,15 @@
use std::cell::RefCell; use std::{cell::RefCell, collections::HashSet};
use color_space::{Hsv, ToRgb}; use color_space::{Hsv, ToRgb};
use embedded_graphics::{ use embedded_graphics::{
mono_font::{iso_8859_10::FONT_8X13, MonoTextStyleBuilder}, mono_font::{iso_8859_10::FONT_8X13, MonoTextStyleBuilder},
pixelcolor::Rgb565, pixelcolor::Rgb565,
prelude::{DrawTarget, Point, RgbColor}, prelude::{DrawTarget, Point, RgbColor},
primitives::Rectangle,
text::Text, text::Text,
Drawable, Drawable, Pixel,
}; };
use rand_xoshiro::rand_core::RngCore;
use raspi_oled::github::get_new_notifications; use raspi_oled::github::get_new_notifications;
use crate::{ use crate::{
@ -42,7 +44,6 @@ impl<D: DrawTarget<Color = Rgb565>> Schedule<D> for GithubNotifications {
return; return;
} }
let max_lines = 8; let max_lines = 8;
let max_line_length = 16;
let mut lines = vec![]; let mut lines = vec![];
let mut relevant = relevant.into_iter(); let mut relevant = relevant.into_iter();
while lines.len() < max_lines { while lines.len() < max_lines {
@ -59,9 +60,7 @@ impl<D: DrawTarget<Color = Rgb565>> Schedule<D> for GithubNotifications {
} }
lines.push(format!("{} #{}", parts[5], parts[7])); lines.push(format!("{} #{}", parts[5], parts[7]));
if lines.len() < max_lines { if lines.len() < max_lines {
let mut desc = format!(" {}", x.subject.title); lines.push(x.subject.title.clone());
desc.truncate(desc.floor_char_boundary(max_line_length));
lines.push(desc);
} }
} else { } else {
break; break;
@ -75,6 +74,7 @@ impl<D: DrawTarget<Color = Rgb565>> Schedule<D> for GithubNotifications {
calls: RefCell::new(0), calls: RefCell::new(0),
screen: &GITHUB, screen: &GITHUB,
lines, lines,
circles: RefCell::new(vec![]),
})); }));
} }
} }
@ -84,36 +84,108 @@ struct GithubNotificationsDraw {
calls: RefCell<usize>, calls: RefCell<usize>,
screen: &'static SimpleScreensaver, screen: &'static SimpleScreensaver,
lines: Vec<String>, lines: Vec<String>,
circles: RefCell<Vec<((u32, u32), u32, Rgb565, Vec<(u32, u32)>)>>,
} }
impl<D: DrawTarget<Color = Rgb565>> Draw<D> for GithubNotificationsDraw { impl<D: DrawTarget<Color = Rgb565>> Draw<D> for GithubNotificationsDraw {
fn draw(&self, disp: &mut D, _rng: &mut crate::Rng) -> Result<bool, D::Error> { fn draw(&self, disp: &mut D, rng: &mut crate::Rng) -> Result<bool, D::Error> {
let calls = *self.calls.borrow(); let calls = *self.calls.borrow();
if calls < 40 { if calls == 0 {
self.screen
.draw_all_colored(disp, Rgb565::new(0xff >> 3, 0xff >> 2, 0xff >> 3))?;
}
if calls < 70 {
let hue = calls as f64 / 40.0 * 360.0; let hue = calls as f64 / 40.0 * 360.0;
let hsv = Hsv::new(hue, 1.0, 1.0); let hsv = Hsv::new(hue, 1.0, 1.0);
let rgb = hsv.to_rgb(); let rgb = hsv.to_rgb();
let r = rgb.r as u8 >> 3; let r = rgb.r as u8 >> 3;
let g = rgb.g as u8 >> 2; let g = rgb.g as u8 >> 2;
let b = rgb.b as u8 >> 3; let b = rgb.b as u8 >> 3;
self.screen.draw_all_colored(disp, Rgb565::new(r, g, b))?; let rgb = Rgb565::new(r, g, b);
let mut x;
let mut y;
loop {
x = rng.next_u32() % 128;
y = rng.next_u32() % 128;
if self.screen.get_pixel(x, y) == Rgb565::WHITE {
break;
}
}
disp.fill_contiguous(&Rectangle::new((x as i32, y as i32).into(), (1, 1).into()), Some(rgb))?;
// advance other circles
let mut circles = self.circles.borrow_mut();
for ((ox, oy), radius, color, points) in &mut *circles {
*radius += 1;
let mut seen = HashSet::new();
let mut next_points = vec![];
loop {
let mut new_points = vec![];
for (x, y) in &*points {
for (dx, dy) in [(-1, 0), (0, -1), (1, 0), (0, 1)] {
let Some(x) = x.checked_add_signed(dx) else {
continue;
};
let Some(y) = y.checked_add_signed(dy) else {
continue;
};
if x >= 128 || y >= 128 {
continue;
}
if self.screen.get_pixel(x, y) != Rgb565::WHITE {
continue;
}
if seen.contains(&(x, y)) {
continue;
}
seen.insert((x, y));
let dist2 = x.abs_diff(*ox).pow(2) + y.abs_diff(*oy).pow(2);
if dist2 > (*radius - 1).pow(2) && dist2 <= (*radius).pow(2) {
new_points.push((x, y));
}
}
}
if new_points.is_empty() {
break;
}
next_points.extend_from_slice(&new_points);
*points = new_points;
}
disp.draw_iter(
next_points
.iter()
.map(|&x| Pixel(Point::new(x.0 as _, x.1 as _), *color)),
)?;
*points = next_points;
}
circles.push(((x, y), 0, rgb, vec![(x, y)]));
} else { } else {
let idx = calls - 70;
disp.clear(Rgb565::BLACK)?; disp.clear(Rgb565::BLACK)?;
// fit 9 lines // fit 9 lines
let max_line_length = 16;
let text_style_clock = MonoTextStyleBuilder::new() let text_style_clock = MonoTextStyleBuilder::new()
.font(&FONT_8X13) .font(&FONT_8X13)
.text_color(Rgb565::WHITE) .text_color(Rgb565::WHITE)
.build(); .build();
for (y, line) in self.lines.iter().enumerate() { for (y, line) in self.lines.iter().enumerate() {
Text::new(line, Point::new(0, (12 + y * 14) as _), text_style_clock).draw(disp)?; let mut line = if calls >= 139 {
format!(" {line}")
} else if line.len() > max_line_length {
let line = format!(" {line} ");
line[line.ceil_char_boundary(idx % line.len())..].to_string()
} else {
line.clone()
};
line.truncate(line.floor_char_boundary(max_line_length));
Text::new(&line, Point::new(0, (12 + y * 14) as _), text_style_clock).draw(disp)?;
} }
} }
*self.calls.borrow_mut() += 1; *self.calls.borrow_mut() += 1;
Ok(calls < 90) Ok(calls < 140)
} }
fn expired(&self) -> bool { fn expired(&self) -> bool {
*self.calls.borrow() > 90 *self.calls.borrow() > 140
} }
fn as_any(&self) -> &dyn std::any::Any { fn as_any(&self) -> &dyn std::any::Any {

View File

@ -105,6 +105,12 @@ impl SimpleScreensaver {
} }
} }
pub fn get_pixel(&self, x: u32, y: u32) -> Rgb565 {
let idx = y as usize * 128 + x as usize;
let (red, green, blue) = (self.data[3 * idx], self.data[3 * idx + 1], self.data[3 * idx + 2]);
Rgb565::new(red >> 3, green >> 2, blue >> 3)
}
pub fn draw_all_colored<D: DrawTarget<Color = Rgb565>>(&self, disp: &mut D, color: Rgb565) -> Result<(), D::Error> { pub fn draw_all_colored<D: DrawTarget<Color = Rgb565>>(&self, disp: &mut D, color: Rgb565) -> Result<(), D::Error> {
disp.fill_contiguous( disp.fill_contiguous(
&Rectangle::new((0, 0).into(), (128, 128).into()), &Rectangle::new((0, 0).into(), (128, 128).into()),