feat(viewer): add object fit functionality for image display
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
use gpui::{
|
||||
App, Application, Bounds, Context, FocusHandle, KeyBinding, Window, WindowBounds,
|
||||
App, Application, Bounds, Context, FocusHandle, KeyBinding, ObjectFit, Window, WindowBounds,
|
||||
WindowOptions, actions, div, img, prelude::*, px, rgb, size,
|
||||
};
|
||||
use nalgebra::Vector2;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct MMViewer {
|
||||
files: Vec<PathBuf>,
|
||||
current: usize,
|
||||
zoom: f32,
|
||||
pan: Vector2<f32>,
|
||||
focus: FocusHandle,
|
||||
fit: ObjectFit,
|
||||
}
|
||||
|
||||
actions!(mm, [Quit, NextImage, PrevImage, FirstImage, LastImage]);
|
||||
actions!(mm, [Quit, NextImage, PrevImage, FirstImage, LastImage, Fit]);
|
||||
|
||||
impl Render for MMViewer {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
@@ -25,6 +25,7 @@ impl Render for MMViewer {
|
||||
.on_action(cx.listener(Self::prev_image))
|
||||
.on_action(cx.listener(Self::first_image))
|
||||
.on_action(cx.listener(Self::last_image))
|
||||
.on_action(cx.listener(Self::object_fit))
|
||||
.on_action(cx.listener(Self::quit))
|
||||
.flex()
|
||||
.size_full()
|
||||
@@ -32,12 +33,22 @@ impl Render for MMViewer {
|
||||
.justify_center()
|
||||
.bg(rgb(0x505050))
|
||||
.child(if let Some(file) = self.files.get(self.current) {
|
||||
div().flex().flex_row().size_full().justify_center().child(
|
||||
img(file.clone())
|
||||
.object_fit(self.fit())
|
||||
.size_full()
|
||||
.with_loading(|| {
|
||||
div()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.size_full()
|
||||
.child("Loading...")
|
||||
.bg(rgb(0xffffff))
|
||||
.justify_center()
|
||||
.child(img(file.clone()).size_full())
|
||||
.into_any()
|
||||
// .align_center()
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
div().child(format!(
|
||||
"No image found (index: {}, total: {})",
|
||||
@@ -53,6 +64,16 @@ impl MMViewer {
|
||||
self.focus.clone()
|
||||
}
|
||||
|
||||
fn fit(&self) -> ObjectFit {
|
||||
match self.fit {
|
||||
ObjectFit::Fill => ObjectFit::Fill,
|
||||
ObjectFit::Contain => ObjectFit::Contain,
|
||||
ObjectFit::Cover => ObjectFit::Cover,
|
||||
ObjectFit::ScaleDown => ObjectFit::ScaleDown,
|
||||
ObjectFit::None => ObjectFit::None,
|
||||
}
|
||||
}
|
||||
|
||||
fn next_image(&mut self, _: &NextImage, _: &mut Window, cx: &mut Context<Self>) {
|
||||
if self.current + 1 < self.files.len() {
|
||||
self.current += 1;
|
||||
@@ -81,6 +102,17 @@ impl MMViewer {
|
||||
}
|
||||
}
|
||||
|
||||
fn object_fit(&mut self, _: &Fit, _: &mut Window, cx: &mut Context<Self>) {
|
||||
match self.fit {
|
||||
ObjectFit::Fill => self.fit = ObjectFit::Contain,
|
||||
ObjectFit::Contain => self.fit = ObjectFit::Cover,
|
||||
ObjectFit::Cover => self.fit = ObjectFit::ScaleDown,
|
||||
ObjectFit::ScaleDown => self.fit = ObjectFit::None,
|
||||
ObjectFit::None => self.fit = ObjectFit::Fill,
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn quit(&mut self, _: &Quit, _: &mut Window, cx: &mut Context<Self>) {
|
||||
cx.quit();
|
||||
}
|
||||
@@ -88,7 +120,7 @@ impl MMViewer {
|
||||
|
||||
pub fn run(files: Vec<PathBuf>) {
|
||||
Application::new().run(|cx: &mut App| {
|
||||
let bounds = Bounds::centered(None, size(px(800f32), px(600f32)), cx);
|
||||
let bounds = Bounds::maximized(None, cx);
|
||||
cx.bind_keys([
|
||||
KeyBinding::new("q", Quit, None),
|
||||
KeyBinding::new("Escape", Quit, None),
|
||||
@@ -98,6 +130,7 @@ pub fn run(files: Vec<PathBuf>) {
|
||||
KeyBinding::new("left", PrevImage, None),
|
||||
KeyBinding::new("shift-g", LastImage, None),
|
||||
KeyBinding::new("g", FirstImage, None),
|
||||
KeyBinding::new("c", Fit, None),
|
||||
]);
|
||||
let window = cx
|
||||
.open_window(
|
||||
@@ -113,6 +146,7 @@ pub fn run(files: Vec<PathBuf>) {
|
||||
zoom: 1.0,
|
||||
pan: Vector2::new(0.0, 0.0),
|
||||
focus: cx.focus_handle(),
|
||||
fit: ObjectFit::Contain,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user