Skip to content

Commit 2a54572

Browse files
committed
feat: support customizable alignment for image display
1 parent fbf9b3d commit 2a54572

File tree

15 files changed

+262
-192
lines changed

15 files changed

+262
-192
lines changed

yazi-adapter/src/adapter.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use ratatui::layout::Rect;
55
use tracing::warn;
66
use yazi_shared::env_exists;
77

8-
use crate::{Brand, Emulator, SHOWN, TMUX, WSL, drivers};
8+
use crate::{Brand, Emulator, Offset, SHOWN, TMUX, WSL, drivers};
99

1010
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1111
pub enum Adapter {
@@ -35,18 +35,18 @@ impl Display for Adapter {
3535
}
3636

3737
impl Adapter {
38-
pub async fn image_show(self, path: &Path, max: Rect) -> Result<Rect> {
38+
pub async fn image_show(self, path: &Path, max: Rect, offset: Option<Offset>) -> Result<Rect> {
3939
if max.is_empty() {
4040
return Ok(Rect::default());
4141
}
4242

4343
match self {
44-
Self::Kgp => drivers::Kgp::image_show(path, max).await,
45-
Self::KgpOld => drivers::KgpOld::image_show(path, max).await,
46-
Self::Iip => drivers::Iip::image_show(path, max).await,
47-
Self::Sixel => drivers::Sixel::image_show(path, max).await,
48-
Self::X11 | Self::Wayland => drivers::Ueberzug::image_show(path, max).await,
49-
Self::Chafa => drivers::Chafa::image_show(path, max).await,
44+
Self::Kgp => drivers::Kgp::image_show(path, max, offset).await,
45+
Self::KgpOld => drivers::KgpOld::image_show(path, max, offset).await,
46+
Self::Iip => drivers::Iip::image_show(path, max, offset).await,
47+
Self::Sixel => drivers::Sixel::image_show(path, max, offset).await,
48+
Self::X11 | Self::Wayland => drivers::Ueberzug::image_show(path, max, offset).await,
49+
Self::Chafa => drivers::Chafa::image_show(path, max, offset).await,
5050
}
5151
}
5252

yazi-adapter/src/drivers/chafa.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ use std::{io::Write, path::Path, process::Stdio};
33
use ansi_to_tui::IntoText;
44
use anyhow::{Result, bail};
55
use crossterm::{cursor::MoveTo, queue};
6-
use ratatui::layout::Rect;
6+
use ratatui::layout::{Rect, Size};
77
use tokio::process::Command;
88

9-
use crate::{Adapter, Emulator};
9+
use crate::{Adapter, Emulator, Offset};
1010

1111
pub(crate) struct Chafa;
1212

1313
impl Chafa {
14-
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
14+
pub(crate) async fn image_show(path: &Path, max: Rect, offset: Option<Offset>) -> Result<Rect> {
1515
let output = Command::new("chafa")
1616
.args([
1717
"-f",
@@ -46,11 +46,13 @@ impl Chafa {
4646
bail!("failed to parse chafa output");
4747
};
4848

49-
let area = Rect {
50-
x: max.x,
51-
y: max.y,
52-
width: first.width() as u16,
53-
height: lines.len() as u16,
49+
let area = {
50+
let width = first.width() as u16;
51+
let height = lines.len() as u16;
52+
let offset = offset.unwrap_or_else(|| {
53+
Offset::from((Size { width, height }, Size { width: max.width, height: max.height }))
54+
});
55+
Rect { x: max.x + offset.x, y: max.y + offset.y, width, height }
5456
};
5557

5658
Adapter::Chafa.image_hide()?;

yazi-adapter/src/drivers/iip.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ use image::{DynamicImage, ExtendedColorType, ImageEncoder, codecs::{jpeg::JpegEn
77
use ratatui::layout::Rect;
88
use yazi_config::PREVIEW;
99

10-
use crate::{CLOSE, Emulator, Image, START, adapter::Adapter};
10+
use crate::{CLOSE, Emulator, Image, Offset, START, adapter::Adapter};
1111

1212
pub(crate) struct Iip;
1313

1414
impl Iip {
15-
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
15+
pub(crate) async fn image_show(path: &Path, max: Rect, offset: Option<Offset>) -> Result<Rect> {
1616
let img = Image::downscale(path, max).await?;
17-
let area = Image::pixel_area((img.width(), img.height()), max);
17+
let area = Image::pixel_area((img.width(), img.height()), max, offset);
1818
let b = Self::encode(img).await?;
1919

2020
Adapter::Iip.image_hide()?;

yazi-adapter/src/drivers/kgp.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crossterm::{cursor::MoveTo, queue};
77
use image::DynamicImage;
88
use ratatui::layout::Rect;
99

10-
use crate::{CLOSE, ESCAPE, Emulator, START, adapter::Adapter, image::Image};
10+
use crate::{CLOSE, ESCAPE, Emulator, Offset, START, adapter::Adapter, image::Image};
1111

1212
static DIACRITICS: [char; 297] = [
1313
'\u{0305}',
@@ -312,9 +312,9 @@ static DIACRITICS: [char; 297] = [
312312
pub(crate) struct Kgp;
313313

314314
impl Kgp {
315-
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
315+
pub(crate) async fn image_show(path: &Path, max: Rect, offset: Option<Offset>) -> Result<Rect> {
316316
let img = Image::downscale(path, max).await?;
317-
let area = Image::pixel_area((img.width(), img.height()), max);
317+
let area = Image::pixel_area((img.width(), img.height()), max, offset);
318318

319319
let b1 = Self::encode(img).await?;
320320
let b2 = Self::place(&area)?;

yazi-adapter/src/drivers/kgp_old.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ use base64::{Engine, engine::general_purpose};
66
use image::DynamicImage;
77
use ratatui::layout::Rect;
88

9-
use crate::{CLOSE, ESCAPE, Emulator, Image, START, adapter::Adapter};
9+
use crate::{CLOSE, ESCAPE, Emulator, Image, Offset, START, adapter::Adapter};
1010

1111
pub(crate) struct KgpOld;
1212

1313
impl KgpOld {
14-
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
14+
pub(crate) async fn image_show(path: &Path, max: Rect, offset: Option<Offset>) -> Result<Rect> {
1515
let img = Image::downscale(path, max).await?;
16-
let area = Image::pixel_area((img.width(), img.height()), max);
16+
let area = Image::pixel_area((img.width(), img.height()), max, offset);
1717
let b = Self::encode(img).await?;
1818

1919
Adapter::KgpOld.image_hide()?;

yazi-adapter/src/drivers/sixel.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ use image::DynamicImage;
77
use ratatui::layout::Rect;
88
use yazi_config::PREVIEW;
99

10-
use crate::{CLOSE, ESCAPE, Emulator, Image, START, adapter::Adapter};
10+
use crate::{CLOSE, ESCAPE, Emulator, Image, Offset, START, adapter::Adapter};
1111

1212
pub(crate) struct Sixel;
1313

1414
impl Sixel {
15-
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
15+
pub(crate) async fn image_show(path: &Path, max: Rect, offset: Option<Offset>) -> Result<Rect> {
1616
let img = Image::downscale(path, max).await?;
17-
let area = Image::pixel_area((img.width(), img.height()), max);
17+
let area = Image::pixel_area((img.width(), img.height()), max, offset);
1818
let b = Self::encode(img).await?;
1919

2020
Adapter::Sixel.image_hide()?;

yazi-adapter/src/drivers/ueberzug.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use std::{path::{Path, PathBuf}, process::Stdio};
22

33
use anyhow::{Result, bail};
4-
use ratatui::layout::Rect;
4+
use ratatui::layout::{Rect, Size};
55
use tokio::{io::AsyncWriteExt, process::{Child, Command}, sync::mpsc::{self, UnboundedSender}};
66
use tracing::{debug, warn};
77
use yazi_config::PREVIEW;
88
use yazi_shared::{RoCell, env_exists};
99

10-
use crate::{Adapter, Dimension};
10+
use crate::{Adapter, Dimension, Offset};
1111

1212
type Cmd = Option<(PathBuf, Rect)>;
1313

@@ -41,7 +41,7 @@ impl Ueberzug {
4141
DEMON.init(Some(tx))
4242
}
4343

44-
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
44+
pub(crate) async fn image_show(path: &Path, max: Rect, offset: Option<Offset>) -> Result<Rect> {
4545
let Some(tx) = &*DEMON else {
4646
bail!("uninitialized ueberzugpp");
4747
};
@@ -50,11 +50,13 @@ impl Ueberzug {
5050
let (w, h) = tokio::task::spawn_blocking(move || image::image_dimensions(p)).await??;
5151

5252
let area = Dimension::ratio()
53-
.map(|(r1, r2)| Rect {
54-
x: max.x,
55-
y: max.y,
56-
width: max.width.min((w.min(PREVIEW.max_width as _) as f64 / r1).ceil() as _),
57-
height: max.height.min((h.min(PREVIEW.max_height as _) as f64 / r2).ceil() as _),
53+
.map(|(r1, r2)| {
54+
let width = max.width.min((w.min(PREVIEW.max_width as _) as f64 / r1).ceil() as _);
55+
let height = max.height.min((h.min(PREVIEW.max_height as _) as f64 / r2).ceil() as _);
56+
let offset = offset.unwrap_or_else(|| {
57+
Offset::from((Size { width, height }, Size { width: max.width, height: max.height }))
58+
});
59+
Rect { x: max.x + offset.x, y: max.y + offset.y, width, height }
5860
})
5961
.unwrap_or(max);
6062

yazi-adapter/src/image.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use std::path::{Path, PathBuf};
22

33
use anyhow::Result;
44
use image::{DynamicImage, ExtendedColorType, ImageDecoder, ImageEncoder, ImageError, ImageReader, ImageResult, Limits, codecs::{jpeg::JpegEncoder, png::PngEncoder}, imageops::FilterType, metadata::Orientation};
5-
use ratatui::layout::Rect;
5+
use ratatui::layout::{Rect, Size};
66
use yazi_config::{PREVIEW, TASKS};
77

8-
use crate::Dimension;
8+
use crate::{Dimension, Offset};
99

1010
pub struct Image;
1111

@@ -73,13 +73,15 @@ impl Image {
7373
.unwrap_or((PREVIEW.max_width, PREVIEW.max_height))
7474
}
7575

76-
pub(super) fn pixel_area(size: (u32, u32), rect: Rect) -> Rect {
76+
pub(super) fn pixel_area(size: (u32, u32), rect: Rect, offset: Option<Offset>) -> Rect {
7777
Dimension::ratio()
78-
.map(|(r1, r2)| Rect {
79-
x: rect.x,
80-
y: rect.y,
81-
width: (size.0 as f64 / r1).ceil() as u16,
82-
height: (size.1 as f64 / r2).ceil() as u16,
78+
.map(|(r1, r2)| {
79+
let width = (size.0 as f64 / r1).ceil() as u16;
80+
let height = (size.1 as f64 / r2).ceil() as u16;
81+
let offset = offset.unwrap_or_else(|| {
82+
Offset::from((Size { width, height }, Size { width: rect.width, height: rect.height }))
83+
});
84+
Rect { x: rect.x + offset.x, y: rect.y + offset.y, width, height }
8385
})
8486
.unwrap_or(rect)
8587
}

yazi-adapter/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
yazi_macro::mod_pub!(drivers);
44

5-
yazi_macro::mod_flat!(adapter brand dimension emulator image info mux unknown);
5+
yazi_macro::mod_flat!(adapter brand dimension emulator image info mux offset unknown);
66

77
use yazi_shared::{RoCell, SyncCell, env_exists, in_wsl};
88

yazi-adapter/src/offset.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use ratatui::layout::Size;
2+
use yazi_config::{PREVIEW, preview::{HorizontalAlignment, VerticalAlignment}};
3+
4+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
5+
pub struct Offset {
6+
pub x: u16,
7+
pub y: u16,
8+
}
9+
10+
impl From<(Size, Size)> for Offset {
11+
fn from(value: (Size, Size)) -> Self {
12+
let inner = value.0;
13+
let outer = value.1;
14+
let offset_x = match PREVIEW.alignment.horizontal {
15+
HorizontalAlignment::Left => 0,
16+
HorizontalAlignment::Center => (outer.width - inner.width) / 2,
17+
HorizontalAlignment::Right => outer.width - inner.width,
18+
};
19+
let offset_y = match PREVIEW.alignment.vertical {
20+
VerticalAlignment::Top => 0,
21+
VerticalAlignment::Center => (outer.height - inner.height) / 2,
22+
VerticalAlignment::Bottom => outer.height - inner.height,
23+
};
24+
Self { x: offset_x, y: offset_y }
25+
}
26+
}

0 commit comments

Comments
 (0)