2019-07-12 22:17:34 +02:00
|
|
|
local api = {
|
|
|
|
screen = screen,
|
|
|
|
}
|
|
|
|
|
2019-07-07 22:43:54 +02:00
|
|
|
local function min(a, b)
|
|
|
|
if a < b then return a else return b end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function max(a, b)
|
|
|
|
if a < b then return b else return a end
|
|
|
|
end
|
|
|
|
|
2019-07-12 22:17:34 +02:00
|
|
|
local function get_screen(s)
|
|
|
|
return s and api.screen[s]
|
|
|
|
end
|
|
|
|
|
2019-07-07 22:19:18 +02:00
|
|
|
--- find the best region for the area-like object
|
|
|
|
-- @param c area-like object - table with properties x, y, width, and height
|
|
|
|
-- @param regions array of area-like objects
|
|
|
|
-- @return the index of the best region
|
|
|
|
local function find_region(c, regions)
|
|
|
|
local choice = 1
|
|
|
|
local choice_value = nil
|
|
|
|
local c_area = c.width * c.height
|
|
|
|
for i, a in ipairs(regions) do
|
|
|
|
local x_cap = max(0, min(c.x + c.width, a.x + a.width) - max(c.x, a.x))
|
|
|
|
local y_cap = max(0, min(c.y + c.height, a.y + a.height) - max(c.y, a.y))
|
|
|
|
local cap = x_cap * y_cap
|
|
|
|
-- -- a cap b / a cup b
|
|
|
|
-- local cup = c_area + a.width * a.height - cap
|
|
|
|
-- if cup > 0 then
|
|
|
|
-- local itx_ratio = cap / cup
|
|
|
|
-- if choice_value == nil or choice_value < itx_ratio then
|
|
|
|
-- choice_value = itx_ratio
|
|
|
|
-- choice = i
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- a cap b
|
|
|
|
if choice_value == nil or choice_value < cap then
|
|
|
|
choice = i
|
|
|
|
choice_value = cap
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return choice
|
|
|
|
end
|
|
|
|
|
2019-07-12 16:05:58 +02:00
|
|
|
local function create(name, editor)
|
2019-07-13 00:04:39 +02:00
|
|
|
local instances = {}
|
|
|
|
|
2019-07-14 00:39:38 +02:00
|
|
|
local get_instance_name
|
|
|
|
if type(name) == "function" then
|
|
|
|
get_instance_name = name
|
|
|
|
else
|
2019-07-14 19:33:39 +02:00
|
|
|
get_instance_name = function () return name, true end
|
2019-07-12 22:21:35 +02:00
|
|
|
end
|
|
|
|
|
2019-07-14 00:39:38 +02:00
|
|
|
local function get_instance(tag)
|
2019-07-14 19:33:39 +02:00
|
|
|
local name, persistent = get_instance_name(tag)
|
2019-07-14 00:39:38 +02:00
|
|
|
if instances[name] == nil then
|
|
|
|
instances[name] = {
|
2019-07-14 19:33:39 +02:00
|
|
|
cmd = persistent and editor.get_last_cmd(name) or nil,
|
2019-07-13 00:04:39 +02:00
|
|
|
regions_cache = {},
|
|
|
|
}
|
|
|
|
end
|
2019-07-14 00:39:38 +02:00
|
|
|
return instances[name]
|
2019-07-13 00:04:39 +02:00
|
|
|
end
|
|
|
|
|
2019-07-14 00:39:38 +02:00
|
|
|
local function get_regions(workarea, tag)
|
|
|
|
local instance = get_instance(tag)
|
2019-07-13 00:04:39 +02:00
|
|
|
if instance.cmd == nil then return {} end
|
|
|
|
|
2019-07-11 17:25:20 +02:00
|
|
|
local key = tostring(workarea.width) .. "x" .. tostring(workarea.height) .. "+" .. tostring(workarea.x) .. "+" .. tostring(workarea.y)
|
2019-07-13 00:04:39 +02:00
|
|
|
if instance.regions_cache[key] == nil then
|
|
|
|
instance.regions_cache[key] = editor.run_cmd(workarea, instance.cmd)
|
2019-07-04 23:32:05 +02:00
|
|
|
end
|
2019-07-13 00:04:39 +02:00
|
|
|
return instance.regions_cache[key]
|
2019-07-04 23:32:05 +02:00
|
|
|
end
|
|
|
|
|
2019-07-14 00:39:38 +02:00
|
|
|
local function set_cmd(cmd, tag)
|
|
|
|
local instance = get_instance(tag)
|
2019-07-13 00:04:39 +02:00
|
|
|
if instance.cmd ~= cmd then
|
|
|
|
instance.cmd = cmd
|
|
|
|
instance.regions_cache = {}
|
2019-07-12 22:17:34 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-07-12 16:05:58 +02:00
|
|
|
local function arrange(p)
|
2019-07-21 18:03:55 +02:00
|
|
|
local useless_gap = p.useless_gap
|
|
|
|
local wa = get_screen(p.screen).workarea -- get the real workarea without the gap (instead of p.workarea)
|
2019-07-11 17:25:20 +02:00
|
|
|
local cls = p.clients
|
2019-07-14 00:39:38 +02:00
|
|
|
local regions = get_regions(wa, get_screen(p.screen).selected_tag)
|
2019-07-11 17:25:20 +02:00
|
|
|
|
|
|
|
if #regions == 0 then return end
|
|
|
|
|
|
|
|
for i, c in ipairs(cls) do
|
|
|
|
if c.floating then
|
|
|
|
print("Ignore client " .. tostring(c))
|
|
|
|
else
|
|
|
|
if c.machi_region == nil then
|
|
|
|
c.machi_region = find_region(c, regions)
|
|
|
|
elseif c.machi_region > #regions then
|
|
|
|
c.machi_region = #regions
|
|
|
|
elseif c.machi_region <= 1 then
|
|
|
|
c.machi_region = 1
|
|
|
|
end
|
|
|
|
local region = c.machi_region
|
2019-07-04 23:32:05 +02:00
|
|
|
|
2019-07-21 18:03:55 +02:00
|
|
|
-- Editor already handled useless_gap in the stored regions.
|
|
|
|
-- We try to negate the gap of outer layer.
|
2019-07-11 17:25:20 +02:00
|
|
|
p.geometries[c] = {
|
2019-07-21 18:03:55 +02:00
|
|
|
x = regions[region].x - useless_gap,
|
|
|
|
y = regions[region].y - useless_gap,
|
|
|
|
width = regions[region].width + useless_gap * 2,
|
|
|
|
height = regions[region].height + useless_gap * 2,
|
2019-07-11 17:25:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
print("Put client " .. tostring(c) .. " to region " .. region)
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
2019-07-04 23:32:05 +02:00
|
|
|
end
|
|
|
|
|
2019-07-05 23:04:18 +02:00
|
|
|
-- move the closest region regardingly to the center distance
|
|
|
|
local function resize_handler(c, context, h)
|
|
|
|
if context ~= "mouse.move" then return end
|
2019-07-11 17:25:20 +02:00
|
|
|
|
|
|
|
local workarea = c.screen.workarea
|
2019-07-14 00:39:38 +02:00
|
|
|
local regions = get_regions(workarea, c.screen.selected_tag)
|
2019-07-11 17:25:20 +02:00
|
|
|
|
2019-07-11 17:36:39 +02:00
|
|
|
if #regions == 0 then return end
|
2019-07-05 23:04:18 +02:00
|
|
|
|
|
|
|
local center_x = h.x + h.width / 2
|
|
|
|
local center_y = h.y + h.height / 2
|
|
|
|
|
|
|
|
local choice = 1
|
|
|
|
local choice_value = nil
|
2019-07-11 17:25:20 +02:00
|
|
|
|
|
|
|
for i, r in ipairs(regions) do
|
2019-07-05 23:04:18 +02:00
|
|
|
local r_x = r.x + r.width / 2
|
|
|
|
local r_y = r.y + r.height / 2
|
|
|
|
local dis = (r_x - center_x) * (r_x - center_x) + (r_y - center_y) * (r_y - center_y)
|
|
|
|
if choice_value == nil or choice_value > dis then
|
|
|
|
choice = i
|
|
|
|
choice_value = dis
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if c.machi_region ~= choice then
|
|
|
|
c.machi_region = choice
|
2019-07-11 17:25:20 +02:00
|
|
|
c.x = regions[choice].x
|
|
|
|
c.y = regions[choice].y
|
2019-07-22 05:57:44 +02:00
|
|
|
c.width = max(1, regions[choice].width - 2 * c.border_width)
|
|
|
|
c.height = max(1, regions[choice].height - 2 * c.border_width)
|
2019-07-05 23:04:18 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-07-04 23:32:05 +02:00
|
|
|
return {
|
2019-07-12 16:05:58 +02:00
|
|
|
name = "machi",
|
2019-07-11 17:25:20 +02:00
|
|
|
arrange = arrange,
|
2019-07-06 00:42:56 +02:00
|
|
|
resize_handler = resize_handler,
|
2019-07-12 22:21:35 +02:00
|
|
|
machi_get_instance_name = get_instance_name,
|
2019-07-12 16:05:58 +02:00
|
|
|
machi_set_cmd = set_cmd,
|
|
|
|
machi_get_regions = get_regions,
|
2019-07-04 23:32:05 +02:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2019-07-11 17:25:20 +02:00
|
|
|
return {
|
2019-07-06 03:57:27 +02:00
|
|
|
create = create,
|
2019-07-07 22:19:18 +02:00
|
|
|
find_region = find_region,
|
2019-07-04 23:32:05 +02:00
|
|
|
}
|