You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
2.9 KiB
119 lines
2.9 KiB
--- @since 26.1.22 |
|
|
|
local get = ya.sync(function(st, url) return st.last == url and st.level end) |
|
|
|
local save = ya.sync(function(st, url, new) |
|
local h = cx.active.current.hovered |
|
if h and h.url == url then |
|
st.last, st.level = url, new |
|
return true |
|
end |
|
end) |
|
|
|
local lock = ya.sync(function(st, url, old, new) |
|
if st.last == url and st.level == old then |
|
st.level = new |
|
return true |
|
end |
|
end) |
|
|
|
local move = ya.sync(function(st) |
|
local h = cx.active.current.hovered |
|
if not h then |
|
return |
|
end |
|
|
|
if st.last ~= h.url then |
|
st.last, st.level = Url(h.url), 0 |
|
end |
|
|
|
return { url = h.url, level = st.level } |
|
end) |
|
|
|
local function end_(job, err) |
|
if not job.old_level then |
|
ya.preview_widget(job, err and ui.Text(err):area(job.area):wrap(ui.Wrap.YES)) |
|
elseif err then |
|
ya.notify { title = "Zoom", content = tostring(err), timeout = 5, level = "error" } |
|
end |
|
end |
|
|
|
local function canvas(area) |
|
local cw, ch = rt.term.cell_size() |
|
if not cw then |
|
return rt.preview.max_width, rt.preview.max_height |
|
end |
|
|
|
return math.min(rt.preview.max_width, math.floor(area.w * cw)), |
|
math.min(rt.preview.max_height, math.floor(area.h * ch)) |
|
end |
|
|
|
local function peek(_, job) |
|
local url = job.file.url |
|
local info, err = ya.image_info(url) |
|
if not info then |
|
return end_(job, Err("Failed to get image info: %s", err)) |
|
end |
|
|
|
local level = ya.clamp(-10, job.new_level or get(Url(url)) or tonumber(job.args[1]) or 0, 10) |
|
local sync = function() |
|
if job.old_level then |
|
return lock(url, job.old_level, level) |
|
else |
|
return save(url, level) |
|
end |
|
end |
|
|
|
local max_w, max_h = canvas(job.area) |
|
local min_w, min_h = math.min(max_w, info.w), math.min(max_h, info.h) |
|
local new_w = min_w + math.floor(min_w * level * 0.1) |
|
local new_h = min_h + math.floor(min_h * level * 0.1) |
|
if new_w > max_w or new_h > max_h then |
|
if job.old_level then |
|
return sync() -- Image larger than available preview area after zooming |
|
else |
|
new_w, new_h = max_w, max_h -- Run as a previewer, render the image anyway |
|
end |
|
end |
|
|
|
local tmp = os.tmpname() |
|
-- stylua: ignore |
|
local output, err = Command("magick"):arg { |
|
tostring(job.file.path), |
|
"-auto-orient", "-strip", |
|
"-sample", string.format("%dx%d", new_w, new_h), |
|
"-quality", rt.preview.image_quality, |
|
string.format("JPG:%s", tmp), |
|
}:output() |
|
|
|
if not output then |
|
end_(job, Err("Failed to start `magick`, error: %s", err)) |
|
elseif not output.status.success then |
|
end_(job, Err("`magick` exited with error code %s: %s", output.status.code, output.stderr)) |
|
elseif sync() then |
|
ya.image_show(Url(tmp), job.area) |
|
end |
|
end_(job) |
|
end |
|
|
|
local function entry(self, job) |
|
local st = move() |
|
if not st then |
|
return |
|
end |
|
|
|
local motion = tonumber(job.args[1]) or 0 |
|
local new = ya.clamp(-10, st.level + motion, 10) |
|
if new ~= st.level then |
|
peek(self, { |
|
area = ui.area("preview"), |
|
args = {}, |
|
file = File { url = st.url, cha = Cha { mode = tonumber("100644", 8) } }, |
|
skip = 0, |
|
new_level = new, |
|
old_level = st.level, |
|
}) |
|
end |
|
end |
|
|
|
return { peek = peek, entry = entry }
|
|
|