This commit is contained in:
sxyazi 2026-04-22 17:52:00 +08:00
parent 8b62826139
commit 835a213379
No known key found for this signature in database
19 changed files with 123 additions and 100 deletions

View file

@ -4,8 +4,7 @@ use mlua::{ObjectLike, Table};
use tracing::error;
use yazi_actor::lives::Lives;
use yazi_binding::runtime_scope;
use yazi_config::YAZI;
use yazi_macro::{render, succ};
use yazi_macro::succ;
use yazi_parser::app::MouseForm;
use yazi_plugin::LUA;
use yazi_shared::data::Data;
@ -30,10 +29,6 @@ impl Actor for Mouse {
LUA.globals().raw_get::<Table>("Root")?.call_method::<Table>("new", area)
})?;
if matches!(event.kind, MouseEventKind::Down(_) if YAZI.mgr.mouse_events.get().draggable()) {
root.raw_set("_drag_start", event)?;
}
match event.kind {
MouseEventKind::Down(_) => root.call_method("click", (event, false))?,
MouseEventKind::Up(_) => root.call_method("click", (event, true))?,
@ -45,10 +40,7 @@ impl Actor for Mouse {
MouseEventKind::ScrollLeft => root.call_method("touch", (event, -1))?,
MouseEventKind::Moved => root.call_method("move", event)?,
MouseEventKind::Drag(_) => {
root.call_method::<()>("drag", event)?;
render!();
}
MouseEventKind::Drag(_) => root.call_method("drag", event)?,
}
Ok(())

View file

@ -1,6 +1,6 @@
use std::ops::{Add, AddAssign, Deref};
use mlua::{FromLua, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use mlua::{FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataFields, Value};
#[derive(Clone, Copy, Default, FromLua)]
pub struct Pad(ratatui::widgets::Padding);
@ -52,7 +52,7 @@ impl Pad {
}
impl UserData for Pad {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("left", |_, me| Ok(me.left));
fields.add_field_method_get("right", |_, me| Ok(me.right));
fields.add_field_method_get("top", |_, me| Ok(me.top));

View file

@ -1,6 +1,6 @@
use std::{ops::Deref, str::FromStr};
use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataFields, UserDataMethods, Value};
use yazi_shim::strum::IntoStr;
use super::Pad;
@ -81,7 +81,7 @@ impl Pos {
}
impl UserData for Pos {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
// TODO: cache
fields.add_field_method_get("1", |_, me| Ok(me.origin.into_str()));
fields.add_field_method_get("x", |_, me| Ok(me.offset.x));

View file

@ -1,6 +1,6 @@
use std::ops::Deref;
use mlua::{FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
use mlua::{FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataFields, UserDataMethods, Value};
use super::Pad;
@ -51,7 +51,7 @@ impl Rect {
}
impl UserData for Rect {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("x", |_, me| Ok(me.x));
fields.add_field_method_get("y", |_, me| Ok(me.y));
fields.add_field_method_get("w", |_, me| Ok(me.width));

View file

@ -1,6 +1,6 @@
use std::ops::Deref;
use mlua::{ExternalError, ExternalResult, FromLua, Lua, UserData, Value};
use mlua::{ExternalError, ExternalResult, FromLua, Lua, UserData, UserDataFields, Value};
#[derive(Clone, Copy, Default)]
pub struct Id(pub yazi_shared::Id);
@ -22,7 +22,7 @@ impl FromLua for Id {
}
impl UserData for Id {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("value", |_, me| Ok(me.0.get()));
}
}

View file

@ -1,6 +1,6 @@
use std::ops::Deref;
use mlua::{MetaMethod, UserData, UserDataMethods};
use mlua::{MetaMethod, UserData, UserDataFields, UserDataMethods};
pub struct ImageInfo(yazi_adapter::ImageInfo);
@ -15,7 +15,7 @@ impl From<yazi_adapter::ImageInfo> for ImageInfo {
}
impl UserData for ImageInfo {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("w", |_, me| Ok(me.width));
fields.add_field_method_get("h", |_, me| Ok(me.height));
fields.add_field_method_get("ori", |_, me| Ok(me.orientation.map(|o| o.to_exif())));

View file

@ -1,6 +1,6 @@
use std::mem;
use mlua::{UserData, Value};
use mlua::{UserData, UserDataFields, Value};
use super::Status;
use crate::{cached_field, cached_field_mut};
@ -20,7 +20,7 @@ impl Output {
}
impl UserData for Output {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
cached_field!(fields, status, |_, me| Ok(Status::new(me.inner.status)));
cached_field_mut!(fields, stdout, |lua, me| {
lua.create_external_string(mem::take(&mut me.inner.stdout))

View file

@ -1,4 +1,4 @@
use mlua::UserData;
use mlua::{UserData, UserDataFields};
pub struct Status {
inner: std::process::ExitStatus,
@ -9,7 +9,7 @@ impl Status {
}
impl UserData for Status {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("success", |_, me| Ok(me.inner.success()));
fields.add_field_method_get("code", |_, me| Ok(me.inner.code()));
}

View file

@ -15,10 +15,6 @@ bitflags! {
}
}
impl MouseEvents {
pub const fn draggable(self) -> bool { self.contains(Self::DRAG) }
}
impl TryFrom<Vec<String>> for MouseEvents {
type Error = anyhow::Error;

View file

@ -49,6 +49,10 @@ end
-- Mouse events
function Current:click(event, up)
if up or event.is_middle then
return
end
local y = event.y - self._area.y + 1
if self._folder.window[y] then
Entity:new(self._folder.window[y]):click(event, up)

View file

@ -34,6 +34,10 @@ end
-- Mouse events
function Parent:click(event, up)
if up or event.is_middle then
return
end
local y = event.y - self._area.y + 1
local window = self._folder and self._folder.window or {}
if window[y] then

View file

@ -16,6 +16,10 @@ function Preview:redraw() return {} end
-- Mouse events
function Preview:click(event, up)
if up or event.is_middle then
return
end
local y = event.y - self._area.y + 1
local window = self._folder and self._folder.window or {}
if window[y] then

View file

@ -1,37 +1,45 @@
Rail = {
_id = "rail",
}
Rail = {}
function Rail:new(chunks, tab)
local me = setmetatable({ _chunks = chunks, _tab = tab }, { __index = self })
me:build()
return me
function Rail:new(id, area, chunks)
return setmetatable({
_id = id,
_area = area,
_chunks = chunks,
}, { __index = self })
end
function Rail:build()
self._base = {
ui.Bar(ui.Edge.RIGHT):area(self._chunks[1]):symbol(th.mgr.border_symbol):style(th.mgr.border_style),
ui.Bar(ui.Edge.LEFT):area(self._chunks[3]):symbol(th.mgr.border_symbol):style(th.mgr.border_style),
}
self._children = {
Marker:new(self._chunks[1], self._tab.parent),
Marker:new(self._chunks[2], self._tab.current),
}
end
function Rail:reflow() return {} end
function Rail:reflow() return { self } end
function Rail:redraw()
local elements = self._base or {}
for _, child in ipairs(self._children) do
elements = ya.list_merge(elements, ui.redraw(child))
end
return elements
return {
ui.Bar(ui.Edge.LEFT):area(self._area):symbol(th.mgr.border_symbol):style(th.mgr.border_style),
}
end
-- Mouse events
function Rail:click(event, up) end
function Rail:drag(event)
local c, parent, current, preview = self._chunks, 0, 0, 0
if self._id == "rail-left" then
local x = math.min(event.x, c[2].right - 2)
parent = math.max(1, x - c[1].x)
current = math.max(1, c[1].w + c[2].w - parent)
preview = math.max(1, c[3].w)
else
local x = math.max(event.x, c[2].x + 2)
preview = math.max(1, c[3].right - x)
current = math.max(1, c[2].w + c[3].w - preview)
parent = math.max(1, c[1].w)
end
local r = rt.mgr.ratio
if r.parent ~= parent or r.current ~= current or r.preview ~= preview then
rt.mgr.ratio = { parent, current, preview }
ui.render()
end
end
function Rail:scroll(event, step) end
function Rail:touch(event, step) end

View file

@ -0,0 +1,48 @@
Rails = {
_id = "rails",
}
function Rails:new(chunks, tab)
local me = setmetatable({ _chunks = chunks, _tab = tab }, { __index = self })
me:build()
return me
end
function Rails:build()
local c, children = self._chunks, {}
if c[1].w > 0 then
children[#children + 1] =
Rail:new("rail-left", ui.Rect { x = c[2].x, y = c[2].y, w = math.min(1, c[2].w), h = c[2].h }, c)
end
if c[3].w > 0 then
children[#children + 1] = Rail:new(
"rail-right",
ui.Rect { x = math.max(0, c[2].right - 1), y = c[2].y, w = math.min(1, c[2].w), h = c[2].h },
c
)
end
self._children = children
end
function Rails:reflow()
local components = {}
for _, child in ipairs(self._children) do
components = ya.list_merge(components, child:reflow())
end
return components
end
function Rails:redraw()
local elements = {}
for _, child in ipairs(self._children) do
elements = ya.list_merge(elements, ui.redraw(child))
end
return elements
end
-- Mouse events
function Rails:click(event, up) end
function Rails:scroll(event, step) end
function Rails:touch(event, step) end

View file

@ -1,7 +1,6 @@
Root = {
_id = "root",
_drag_start = ui.Rect {},
_drag_which = nil, -- "left" or "right" when dragging a panel separator
_dragging = nil,
}
function Root:new(area)
@ -55,26 +54,9 @@ function Root:click(event, up)
return
end
if up then
Root._drag_which = nil
elseif event.is_left then
-- Check if clicking on a panel separator (Tab is self._children[3])
local tab = self._children[3]
if tab and tab._chunks then
local c = tab._chunks
local lx = c[2].x - 1 -- left separator center x
local rx = c[3].x -- right separator center x
if c[1].w > 0 and event.x >= lx - 1 and event.x <= lx + 1 then
Root._drag_which = "left"
return
elseif c[3].w > 0 and event.x >= rx - 1 and event.x <= rx + 1 then
Root._drag_which = "right"
return
end
end
end
local c = Root._dragging or ya.child_at(ui.Rect { x = event.x, y = event.y }, self:reflow())
Root._dragging = not up and c or nil
local c = ya.child_at(ui.Rect { x = event.x, y = event.y }, self:reflow())
return c and c:click(event, up)
end
@ -97,28 +79,10 @@ end
function Root:move(event) end
function Root:drag(event)
if not Root._drag_which then
if tostring(cx.layer) ~= "mgr" then
return
end
local tab = self._children[3]
if not tab or not tab._chunks then
return
end
local c = tab._chunks
local ratio = rt.mgr.ratio
if Root._drag_which == "left" then
-- Dragging the left separator: adjust parent and current widths
local new_parent = math.max(1, event.x - c[1].x + 1)
local new_current = math.max(1, c[1].w + c[2].w - new_parent)
rt.mgr.ratio = { new_parent, new_current, c[3].w > 0 and c[3].w or 1 }
elseif Root._drag_which == "right" then
-- Dragging the right separator: adjust current and preview widths
local right_edge = c[3].x + c[3].w - 1
local new_preview = math.max(1, right_edge - event.x)
local new_current = math.max(1, c[2].w + c[3].w - new_preview)
rt.mgr.ratio = { c[1].w > 0 and c[1].w or 1, new_current, new_preview }
end
local c = Root._dragging
return c and c.drag and c:drag(event)
end

View file

@ -23,11 +23,12 @@ end
function Tab:build()
local c = self._chunks
local p = c[2].w > 0 and 0 or 1
self._children = {
Parent:new(c[1]:pad(ui.Pad.x(1)), self._tab),
Current:new(c[2]:pad(ui.Pad(0, c[3].w > 0 and 0 or 1, 0, c[1].w > 0 and 0 or 1)), self._tab),
Preview:new(c[3]:pad(ui.Pad.x(1)), self._tab),
Rail:new(c, self._tab),
Parent:new(c[1]:pad(ui.Pad(0, p, 0, 1)), self._tab),
Current:new(c[2]:pad(ui.Pad.x(1)), self._tab),
Preview:new(c[3]:pad(ui.Pad(0, 1, 0, p)), self._tab),
Rails:new(c, self._tab),
}
end

View file

@ -52,6 +52,7 @@ fn stage_1(lua: &Lua) -> Result<()> {
lua.load(preset!("components/preview")).set_name("preview.lua").exec()?;
lua.load(preset!("components/progress")).set_name("progress.lua").exec()?;
lua.load(preset!("components/rail")).set_name("rail.lua").exec()?;
lua.load(preset!("components/rails")).set_name("rails.lua").exec()?;
lua.load(preset!("components/root")).set_name("root.lua").exec()?;
lua.load(preset!("components/status")).set_name("status.lua").exec()?;
lua.load(preset!("components/tab")).set_name("tab.lua").exec()?;

View file

@ -65,6 +65,7 @@ impl Default for Loader {
("preview".to_owned(), [][..].into()),
("progress".to_owned(), [][..].into()),
("rail".to_owned(), [][..].into()),
("rails".to_owned(), [][..].into()),
("root".to_owned(), [][..].into()),
("status".to_owned(), [][..].into()),
("tab".to_owned(), [][..].into()),

View file

@ -30,7 +30,7 @@ impl Widget for Clear {
}
const fn is_overlapping(a: Rect, b: Rect) -> bool {
a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y
a.x < b.right() && a.right() > b.x && a.y < b.y + b.height && a.y + a.height > b.y
}
fn overlap(a: Rect, b: Rect) -> Option<Rect> {
@ -40,7 +40,7 @@ fn overlap(a: Rect, b: Rect) -> Option<Rect> {
let x = a.x.max(b.x);
let y = a.y.max(b.y);
let width = (a.x + a.width).min(b.x + b.width) - x;
let width = a.right().min(b.right()) - x;
let height = (a.y + a.height).min(b.y + b.height) - y;
Some(Rect { x, y, width, height })
}