feat(viewer): add object fit functionality for image display
Some checks failed
build / checks-matrix (push) Successful in 19m20s
build / checks-build (push) Has been cancelled
docs / docs (push) Has been cancelled
build / codecov (push) Has been cancelled

This commit is contained in:
uttarayan21
2025-10-08 02:35:58 +05:30
parent 935ac583f7
commit 63e05c994b

View File

@@ -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,
})
},
)