🔒 Repository is read-only – file editing is disabled.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
//! `Image` — obrazek (GTK4) oparty na wbudowanych ikonach wektorowych.
//!
//! libLuna nie dekoduje plików graficznych (świadomie — bez balastu kodeków); `Image`
//! pokazuje natomiast zestaw ikon rysowanych wektorowo (folder, plik, lupka, krzyżyk,
//! hamburger), skalowanych do zadanego rozmiaru.
use libluna_core::{Rect, Theme};
use crate::ctx::PaintCtx;
use crate::icon;
/// Zestaw wbudowanych ikon [`Image`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ImageIcon {
#[default]
Folder,
File,
Search,
Close,
Burger,
}
/// Obrazek z wbudowanej ikony wektorowej.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Image {
icon: ImageIcon,
size: f64,
}
impl Default for Image {
fn default() -> Self {
Self {
icon: ImageIcon::Folder,
size: 48.0,
}
}
}
impl Image {
pub fn new(icon: ImageIcon) -> Self {
Self {
icon,
..Self::default()
}
}
pub fn icon(&self) -> ImageIcon {
self.icon
}
pub fn set_icon(&mut self, icon: ImageIcon) {
self.icon = icon;
}
pub fn size(mut self, size: f64) -> Self {
self.size = size.max(0.0);
self
}
pub fn width(&self) -> f64 {
self.size
}
pub fn height(&self) -> f64 {
self.size
}
/// Kwadrat obrazka wyśrodkowany w `rect` (o boku `min(rect, size)`).
pub fn image_rect(&self, rect: Rect) -> Rect {
let side = self.size.min(rect.width()).min(rect.height()).max(0.0);
let c = rect.center();
Rect::from_xywh(c.x - side / 2.0, c.y - side / 2.0, side, side)
}
pub fn paint(&self, ctx: &mut PaintCtx, rect: Rect) {
let theme = *ctx.theme;
let box_ = self.image_rect(rect);
let color = theme.colors.text;
match self.icon {
ImageIcon::Folder => icon::folder(ctx, color, box_),
ImageIcon::File => icon::file(ctx, color, box_),
ImageIcon::Search => icon::search(ctx, color, box_.center(), box_.width() * 0.9),
ImageIcon::Close => icon::close(ctx, color, box_, box_.width() * 0.22),
ImageIcon::Burger => icon::burger(ctx, color, box_.center(), box_.width() * 0.34, 1.8),
}
}
}
/// Rozmiar obrazka domyślnie ustawiany przez motyw (bok kwadratu).
pub fn default_size(theme: &Theme) -> f64 {
theme.spacing.xl * 3.0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn image_rect_is_square_and_centered() {
let img = Image::new(ImageIcon::Folder).size(40.0);
let rect = Rect::from_xywh(0.0, 0.0, 100.0, 60.0);
let r = img.image_rect(rect);
assert_eq!(r.width(), 40.0);
assert_eq!(r.height(), 40.0);
assert_eq!(r.center().x, 50.0);
assert_eq!(r.center().y, 30.0);
}
#[test]
fn image_shrinks_to_fit_small_rect() {
let img = Image::new(ImageIcon::File).size(80.0);
let rect = Rect::from_xywh(0.0, 0.0, 30.0, 20.0);
let r = img.image_rect(rect);
assert_eq!(r.width(), 20.0);
assert_eq!(r.height(), 20.0);
}
#[test]
fn size_defaults_from_integer_scale() {
let theme = Theme::light();
assert!(default_size(&theme) > 0.0);
}
}