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