use std::path::PathBuf;
use saudade::{App, Color, Column, Event, EventCtx, Painter, Rect, Theme, Widget, WindowConfig};
const W: i32 = 460;
const H: i32 = 320;
fn main() {
let root = Column::new()
.with_background(Color::WHITE)
.add_fill(DropZone::new());
App::new(WindowConfig::new("Drag & Drop", W, H).resizable(true), root)
.with_theme(Theme::windows_31())
.run();
}
struct DropZone {
bounds: Rect,
hovering: bool,
dropped: Vec<PathBuf>,
}
impl DropZone {
fn new() -> Self {
Self {
bounds: Rect::new(0, 0, W, H),
hovering: false,
dropped: Vec::new(),
}
}
}
impl Widget for DropZone {
fn bounds(&self) -> Rect {
self.bounds
}
fn layout(&mut self, bounds: Rect) {
self.bounds = bounds;
}
fn paint(&mut self, p: &mut Painter, theme: &Theme) {
let area = self.bounds.inset(8);
let (fill, fg) = if self.hovering {
(theme.highlight_bg, theme.highlight_text)
} else {
(Color::WHITE, theme.text)
};
p.fill_rect(area, fill);
p.sunken_bevel(area, theme.highlight, theme.shadow);
let inner = area.inset(8);
if self.dropped.is_empty() {
p.text_centered(area, "Drop files here", theme.font_size, fg);
return;
}
let line_h = (theme.font_size * 1.5).round() as i32;
let mut y = inner.y;
p.text(inner.x, y, "Dropped:", theme.font_size, fg);
y += line_h;
for path in &self.dropped {
if y > inner.bottom() - line_h {
break;
}
p.text(inner.x, y, &path.display().to_string(), theme.font_size, fg);
y += line_h;
}
}
fn event(&mut self, event: &Event, ctx: &mut EventCtx) {
match event {
Event::DragEnter { .. } | Event::DragMove { .. } => {
ctx.accept_drop();
if !self.hovering {
self.hovering = true;
ctx.request_paint();
}
}
Event::DragLeave => {
if self.hovering {
self.hovering = false;
ctx.request_paint();
}
}
Event::Drop { data, .. } => {
self.hovering = false;
self.dropped = data.paths.clone();
ctx.request_paint();
}
_ => {}
}
}
}