mirror of
https://github.com/itsjunetime/tdf.git
synced 2026-06-01 23:51:46 -04:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9df806a8f | |||
| 5e7ec97b43 |
+42
-5
@@ -1,11 +1,14 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
future::poll_fn,
|
||||||
io::{stdout, Read, Write},
|
io::{stdout, Read, Write},
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
path::PathBuf
|
path::PathBuf,
|
||||||
|
task::Poll
|
||||||
};
|
};
|
||||||
|
|
||||||
use converter::{run_conversion_loop, ConvertedPage, ConverterMsg};
|
use converter::{run_conversion_loop, ConvertedPage, ConverterMsg};
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
|
event::{Event, EventStream, MouseEvent, MouseEventKind},
|
||||||
execute,
|
execute,
|
||||||
terminal::{
|
terminal::{
|
||||||
disable_raw_mode, enable_raw_mode, window_size, EndSynchronizedUpdate,
|
disable_raw_mode, enable_raw_mode, window_size, EndSynchronizedUpdate,
|
||||||
@@ -14,7 +17,7 @@ use crossterm::{
|
|||||||
};
|
};
|
||||||
use futures_util::{stream::StreamExt, FutureExt};
|
use futures_util::{stream::StreamExt, FutureExt};
|
||||||
use glib::{LogField, LogLevel, LogWriterOutput};
|
use glib::{LogField, LogLevel, LogWriterOutput};
|
||||||
use notify::{Event, EventKind, RecursiveMode, Watcher};
|
use notify::{EventKind, RecursiveMode, Watcher};
|
||||||
use ratatui::{backend::CrosstermBackend, Terminal};
|
use ratatui::{backend::CrosstermBackend, Terminal};
|
||||||
use ratatui_image::picker::Picker;
|
use ratatui_image::picker::Picker;
|
||||||
use renderer::{RenderError, RenderInfo, RenderNotif};
|
use renderer::{RenderError, RenderInfo, RenderNotif};
|
||||||
@@ -123,7 +126,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
// We need to create `picker` on this thread because if we create it on the `renderer` thread,
|
// We need to create `picker` on this thread because if we create it on the `renderer` thread,
|
||||||
// it messes up something with user input. Input never makes it to the crossterm thing
|
// it messes up something with user input. Input never makes it to the crossterm thing
|
||||||
let picker = Picker::from_query_stdio()?;
|
let picker = Picker::from_query_stdio()?;
|
||||||
|
|
||||||
// then we want to spawn off the rendering task
|
// then we want to spawn off the rendering task
|
||||||
// We need to use the thread::spawn API so that this exists in a thread not owned by tokio,
|
// We need to use the thread::spawn API so that this exists in a thread not owned by tokio,
|
||||||
@@ -132,7 +135,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
renderer::start_rendering(&file_path, render_tx, render_rx, window_size)
|
renderer::start_rendering(&file_path, render_tx, render_rx, window_size)
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut ev_stream = crossterm::event::EventStream::new();
|
let mut ev_stream = EventStream::new();
|
||||||
|
|
||||||
let (to_converter, from_main) = flume::unbounded();
|
let (to_converter, from_main) = flume::unbounded();
|
||||||
let (to_main, from_converter) = flume::unbounded();
|
let (to_main, from_converter) = flume::unbounded();
|
||||||
@@ -175,6 +178,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// If we can't get user input, just crash.
|
// If we can't get user input, just crash.
|
||||||
let ev = ev.expect("Couldn't get any user input");
|
let ev = ev.expect("Couldn't get any user input");
|
||||||
|
|
||||||
|
flush_if_mouse(&ev, &mut ev_stream).await;
|
||||||
|
|
||||||
match tui.handle_event(&ev) {
|
match tui.handle_event(&ev) {
|
||||||
None => needs_redraw = false,
|
None => needs_redraw = false,
|
||||||
Some(action) => match action {
|
Some(action) => match action {
|
||||||
@@ -244,7 +249,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
fn on_notify_ev(
|
fn on_notify_ev(
|
||||||
to_tui_tx: flume::Sender<Result<RenderInfo, RenderError>>,
|
to_tui_tx: flume::Sender<Result<RenderInfo, RenderError>>,
|
||||||
to_render_tx: flume::Sender<RenderNotif>
|
to_render_tx: flume::Sender<RenderNotif>
|
||||||
) -> impl Fn(notify::Result<Event>) {
|
) -> impl Fn(notify::Result<notify::Event>) {
|
||||||
move |res| match res {
|
move |res| match res {
|
||||||
// If we get an error here, and then an error sending, everything's going wrong. Just give
|
// If we get an error here, and then an error sending, everything's going wrong. Just give
|
||||||
// up lol.
|
// up lol.
|
||||||
@@ -267,3 +272,35 @@ fn on_notify_ev(
|
|||||||
fn noop(_: LogLevel, _: &[LogField<'_>]) -> LogWriterOutput {
|
fn noop(_: LogLevel, _: &[LogField<'_>]) -> LogWriterOutput {
|
||||||
LogWriterOutput::Handled
|
LogWriterOutput::Handled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn flush_if_mouse(ev: &Event, ev_stream: &mut EventStream) {
|
||||||
|
// If you have a high scroll sensitivity, on some platforms, crossterm sends 2+ mouse events per
|
||||||
|
// scroll. However, because tdf scrolls pages once per mouse event, that means that they can't
|
||||||
|
// scroll the pages of their PDF as they would expect - it jumps multiple pages per one scroll.
|
||||||
|
// So this just flushes the event queue once we detect a scroll event to make sure those extra
|
||||||
|
// scrolls are ignored.
|
||||||
|
//
|
||||||
|
// Theoretically, this introduces a race condition where events that arrive in between the
|
||||||
|
// processing of `ev` and the time we call `poll_next_unpin` can get ignored, but that's a very
|
||||||
|
// very small amount of time, so unlikely to happen. However, if that does become an issue, we
|
||||||
|
// can just flush the event queue until we see a non-scroll event, then store that event in a
|
||||||
|
// future that will return it next time we call `tokio::select!` in the main loop. That'll make
|
||||||
|
// sure we don't miss anything.
|
||||||
|
if let Event::Mouse(MouseEvent {
|
||||||
|
kind:
|
||||||
|
MouseEventKind::ScrollUp
|
||||||
|
| MouseEventKind::ScrollDown
|
||||||
|
| MouseEventKind::ScrollLeft
|
||||||
|
| MouseEventKind::ScrollRight,
|
||||||
|
..
|
||||||
|
}) = ev
|
||||||
|
{
|
||||||
|
poll_fn(|ctx| {
|
||||||
|
while ev_stream.poll_next_unpin(ctx).is_ready() {
|
||||||
|
println!("got another mouse event!");
|
||||||
|
}
|
||||||
|
Poll::Ready(())
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user