Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22de9274b1 | ||
|
|
9384b50397 |
62
Cargo.lock
generated
62
Cargo.lock
generated
@@ -677,6 +677,22 @@ dependencies = [
|
||||
"piper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bounding-box"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/aftershootco/ndcv-bridge#16c3b2e9105d3528a6ffbc2e1fe9046cb6930a6e"
|
||||
dependencies = [
|
||||
"color",
|
||||
"itertools 0.14.0",
|
||||
"nalgebra",
|
||||
"ndarray",
|
||||
"num",
|
||||
"ordered-float",
|
||||
"simba",
|
||||
"thiserror 2.0.17",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.12.0"
|
||||
@@ -983,6 +999,12 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a18ef4657441fb193b65f34dc39b3781f0dfec23d3bd94d0eeb4e88cde421edb"
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
@@ -3153,6 +3175,7 @@ name = "mm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ash",
|
||||
"bounding-box",
|
||||
"clap",
|
||||
"clap_complete",
|
||||
"error-stack",
|
||||
@@ -3255,6 +3278,21 @@ dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndarray"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
|
||||
dependencies = [
|
||||
"matrixmultiply",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"rawpointer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
@@ -3600,6 +3638,15 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-stream"
|
||||
version = "0.2.0"
|
||||
@@ -3787,6 +3834,21 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "postage"
|
||||
version = "0.5.0"
|
||||
|
||||
@@ -14,10 +14,14 @@ thiserror = "2.0"
|
||||
tokio = "1.43.1"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
gpui = { git = "https://github.com/uttarayan21/zed", default-features = false, features = ["wayland"] }
|
||||
gpui = { git = "https://github.com/uttarayan21/zed", default-features = false, features = [
|
||||
"wayland",
|
||||
] }
|
||||
nalgebra = "0.34.1"
|
||||
wayland-sys = { version = "0.31.7", default-features = false }
|
||||
wayland-backend = { version = "0.3.11", default-features = false }
|
||||
ignore = { version = "0.4.23", features = ["simd-accel"] }
|
||||
unicode-segmentation = "1.12.0"
|
||||
ash = { version = "0.38.0", features = ["linked"] }
|
||||
|
||||
bounding-box = { git = "https://github.com/aftershootco/ndcv-bridge" }
|
||||
|
||||
6
assets/arrow_circle.svg
Normal file
6
assets/arrow_circle.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 8C3 6.67392 3.52678 5.40215 4.46446 4.46447C5.40214 3.52679 6.67391 3.00001 7.99999 3.00001C9.39779 3.00527 10.7394 3.55069 11.7444 4.52223L13 5.77778" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M13 3.00001V5.77778H10.2222" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M13 8C13 9.32608 12.4732 10.5978 11.5355 11.5355C10.5978 12.4732 9.32607 13 7.99999 13C6.60219 12.9947 5.26054 12.4493 4.25555 11.4778L3 10.2222" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.77777 10.2222H3V13" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 748 B |
10
src/main.rs
10
src/main.rs
@@ -18,11 +18,11 @@ pub fn main() -> Result<()> {
|
||||
.change_context(Error)
|
||||
.attach("Failed to canonicalize path")?;
|
||||
let files = walker(&input);
|
||||
if files.is_empty() {
|
||||
return Err(Error)
|
||||
.attach("No files found in the folder")
|
||||
.attach(input.display().to_string());
|
||||
}
|
||||
// if files.is_empty() {
|
||||
// return Err(Error)
|
||||
// .attach("No files found in the folder")
|
||||
// .attach(input.display().to_string());
|
||||
// }
|
||||
viewer::run(files);
|
||||
|
||||
Ok(())
|
||||
|
||||
115
src/viewer.rs
115
src/viewer.rs
@@ -1,21 +1,54 @@
|
||||
use gpui::{
|
||||
App, Application, Bounds, Context, FocusHandle, KeyBinding, ObjectFit, Window, WindowBounds,
|
||||
WindowOptions, actions, div, img, prelude::*, px, rgb, size,
|
||||
Animation, AnimationExt, App, Application, Bounds, Canvas, Context, FocusHandle, KeyBinding,
|
||||
ObjectFit, Transformation, Window, WindowBounds, WindowOptions, actions, black, bounce, canvas,
|
||||
div, ease_in_out, img, percentage, prelude::*, pulsating_between, px, rgb, rgba, size, svg,
|
||||
};
|
||||
use nalgebra::Vector2;
|
||||
use std::path::PathBuf;
|
||||
use std::{path::PathBuf, time::Duration};
|
||||
|
||||
struct MMViewer {
|
||||
files: Vec<PathBuf>,
|
||||
current: usize,
|
||||
zoom: f32,
|
||||
pan: Vector2<f32>,
|
||||
last: Option<usize>,
|
||||
// zoom: f32,
|
||||
// pan: Vector2<f32>,
|
||||
focus: FocusHandle,
|
||||
fit: ObjectFit,
|
||||
}
|
||||
|
||||
actions!(mm, [Quit, NextImage, PrevImage, FirstImage, LastImage, Fit]);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoundingBox {
|
||||
inner: bounding_box::Aabb2<f32>,
|
||||
pub width: gpui::Pixels,
|
||||
pub color: gpui::Rgba,
|
||||
}
|
||||
|
||||
impl From<bounding_box::Aabb2<f32>> for BoundingBox {
|
||||
fn from(aabb: bounding_box::Aabb2<f32>) -> Self {
|
||||
Self {
|
||||
inner: aabb,
|
||||
width: px(2.0),
|
||||
color: gpui::green().to_rgb(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl Render for BoundingBox {
|
||||
// fn render(&mut self, window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
// let mut builder = gpui::PathBuilder::stroke(self.width);
|
||||
// let aabb = self.inner;
|
||||
// builder.move_to(gpui::Point::new(px(aabb.x1()), px(aabb.y1())));
|
||||
// builder.line_to(gpui::Point::new(px(aabb.x2()), px(aabb.y1())));
|
||||
// builder.line_to(gpui::Point::new(px(aabb.x2()), px(aabb.y2())));
|
||||
// builder.line_to(gpui::Point::new(px(aabb.x1()), px(aabb.y2())));
|
||||
// builder.line_to(gpui::Point::new(px(aabb.x1()), px(aabb.y1())));
|
||||
// let path = builder.build().expect("Failed to build path");
|
||||
// window.paint_path(path, gpui::green())
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Render for MMViewer {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
div()
|
||||
@@ -31,34 +64,59 @@ impl Render for MMViewer {
|
||||
.size_full()
|
||||
.flex_col()
|
||||
.justify_center()
|
||||
.bg(rgb(0x505050))
|
||||
.bg(rgba(0xffffffff))
|
||||
.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()
|
||||
.into_any()
|
||||
}),
|
||||
)
|
||||
div()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.size_full()
|
||||
.justify_center()
|
||||
.child(
|
||||
img(file.clone())
|
||||
.id("loupe")
|
||||
.object_fit(self.fit())
|
||||
.size_full()
|
||||
.with_loading(|| Self::loading().into_any_element()),
|
||||
)
|
||||
.relative()
|
||||
.into_any()
|
||||
} else {
|
||||
div().child(format!(
|
||||
"No image found (index: {}, total: {})",
|
||||
self.current,
|
||||
self.files.len()
|
||||
))
|
||||
Self::loading().into_any_element()
|
||||
// div().child(format!(
|
||||
// "No image found (index: {}, total: {})",
|
||||
// self.current,
|
||||
// self.files.len()
|
||||
// ))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const ARROW_CIRCLE_SVG: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/assets/arrow_circle.svg");
|
||||
|
||||
fn wheel() -> impl IntoElement {
|
||||
svg()
|
||||
.path(ARROW_CIRCLE_SVG)
|
||||
.flex_none()
|
||||
.size_full()
|
||||
.text_color(black())
|
||||
.with_animation(
|
||||
"wheel",
|
||||
Animation::new(Duration::from_secs(2))
|
||||
.repeat()
|
||||
.with_easing(bounce(ease_in_out)),
|
||||
move |svg, delta| svg.with_transformation(Transformation::rotate(percentage(delta))),
|
||||
)
|
||||
}
|
||||
|
||||
impl MMViewer {
|
||||
fn loading() -> impl IntoElement {
|
||||
div()
|
||||
.size_full()
|
||||
.flex_none()
|
||||
.bg(rgb(0xff00ff))
|
||||
.child(wheel())
|
||||
}
|
||||
|
||||
fn focus_handle(&self, _: &App) -> FocusHandle {
|
||||
self.focus.clone()
|
||||
}
|
||||
@@ -143,8 +201,9 @@ pub fn run(files: Vec<PathBuf>) {
|
||||
cx.new(|cx| MMViewer {
|
||||
files,
|
||||
current: 0,
|
||||
zoom: 1.0,
|
||||
pan: Vector2::new(0.0, 0.0),
|
||||
last: None,
|
||||
// zoom: 1.0,
|
||||
// pan: Vector2::new(0.0, 0.0),
|
||||
focus: cx.focus_handle(),
|
||||
fit: ObjectFit::Contain,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user