From 63e05c994bb79ee4c17f35a80f95c64dfa88bcf2 Mon Sep 17 00:00:00 2001 From: uttarayan21 Date: Wed, 8 Oct 2025 02:35:58 +0530 Subject: [PATCH] feat(viewer): add object fit functionality for image display --- src/viewer.rs | 54 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/viewer.rs b/src/viewer.rs index 63655b7..32789ba 100644 --- a/src/viewer.rs +++ b/src/viewer.rs @@ -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, current: usize, zoom: f32, pan: Vector2, 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) -> 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()).size_full()) + 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() + .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) { 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) { + 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) { cx.quit(); } @@ -88,7 +120,7 @@ impl MMViewer { pub fn run(files: Vec) { 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) { 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) { zoom: 1.0, pan: Vector2::new(0.0, 0.0), focus: cx.focus_handle(), + fit: ObjectFit::Contain, }) }, )