mirror of https://github.com/terhechte/postsack
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
7.3 KiB
Rust
233 lines
7.3 KiB
Rust
//! Various background utilities
|
|
use eframe::egui::{
|
|
self,
|
|
epaint::{RectShape, Shadow},
|
|
vec2, Color32, Painter, Pos2, Rect, Response, Shape, Stroke, Ui, Vec2,
|
|
};
|
|
|
|
use std::ops::Rem;
|
|
|
|
use crate::platform::{platform_colors, PlatformColors};
|
|
|
|
/// This will draw Ui with a background color and margins.
|
|
/// This can be used for calls that don't provide a `Frame`,
|
|
/// such as `horizontal` or `vertical`
|
|
pub fn color_background(
|
|
ui: &mut Ui,
|
|
padding: f32,
|
|
stroke: Stroke,
|
|
fill: Color32,
|
|
show: impl FnOnce(&mut Ui) -> Response,
|
|
) -> Response {
|
|
let outer_rect_bounds = ui.available_rect_before_wrap();
|
|
let where_to_put_background = ui.painter().add(egui::Shape::Noop);
|
|
let margin = egui::Vec2::splat(padding);
|
|
let inner_rect = outer_rect_bounds.shrink2(margin);
|
|
|
|
let mut content_ui = ui.child_ui(inner_rect, *ui.layout());
|
|
let ret = show(&mut content_ui);
|
|
let outer_rect = Rect::from_min_max(outer_rect_bounds.min, content_ui.min_rect().max + margin);
|
|
let (rect, _) = ui.allocate_at_least(outer_rect.size(), egui::Sense::hover());
|
|
|
|
ui.painter().set(
|
|
where_to_put_background,
|
|
egui::epaint::Shape::Rect(RectShape {
|
|
corner_radius: 0.0,
|
|
fill,
|
|
stroke,
|
|
rect,
|
|
}),
|
|
);
|
|
ret
|
|
}
|
|
|
|
/// Draw a rectangular background with a shadow
|
|
pub fn shadow_background(
|
|
painter: &Painter,
|
|
paint_rect: Rect,
|
|
fill: Color32,
|
|
stroke: Stroke,
|
|
corner_radius: f32,
|
|
shadow: Shadow,
|
|
) {
|
|
let frame_shape = Shape::Rect(RectShape {
|
|
rect: paint_rect,
|
|
corner_radius,
|
|
fill,
|
|
stroke,
|
|
});
|
|
|
|
let shadow = shadow.tessellate(paint_rect, corner_radius);
|
|
let shadow = Shape::Mesh(shadow);
|
|
let shape = Shape::Vec(vec![shadow, frame_shape]);
|
|
painter.add(shape);
|
|
}
|
|
|
|
/// A animated backwround with some parameters.
|
|
/// Used in some `app_states`.
|
|
pub struct AnimatedBackground<'a> {
|
|
/// The divisions
|
|
pub divisions: usize,
|
|
/// For each division cell, we take 8 sub divisions
|
|
pub animate_progress: Option<(&'a [usize], usize)>,
|
|
/// time counter
|
|
pub timer: &'a mut f64,
|
|
/// recursive offset counter
|
|
pub offset_counter: &'a mut usize,
|
|
}
|
|
|
|
impl<'a> AnimatedBackground<'a> {
|
|
pub fn draw_background(&mut self, ui: &mut egui::Ui, size: Vec2) {
|
|
let painter = ui.painter();
|
|
|
|
let divisions = self.divisions as f32;
|
|
|
|
// paint stuff
|
|
let rect_size = vec2(size.x / divisions, size.y / divisions);
|
|
|
|
let colors = platform_colors();
|
|
|
|
// we only animate if there's no progress
|
|
let (offset, add) = if self.animate_progress.is_none() {
|
|
// Define the animation speed
|
|
let offset = *self.timer * 42.5;
|
|
|
|
if offset > rect_size.x as f64 {
|
|
*self.timer = 0.0;
|
|
*self.offset_counter += 1;
|
|
}
|
|
|
|
// Reset the offset counter as we're going out of the size
|
|
if (*self.offset_counter as f32 * rect_size.x) > (size.x * 1.1) {
|
|
*self.offset_counter = 0;
|
|
}
|
|
|
|
// figure out the offset addition
|
|
let add = *self.offset_counter as i8;
|
|
(offset, add)
|
|
} else {
|
|
(0.0, 0)
|
|
};
|
|
|
|
Self::draw_rectangles(
|
|
painter,
|
|
offset,
|
|
divisions,
|
|
rect_size,
|
|
&[
|
|
(4 + add, 4, 3),
|
|
(3 + add, 3, 2),
|
|
(1 + add, 1, 5),
|
|
(5 + add, 2, 5),
|
|
(2 + add, 1, 6),
|
|
(3 + add, 3, 7),
|
|
(4 + add, 5, 1),
|
|
(3 + add, 3, 7),
|
|
(6 + add, 1, 3),
|
|
(1 + add, 5, 4),
|
|
(3 + add, 6, 5),
|
|
],
|
|
self.divisions,
|
|
);
|
|
|
|
// Next, draw the rectangles
|
|
if let Some((blocks, d)) = self.animate_progress {
|
|
// the resolution of the block animation
|
|
let divisor = self.divisions * d;
|
|
let w = rect_size.x / d as f32;
|
|
let h = rect_size.y / d as f32;
|
|
let mut color_adder = self.divisions;
|
|
for n in blocks {
|
|
// calculate x/y from the value
|
|
let y = n / divisor;
|
|
let x = n % divisor;
|
|
let y = y as f32;
|
|
let x = x as f32;
|
|
let pos = Pos2::new(x * w, y * h);
|
|
let size = vec2(w, h);
|
|
let rect = Rect::from_min_size(pos, size);
|
|
// the fill color is based on the added block count
|
|
color_adder += *n;
|
|
let color_addition = if colors.is_light {
|
|
-((color_adder % 50) as i8)
|
|
} else {
|
|
(color_adder % 50) as i8
|
|
};
|
|
let color = Color32::from_rgb(
|
|
(colors.animation_background.r() as i8 + color_addition) as u8,
|
|
(colors.animation_background.g() as i8 + color_addition) as u8,
|
|
(colors.animation_background.b() as i8 + color_addition) as u8,
|
|
);
|
|
|
|
painter.rect_filled(rect, 0.0, color);
|
|
painter.rect_stroke(rect, 0.0, Stroke::new(1.0, colors.line3));
|
|
}
|
|
}
|
|
|
|
let diff = ui.input().unstable_dt as f64;
|
|
*self.timer += diff;
|
|
|
|
ui.ctx().request_repaint();
|
|
}
|
|
|
|
fn draw_rectangles(
|
|
painter: &Painter,
|
|
offset: f64,
|
|
division: f32,
|
|
size: Vec2,
|
|
recurse: &[(i8, i8, i8)],
|
|
total: usize,
|
|
) {
|
|
let colors = platform_colors();
|
|
|
|
for y in 0..=(division + 2.0) as i8 {
|
|
for x in 0..=(division + 2.0) as i8 {
|
|
let fx = ((x - 1) as f32 * size.x) + (offset as f32);
|
|
let fy = (y - 1) as f32 * size.y;
|
|
let pos = Pos2::new(fx, fy);
|
|
let rect = Rect::from_min_size(pos, size);
|
|
painter.rect_stroke(rect, 0.0, Stroke::new(1.0, Color32::from_gray(70)));
|
|
for (rx, ry, rd) in recurse {
|
|
// on the x axis take the offset into account
|
|
let rx = (*rx).rem((total as i8) + 1);
|
|
if rx == x && ry == &y {
|
|
Self::draw_segmentation(painter, rect, *rd, colors);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn draw_segmentation(painter: &Painter, into: Rect, divisions: i8, colors: &PlatformColors) {
|
|
let mut rect = into;
|
|
for d in 0..=divisions {
|
|
// division back and forth in direction
|
|
let next = if d % 2 == 0 {
|
|
Rect::from_min_size(
|
|
Pos2 {
|
|
x: rect.center().x,
|
|
y: rect.top(),
|
|
},
|
|
Vec2 {
|
|
x: rect.width() / 2.0,
|
|
y: rect.height(),
|
|
},
|
|
)
|
|
} else {
|
|
Rect::from_min_size(
|
|
Pos2 {
|
|
x: rect.left(),
|
|
y: rect.center().y,
|
|
},
|
|
Vec2 {
|
|
x: rect.width(),
|
|
y: rect.height() / 2.0,
|
|
},
|
|
)
|
|
};
|
|
painter.rect_stroke(next, 0.0, Stroke::new(1.0, colors.line4));
|
|
rect = next;
|
|
}
|
|
}
|
|
}
|