diff --git a/Cargo.lock b/Cargo.lock index 4f93ec2..bd1ab81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1522,9 +1522,9 @@ dependencies = [ [[package]] name = "error-stack" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe413319145d1063f080f27556fd30b1d70b01e2ba10c2a6e40d4be982ffc5d1" +checksum = "b878b3fac9613c3c7f22eb70bc8a3c6ebdc03cc11479ee60fde1692d747fd45f" dependencies = [ "anyhow", "rustc_version", @@ -2322,24 +2322,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hello" -version = "0.1.0" -dependencies = [ - "clap", - "clap_complete", - "error-stack", - "gpui", - "ignore", - "nalgebra", - "thiserror 2.0.12", - "tokio", - "tracing", - "tracing-subscriber", - "wayland-backend", - "wayland-sys", -] - [[package]] name = "hermit-abi" version = "0.5.2" @@ -3152,6 +3134,25 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "mm" +version = "0.1.0" +dependencies = [ + "clap", + "clap_complete", + "error-stack", + "gpui", + "ignore", + "nalgebra", + "thiserror 2.0.12", + "tokio", + "tracing", + "tracing-subscriber", + "unicode-segmentation", + "wayland-backend", + "wayland-sys", +] + [[package]] name = "moxcms" version = "0.7.6" diff --git a/Cargo.toml b/Cargo.toml index 51e214f..5fc71c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hello" +name = "mm" version = "0.1.0" edition = "2024" license = "MIT" @@ -9,7 +9,7 @@ license = "MIT" [dependencies] clap = { version = "4.5", features = ["derive"] } clap_complete = "4.5" -error-stack = "0.5" +error-stack = "0.6" thiserror = "2.0" tokio = "1.43.1" tracing = "0.1" @@ -19,3 +19,4 @@ 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" diff --git a/src/main.rs b/src/main.rs index 5cca65a..6306e67 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ pub fn main() -> Result<()> { fn walker(input: impl AsRef) -> Vec { let mut tb = ignore::types::TypesBuilder::new(); tb.add("image", "*.jpg").expect("Failed to add image type"); + tb.add("image", "*.png").expect("Failed to add image type"); ignore::WalkBuilder::new(input) .types( tb.select("image") diff --git a/src/viewer.rs b/src/viewer.rs index a48889f..e36c429 100644 --- a/src/viewer.rs +++ b/src/viewer.rs @@ -1,5 +1,5 @@ use gpui::{ - App, Application, Bounds, Context, KeyBinding, SharedString, Window, WindowBounds, + App, Application, Bounds, Context, FocusHandle, KeyBinding, SharedString, Window, WindowBounds, WindowOptions, actions, div, img, prelude::*, px, rgb, rgba, size, }; use nalgebra::Vector2; @@ -11,17 +11,23 @@ struct MMViewer { current: usize, zoom: f32, pan: Vector2, + focus: FocusHandle, } -actions!(mm, [Quit, NextImage, PrevImage]); +actions!(mm, [Quit, NextImage, PrevImage, FirstImage, LastImage]); impl Render for MMViewer { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { div() - .size_full() - .flex() + .key_context("MMViewer") + .track_focus(&self.focus_handle(cx)) .on_action(cx.listener(Self::next_image)) .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::quit)) + .flex() + .size_full() .flex_col() .justify_center() .bg(rgb(0x505050)) @@ -43,48 +49,79 @@ impl Render for MMViewer { } impl MMViewer { + fn focus_handle(&self, _: &App) -> FocusHandle { + self.focus.clone() + } + fn next_image(&mut self, _: &NextImage, _: &mut Window, cx: &mut Context) { - dbg!("aasdfasdf"); if self.current + 1 < self.files.len() { self.current += 1; cx.notify(); } } + + fn last_image(&mut self, _: &LastImage, _: &mut Window, cx: &mut Context) { + if !self.files.is_empty() { + self.current = self.files.len() - 1; + cx.notify(); + } + } + fn prev_image(&mut self, _: &PrevImage, _: &mut Window, cx: &mut Context) { - dbg!("aasdfascawsdfasdfdf"); if self.current > 0 { self.current -= 1; cx.notify(); } } + + fn first_image(&mut self, _: &FirstImage, _: &mut Window, cx: &mut Context) { + if !self.files.is_empty() { + self.current = 0; + cx.notify(); + } + } + + fn quit(&mut self, _: &Quit, _: &mut Window, cx: &mut Context) { + cx.quit(); + } } pub fn run(files: Vec) { Application::new().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(800f32), px(600f32)), cx); - cx.on_action(|_: &Quit, cx| cx.quit()); cx.bind_keys([ KeyBinding::new("q", Quit, None), KeyBinding::new("Escape", Quit, None), KeyBinding::new("j", NextImage, None), + KeyBinding::new("right", NextImage, None), KeyBinding::new("k", PrevImage, None), + KeyBinding::new("left", PrevImage, None), + KeyBinding::new("shift-g", LastImage, None), + KeyBinding::new("g", FirstImage, None), ]); - cx.open_window( - WindowOptions { - window_bounds: Some(WindowBounds::Windowed(bounds)), - // bounds: WindowBounds::Fixed(bounds), - ..Default::default() - }, - |_, cx| { - cx.new(|_| MMViewer { - files, - current: 0, - zoom: 1.0, - pan: Vector2::new(0.0, 0.0), - }) - }, - ) - .expect("Failed to open window"); - cx.activate(true); + let window = cx + .open_window( + WindowOptions { + window_bounds: Some(WindowBounds::Windowed(bounds)), + titlebar: None, + ..Default::default() + }, + |_, cx| { + cx.new(|cx| MMViewer { + files, + current: 0, + zoom: 1.0, + pan: Vector2::new(0.0, 0.0), + focus: cx.focus_handle(), + }) + }, + ) + .expect("Failed to open window"); + window + .update(cx, |view, window, cx| { + window.focus(&view.focus_handle(cx)); + cx.activate(true); + }) + .expect("Failed to focus"); }); }