1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-03 09:20:04 +08:00
SpaceVim/bundle/nui.nvim/lua/nui/layout/float.lua
2023-05-30 21:09:18 +08:00

226 lines
5.7 KiB
Lua
Vendored

local utils = require("nui.utils")
local layout_utils = require("nui.layout.utils")
local u = {
is_type = utils.is_type,
calculate_window_size = layout_utils.calculate_window_size,
}
local mod = {}
local function get_child_position(box, child, current_position, canvas_position)
local position = box.dir == "row" and {
row = canvas_position.row,
col = current_position.col,
} or {
col = canvas_position.col,
row = current_position.row,
}
if child.component then
local border = child.component.border
if border and border._.type == "complex" then
position.col = position.col + math.floor(border._.size_delta.width / 2 + 0.5)
position.row = position.row + math.floor(border._.size_delta.height / 2 + 0.5)
end
end
return position
end
---@param parent table Layout.Box
---@param child table Layout.Box
---@param container_size table
---@param growable_dimension_per_factor? number
local function get_child_size(parent, child, container_size, growable_dimension_per_factor)
local child_size = {
width = child.size.width,
height = child.size.height,
}
if child.grow and growable_dimension_per_factor then
if parent.dir == "col" then
child_size.height = math.floor(growable_dimension_per_factor * child.grow)
else
child_size.width = math.floor(growable_dimension_per_factor * child.grow)
end
end
local outer_size = u.calculate_window_size(child_size, container_size)
local inner_size = {
width = outer_size.width,
height = outer_size.height,
}
if child.component then
if child.component.border then
inner_size.width = inner_size.width - child.component.border._.size_delta.width
inner_size.height = inner_size.height - child.component.border._.size_delta.height
end
end
return outer_size, inner_size
end
function mod.process(box, meta)
if box.mount or box.component or not box.box then
return error("invalid paramter: box")
end
local container_size = meta.container_size
if not u.is_type("number", container_size.width) or not u.is_type("number", container_size.height) then
return error("invalid value: box.size")
end
local current_position = {
col = 0,
row = 0,
}
local growable_child_factor = 0
for _, child in ipairs(box.box) do
if meta.process_growable_child or not child.grow then
local position = get_child_position(box, child, current_position, meta.position)
local outer_size, inner_size = get_child_size(box, child, container_size, meta.growable_dimension_per_factor)
if child.component then
child.component:set_layout({
size = inner_size,
relative = {
type = "win",
winid = meta.winid,
},
position = position,
})
else
mod.process(child, {
winid = meta.winid,
container_size = outer_size,
position = position,
})
end
current_position.col = current_position.col + outer_size.width
current_position.row = current_position.row + outer_size.height
end
if child.grow then
growable_child_factor = growable_child_factor + child.grow
end
end
if meta.process_growable_child or growable_child_factor == 0 then
return
end
local growable_width = container_size.width - current_position.col
local growable_height = container_size.height - current_position.row
local growable_dimension = box.dir == "col" and growable_height or growable_width
local growable_dimension_per_factor = growable_dimension / growable_child_factor
mod.process(box, {
winid = meta.winid,
container_size = meta.container_size,
position = meta.position,
process_growable_child = true,
growable_dimension_per_factor = growable_dimension_per_factor,
})
end
function mod.mount_box(box)
for _, child in ipairs(box.box) do
if child.component then
child.component:mount()
else
mod.mount_box(child)
end
end
end
---@param box table Layout.Box
function mod.show_box(box)
for _, child in ipairs(box.box) do
if child.component then
child.component:show()
else
mod.show_box(child)
end
end
end
function mod.unmount_box(box)
for _, child in ipairs(box.box) do
if child.component then
child.component:unmount()
else
mod.unmount_box(child)
end
end
end
---@param box table Layout.Box
function mod.hide_box(box)
for _, child in ipairs(box.box) do
if child.component then
child.component:hide()
else
mod.hide_box(child)
end
end
end
---@param box table Layout.Box
---@return table<string, table>
local function collect_box_components(box, components)
if not components then
components = {}
end
for _, child in ipairs(box.box) do
if child.component then
components[child.component._.id] = child.component
else
collect_box_components(child, components)
end
end
return components
end
---@param curr_box table Layout.Box
---@param prev_box table Layout.Box
function mod.process_box_change(curr_box, prev_box)
if curr_box == prev_box then
return
end
local curr_components = collect_box_components(curr_box)
local prev_components = collect_box_components(prev_box)
for id, component in pairs(curr_components) do
if not prev_components[id] then
if not component.winid then
if component._.mounted then
component:show()
else
component:mount()
end
end
end
end
for id, component in pairs(prev_components) do
if not curr_components[id] then
if component._.mounted then
if component.winid then
component:hide()
end
end
end
end
end
return mod