Added/Implemented machi-editor
This commit is contained in:
841
lib/layout-machi/switcher.lua
Normal file
841
lib/layout-machi/switcher.lua
Normal file
@@ -0,0 +1,841 @@
|
||||
local machi = {
|
||||
layout = require((...):match("(.-)[^%.]+$") .. "layout"),
|
||||
engine = require((...):match("(.-)[^%.]+$") .. "engine"),
|
||||
}
|
||||
|
||||
local capi = {
|
||||
client = client,
|
||||
screen = screen,
|
||||
}
|
||||
|
||||
local beautiful = require("beautiful")
|
||||
local wibox = require("wibox")
|
||||
local awful = require("awful")
|
||||
local gears = require("gears")
|
||||
local lgi = require("lgi")
|
||||
local dpi = require("beautiful.xresources").apply_dpi
|
||||
local gtimer = require("gears.timer")
|
||||
|
||||
local ERROR = 2
|
||||
local WARNING = 1
|
||||
local INFO = 0
|
||||
local DEBUG = -1
|
||||
|
||||
local module = {
|
||||
log_level = WARNING,
|
||||
}
|
||||
|
||||
local function log(level, msg)
|
||||
if level > module.log_level then
|
||||
print(msg)
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
local function with_alpha(col, alpha)
|
||||
local r, g, b
|
||||
_, r, g, b, _ = col:get_rgba()
|
||||
return lgi.cairo.SolidPattern.create_rgba(r, g, b, alpha)
|
||||
end
|
||||
|
||||
function module.start(c, exit_keys)
|
||||
local tablist_font_desc = beautiful.get_merged_font(
|
||||
beautiful.font, dpi(10))
|
||||
local font_color = with_alpha(gears.color(beautiful.fg_normal), 1)
|
||||
local font_color_hl = with_alpha(gears.color(beautiful.fg_focus), 1)
|
||||
local label_size = dpi(30)
|
||||
local border_color = with_alpha(
|
||||
gears.color(beautiful.machi_switcher_border_color or beautiful.border_focus),
|
||||
beautiful.machi_switcher_border_opacity or 0.25)
|
||||
local border_color_hl = with_alpha(
|
||||
gears.color(beautiful.machi_switcher_border_hl_color or beautiful.border_focus),
|
||||
beautiful.machi_switcher_border_hl_opacity or 0.75)
|
||||
local fill_color = with_alpha(
|
||||
gears.color(beautiful.machi_switcher_fill_color or beautiful.bg_normal),
|
||||
beautiful.machi_switcher_fill_opacity or 0.25)
|
||||
local box_bg = with_alpha(
|
||||
gears.color(beautiful.machi_switcher_box_bg or beautiful.bg_normal),
|
||||
beautiful.machi_switcher_box_opacity or 0.85)
|
||||
local fill_color_hl = with_alpha(
|
||||
gears.color(beautiful.machi_switcher_fill_color_hl or beautiful.bg_focus),
|
||||
beautiful.machi_switcher_fill_hl_opacity or 1)
|
||||
-- for comparing floats
|
||||
local threshold = 0.1
|
||||
local traverse_radius = dpi(5)
|
||||
|
||||
local screen = c and c.screen or awful.screen.focused()
|
||||
local tag = screen.selected_tag
|
||||
local layout = tag.layout
|
||||
local gap = tag.gap
|
||||
local start_x = screen.workarea.x
|
||||
local start_y = screen.workarea.y
|
||||
|
||||
if layout.machi_get_instance_data == nil then return end
|
||||
|
||||
local cd, td, areas, _new_placement_cb = layout.machi_get_instance_data(screen, screen.selected_tag)
|
||||
if areas == nil or #areas == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local infobox, infotabbox
|
||||
local tablist = nil
|
||||
|
||||
local traverse_x, traverse_y
|
||||
if c then
|
||||
traverse_x = c.x + traverse_radius
|
||||
traverse_y = c.y + traverse_radius
|
||||
else
|
||||
traverse_x = screen.workarea.x + screen.workarea.width / 2
|
||||
traverse_y = screen.workarea.y + screen.workarea.height / 2
|
||||
end
|
||||
|
||||
local selected_area_ = nil
|
||||
local function set_selected_area(area)
|
||||
selected_area_ = area
|
||||
if area then
|
||||
traverse_x = max(areas[area].x + traverse_radius, min(areas[area].x + areas[area].width - traverse_radius, traverse_x))
|
||||
traverse_y = max(areas[area].y + traverse_radius, min(areas[area].y + areas[area].height - traverse_radius, traverse_y))
|
||||
end
|
||||
end
|
||||
|
||||
local function selected_area()
|
||||
if selected_area_ == nil then
|
||||
local min_dis = nil
|
||||
for i, a in ipairs(areas) do
|
||||
if a.habitable then
|
||||
local dis =
|
||||
math.abs(a.x + traverse_radius - traverse_x) + math.abs(a.x + a.width - traverse_radius - traverse_x) - a.width +
|
||||
math.abs(a.y + traverse_radius - traverse_y) + math.abs(a.y + a.height - traverse_radius - traverse_y) - a.height +
|
||||
traverse_radius * 4
|
||||
if min_dis == nil or min_dis > dis then
|
||||
min_dis = dis
|
||||
selected_area_ = i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
set_selected_area(selected_area_)
|
||||
end
|
||||
return selected_area_
|
||||
end
|
||||
|
||||
local parent_stack = {}
|
||||
|
||||
local function get_tablist(area)
|
||||
local list = {}
|
||||
for _, tc in ipairs(screen.tiled_clients) do
|
||||
if not (tc.floating or tc.immobilized)
|
||||
then
|
||||
if areas[area].x <= tc.x + tc.width + tc.border_width * 2 and tc.x <= areas[area].x + areas[area].width and
|
||||
areas[area].y <= tc.y + tc.height + tc.border_width * 2 and tc.y <= areas[area].y + areas[area].height
|
||||
then
|
||||
list[#list + 1] = tc
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return list
|
||||
end
|
||||
|
||||
local function maintain_tablist()
|
||||
tablist = get_tablist(selected_area())
|
||||
if #tablist ~= 0 then
|
||||
c = tablist[1]
|
||||
end
|
||||
end
|
||||
|
||||
local function draw_tab_info(context, cr, width, height)
|
||||
maintain_tablist()
|
||||
|
||||
local wi = { x = 0, y = 0, w = 1, h = 1 }
|
||||
local ext
|
||||
local active_area = selected_area()
|
||||
if #tablist > 0 then
|
||||
local a = areas[active_area]
|
||||
local pl = lgi.Pango.Layout.create(cr)
|
||||
pl:set_font_description(tablist_font_desc)
|
||||
|
||||
local vpadding = dpi(10)
|
||||
local hpadding = dpi(15)
|
||||
local vborder = dpi(5)
|
||||
local hborder = dpi(5)
|
||||
local list_height = 2 * vborder
|
||||
local list_width = 2 * hpadding + 2 * hborder
|
||||
local exts = {}
|
||||
|
||||
local tl = {}
|
||||
local hw = math.floor((#tablist-1)/2)
|
||||
for i = hw+1,2,-1 do
|
||||
table.insert(tl, tablist[i])
|
||||
end
|
||||
table.insert(tl, tablist[1])
|
||||
local active = #tl
|
||||
for i = #tablist,hw+2,-1 do
|
||||
table.insert(tl, tablist[i])
|
||||
end
|
||||
|
||||
for index, tc in ipairs(tl) do
|
||||
local label = tc.name or "<unnamed>"
|
||||
pl:set_text(label)
|
||||
local w, h
|
||||
w, h = pl:get_size()
|
||||
w = w / lgi.Pango.SCALE
|
||||
h = h / lgi.Pango.SCALE
|
||||
local ext = { width = w, height = h }
|
||||
exts[#exts + 1] = ext
|
||||
list_height = list_height + ext.height + vpadding
|
||||
list_width = max(list_width, w + 2 * hpadding + 2 * hborder)
|
||||
end
|
||||
|
||||
local y_offset = vborder
|
||||
wi.x = a.x + (a.width - list_width) / 2
|
||||
wi.y = a.y + (a.height - list_height) / 2
|
||||
wi.w = list_width
|
||||
wi.h = list_height
|
||||
|
||||
cr:rectangle(0, 0, list_width, list_height)
|
||||
cr:set_source(border_color_hl)
|
||||
cr:fill()
|
||||
|
||||
for index, tc in ipairs(tl) do
|
||||
local label = tc.name or "<unnamed>"
|
||||
local ext = exts[index]
|
||||
if index == active then
|
||||
cr:rectangle(hborder, y_offset, list_width - 2 * hborder, ext.height + vpadding)
|
||||
cr:set_source(fill_color_hl)
|
||||
cr:fill()
|
||||
pl:set_text(label)
|
||||
cr:move_to(hborder + hpadding, vpadding / 2 + y_offset)
|
||||
cr:set_source(font_color_hl)
|
||||
cr:show_layout(pl)
|
||||
else
|
||||
pl:set_text(label)
|
||||
cr:move_to(hborder + hpadding, vpadding / 2 + y_offset)
|
||||
cr:set_source(font_color)
|
||||
cr:show_layout(pl)
|
||||
end
|
||||
|
||||
y_offset = y_offset + ext.height + vpadding
|
||||
end
|
||||
end
|
||||
|
||||
if infotabbox.x ~= wi.x or infotabbox.y ~= wi.y or
|
||||
infotabbox.width ~= wi.w or infotabbox.height ~= wi.h
|
||||
then
|
||||
infotabbox.x = wi.x
|
||||
infotabbox.y = wi.y
|
||||
infotabbox.width = wi.w
|
||||
infotabbox.height = wi.h
|
||||
end
|
||||
end
|
||||
|
||||
local function draw_info(context, cr, width, height)
|
||||
maintain_tablist()
|
||||
|
||||
cr:set_source_rgba(0, 0, 0, 0)
|
||||
cr:rectangle(0, 0, width, height)
|
||||
cr:fill()
|
||||
|
||||
local padx = 5
|
||||
local pady = 5
|
||||
local msg
|
||||
local active_area = selected_area()
|
||||
for i, a in ipairs(areas) do
|
||||
if a.habitable or i == active_area then
|
||||
cr:rectangle(a.x - padx - start_x, a.y - pady - start_y, a.width + 2*padx, a.height + 2*pady)
|
||||
cr:clip()
|
||||
cr:set_source(fill_color)
|
||||
cr:rectangle(a.x - start_x, a.y - start_y, a.width, a.height)
|
||||
cr:fill()
|
||||
cr:set_source(i == active_area and border_color_hl or border_color)
|
||||
cr:rectangle(a.x - start_x, a.y - start_y, a.width, a.height)
|
||||
cr:set_line_width(10.0)
|
||||
cr:stroke()
|
||||
cr:reset_clip()
|
||||
end
|
||||
end
|
||||
|
||||
if infobox.width ~= screen.workarea.width or infobox.height ~= screen.workarea.height then
|
||||
gtimer.delayed_call(function ()
|
||||
infobox.width = screen.workarea.width
|
||||
infobox.height = screen.workarea.height
|
||||
infobox.visible = true
|
||||
end)
|
||||
end
|
||||
|
||||
-- show the traverse point
|
||||
-- cr:rectangle(traverse_x - start_x - traverse_radius, traverse_y - start_y - traverse_radius, traverse_radius * 2, traverse_radius * 2)
|
||||
-- cr:set_source_rgba(1, 1, 1, 1)
|
||||
-- cr:fill()
|
||||
end
|
||||
|
||||
local draw = function()
|
||||
if infobox ~= nil then
|
||||
infobox.bgimage = draw_info
|
||||
end
|
||||
if infotabbox ~= nil then
|
||||
infotabbox.bgimage = draw_tab_info
|
||||
end
|
||||
end
|
||||
|
||||
local largest_area = function(areas)
|
||||
local largest = nil
|
||||
local size = 0
|
||||
for i, a in ipairs(areas) do
|
||||
local s = a.width * a.height
|
||||
if a.habitable and (largest == nil or s > size) then
|
||||
largest = i
|
||||
size = s
|
||||
end
|
||||
end
|
||||
|
||||
return largest
|
||||
end
|
||||
|
||||
local snap_area = function(x, y, width, height)
|
||||
local bestD, d
|
||||
local best
|
||||
local dist = function(x0, y0, x1, y1)
|
||||
local a, b = x0-x1, y0-y1
|
||||
return math.sqrt(a*a+b*b)
|
||||
end
|
||||
for i, a in ipairs(areas) do
|
||||
d = dist(a.x, a.y, x, y) +
|
||||
dist(a.x+a.width, a.y+a.height, x+width, y+height)
|
||||
if bestD == nil or d < bestD then
|
||||
bestD = d
|
||||
best = i
|
||||
end
|
||||
end
|
||||
|
||||
return best
|
||||
end
|
||||
|
||||
|
||||
-- area is the index in areas, should be made consistent after el big refactor
|
||||
-- draft is reset
|
||||
local move_client
|
||||
move_client = function(c, area)
|
||||
if area == nil or areas[area] == nil or c == nil or not c.valid or c.floating then
|
||||
return
|
||||
end
|
||||
machi.layout.set_geometry(c, areas[area], areas[area], 0, c.border_width)
|
||||
if cd[c] == nil then
|
||||
return
|
||||
end
|
||||
cd[c].lu = nil
|
||||
cd[c].rd = nil
|
||||
cd[c].area = area
|
||||
end
|
||||
|
||||
local snap_client = function()
|
||||
if c == nil then
|
||||
return
|
||||
end
|
||||
a = snap_area(c.x, c.y, c.width, c.height)
|
||||
if a == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
move_client(c, a)
|
||||
return true
|
||||
end
|
||||
|
||||
local master_add = function()
|
||||
if c == nil or c.floating then
|
||||
return
|
||||
end
|
||||
|
||||
local dst = largest_area(areas)
|
||||
if dst == nil then
|
||||
return
|
||||
end
|
||||
move_client(c, dst)
|
||||
awful.layout.arrange(screen)
|
||||
end
|
||||
|
||||
local master_swap = function(all)
|
||||
if c == nil or c.floating then
|
||||
return
|
||||
end
|
||||
|
||||
local src = selected_area()
|
||||
local dst = largest_area(areas)
|
||||
if dst == nil or dst == src then
|
||||
return
|
||||
end
|
||||
local srclist = get_tablist(src)
|
||||
local dstlist = get_tablist(dst)
|
||||
|
||||
for i, c in ipairs(dstlist) do
|
||||
if all or i == 1 then
|
||||
move_client(c, src)
|
||||
end
|
||||
end
|
||||
for i, c in ipairs(srclist) do
|
||||
if all or i == 1 then
|
||||
move_client(c, dst)
|
||||
end
|
||||
end
|
||||
awful.layout.arrange(screen)
|
||||
end
|
||||
|
||||
local traverse_clients = function(dir)
|
||||
dir = string.lower(dir)
|
||||
local current_area = selected_area()
|
||||
local current = areas[current_area]
|
||||
if current == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
local candidates = {}
|
||||
for i, a in ipairs(areas) do
|
||||
local data = {i = i, a = a}
|
||||
if not a.habitable or i == current_area then
|
||||
elseif dir == "up" and
|
||||
a.y + a.height < current.y and
|
||||
#get_tablist(i) ~= 0 then
|
||||
table.insert(candidates, data)
|
||||
elseif dir == "down" and
|
||||
a.y > current.y + current.height and
|
||||
#get_tablist(i) ~= 0 then
|
||||
table.insert(candidates, data)
|
||||
elseif dir == "left" and
|
||||
a.x + a.width < current.x and
|
||||
#get_tablist(i) ~= 0 then
|
||||
table.insert(candidates, data)
|
||||
elseif dir == "right" and
|
||||
a.x > current.x + current.width and
|
||||
#get_tablist(i) ~= 0 then
|
||||
table.insert(candidates, data)
|
||||
end
|
||||
end
|
||||
|
||||
local best_area
|
||||
local score
|
||||
for i, d in ipairs(candidates) do
|
||||
local a = d.a
|
||||
local dist, overlap
|
||||
|
||||
if dir == "up" or dir == "down" then
|
||||
overlap = min(current.x+current.width, a.x+a.width) - max(current.x, a.x)
|
||||
elseif dir == "left" or dir == "right" then
|
||||
overlap = min(current.y+current.height, a.y+a.height) - max(current.y, a.y)
|
||||
end
|
||||
|
||||
if dir == "up" then
|
||||
dist = current.y - a.y - a.height
|
||||
elseif dir == "down" then
|
||||
dist = a.y - current. y - current.height
|
||||
elseif dir == "left" then
|
||||
dist = current.x - a.x - a.width
|
||||
elseif dir == "right" then
|
||||
dist = a.x - current.x - current.width
|
||||
end
|
||||
|
||||
-- TODO this is probably not optimal
|
||||
local s = overlap - dist
|
||||
if score == nil or s > score then
|
||||
best_area = d.i
|
||||
score = s
|
||||
end
|
||||
end
|
||||
|
||||
if best_area == nil then
|
||||
if #candidates == 0 then
|
||||
return false
|
||||
end
|
||||
best_area = candidates[1].i
|
||||
end
|
||||
|
||||
set_selected_area(best_area)
|
||||
local tablist = get_tablist(best_area)
|
||||
if #tablist == 0 or tablist[1] == c then
|
||||
return false
|
||||
end
|
||||
c = tablist[1]
|
||||
capi.client.focus = c
|
||||
return true
|
||||
end
|
||||
|
||||
local traverse_areas = function(dir, move, draft)
|
||||
dir = string.lower(dir)
|
||||
local current_area = selected_area()
|
||||
|
||||
if c and move then
|
||||
if current_area == nil or
|
||||
areas[current_area].x ~= c.x or
|
||||
areas[current_area].y ~= c.y
|
||||
then
|
||||
traverse_x = c.x + traverse_radius
|
||||
traverse_y = c.y + traverse_radius
|
||||
set_selected_area(nil)
|
||||
end
|
||||
elseif c and draft then
|
||||
local ex = c.x + c.width + c.border_width * 2
|
||||
local ey = c.y + c.height + c.border_width * 2
|
||||
if current_area == nil or
|
||||
areas[current_area].x + areas[current_area].width ~= ex or
|
||||
areas[current_area].y + areas[current_area].height ~= ey
|
||||
then
|
||||
traverse_x = ex - traverse_radius
|
||||
traverse_y = ey - traverse_radius
|
||||
set_selected_area(nil)
|
||||
end
|
||||
end
|
||||
|
||||
local choice = nil
|
||||
local choice_value
|
||||
|
||||
current_area = selected_area()
|
||||
|
||||
for i, a in ipairs(areas) do
|
||||
if not a.habitable then goto continue end
|
||||
|
||||
local v
|
||||
if dir == "up" then
|
||||
if a.x < traverse_x + threshold
|
||||
and traverse_x < a.x + a.width + threshold then
|
||||
v = traverse_y - a.y - a.height
|
||||
else
|
||||
v = -1
|
||||
end
|
||||
elseif dir == "down" then
|
||||
if a.x < traverse_x + threshold
|
||||
and traverse_x < a.x + a.width + threshold then
|
||||
v = a.y - traverse_y
|
||||
else
|
||||
v = -1
|
||||
end
|
||||
elseif dir == "left" then
|
||||
if a.y < traverse_y + threshold
|
||||
and traverse_y < a.y + a.height + threshold then
|
||||
v = traverse_x - a.x - a.width
|
||||
else
|
||||
v = -1
|
||||
end
|
||||
elseif dir == "right" then
|
||||
if a.y < traverse_y + threshold
|
||||
and traverse_y < a.y + a.height + threshold then
|
||||
v = a.x - traverse_x
|
||||
else
|
||||
v = -1
|
||||
end
|
||||
end
|
||||
|
||||
if (v > threshold) and (choice_value == nil or choice_value > v) then
|
||||
choice = i
|
||||
choice_value = v
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
|
||||
if choice == nil then
|
||||
choice = current_area
|
||||
if dir == "up" then
|
||||
traverse_y = screen.workarea.y
|
||||
elseif dir == "down" then
|
||||
traverse_y = screen.workarea.y + screen.workarea.height
|
||||
elseif dir == "left" then
|
||||
traverse_x = screen.workarea.x
|
||||
else
|
||||
traverse_x = screen.workarea.x + screen.workarea.width
|
||||
end
|
||||
end
|
||||
|
||||
if choice ~= nil then
|
||||
tablist = nil
|
||||
set_selected_area(choice)
|
||||
|
||||
if c and draft and cd[c].draft ~= false then
|
||||
local lu = cd[c].lu or cd[c].area
|
||||
local rd = cd[c].rd or cd[c].area
|
||||
|
||||
if draft and move then
|
||||
lu = choice
|
||||
if areas[rd].x + areas[rd].width <= areas[lu].x or
|
||||
areas[rd].y + areas[rd].height <= areas[lu].y
|
||||
then
|
||||
rd = nil
|
||||
end
|
||||
else
|
||||
rd = choice
|
||||
if areas[rd].x + areas[rd].width <= areas[lu].x or
|
||||
areas[rd].y + areas[rd].height <= areas[lu].y
|
||||
then
|
||||
lu = nil
|
||||
end
|
||||
end
|
||||
|
||||
if lu ~= nil and rd ~= nil then
|
||||
machi.layout.set_geometry(c, areas[lu], areas[rd], 0, c.border_width)
|
||||
elseif lu ~= nil then
|
||||
machi.layout.set_geometry(c, areas[lu], nil, 0, c.border_width)
|
||||
elseif rd ~= nil then
|
||||
c.x = min(c.x, areas[rd].x)
|
||||
c.y = min(c.y, areas[rd].y)
|
||||
machi.layout.set_geometry(c, nil, areas[rd], 0, c.border_width)
|
||||
end
|
||||
|
||||
if lu == rd and cd[c].draft ~= true then
|
||||
cd[c].lu = nil
|
||||
cd[c].rd = nil
|
||||
cd[c].area = lu
|
||||
else
|
||||
cd[c].lu = lu
|
||||
cd[c].rd = rd
|
||||
cd[c].area = nil
|
||||
end
|
||||
|
||||
c:emit_signal("request::activate", "mouse.move", {raise=false})
|
||||
c:raise()
|
||||
awful.layout.arrange(screen)
|
||||
elseif c and move then
|
||||
-- move the window
|
||||
local in_draft = cd[c].draft
|
||||
if cd[c].draft ~= nil then
|
||||
in_draft = cd[c].draft
|
||||
elseif cd[c].lu then
|
||||
in_draft = true
|
||||
elseif cd[c].area then
|
||||
in_draft = false
|
||||
else
|
||||
log(ERROR, "Assuming in_draft for unhandled client "..tostring(c))
|
||||
in_draft = true
|
||||
end
|
||||
if in_draft then
|
||||
c.x = areas[choice].x
|
||||
c.y = areas[choice].y
|
||||
else
|
||||
machi.layout.set_geometry(c, areas[choice], areas[choice], 0, c.border_width)
|
||||
cd[c].lu = nil
|
||||
cd[c].rd = nil
|
||||
cd[c].area = choice
|
||||
end
|
||||
c:emit_signal("request::activate", "mouse.move", {raise=false})
|
||||
c:raise()
|
||||
awful.layout.arrange(screen)
|
||||
|
||||
tablist = nil
|
||||
else
|
||||
maintain_tablist()
|
||||
-- move the focus
|
||||
if #tablist > 0 and tablist[1] ~= c then
|
||||
c = tablist[1]
|
||||
capi.client.focus = c
|
||||
end
|
||||
end
|
||||
|
||||
draw()
|
||||
end
|
||||
end
|
||||
|
||||
local tab = function()
|
||||
maintain_tablist()
|
||||
if #tablist > 1 then
|
||||
c = tablist[#tablist]
|
||||
c:emit_signal("request::activate", "mouse.move", {raise=false})
|
||||
c:raise()
|
||||
|
||||
draw()
|
||||
end
|
||||
end
|
||||
|
||||
local function handle_key(mod, key, event)
|
||||
local key_translate_tab = {
|
||||
["k"] = "Up",
|
||||
["h"] = "Left",
|
||||
["j"] = "Down",
|
||||
["l"] = "Right",
|
||||
["K"] = "Up",
|
||||
["H"] = "Left",
|
||||
["J"] = "Down",
|
||||
["L"] = "Right",
|
||||
}
|
||||
|
||||
if event == "release" then
|
||||
if exit_keys and exit_keys[key] then
|
||||
exit()
|
||||
end
|
||||
return
|
||||
end
|
||||
if key_translate_tab[key] ~= nil then
|
||||
key = key_translate_tab[key]
|
||||
end
|
||||
|
||||
maintain_tablist()
|
||||
assert(tablist ~= nil)
|
||||
|
||||
local super = false
|
||||
local shift = false
|
||||
local ctrl = false
|
||||
for i, m in ipairs(mod) do
|
||||
if m == "Mod4" then super = true
|
||||
elseif m == "Shift" then shift = true
|
||||
elseif m == "Control" then ctrl = true
|
||||
end
|
||||
end
|
||||
|
||||
if key == "Tab" then
|
||||
tab()
|
||||
elseif key == "Up" or key == "Down" or key == "Left" or key == "Right" then
|
||||
traverse_areas(key, shift or super, ctrl)
|
||||
elseif (key == "q" or key == "Prior") then
|
||||
local current_area = selected_area()
|
||||
if areas[current_area].parent_id == nil then
|
||||
return
|
||||
end
|
||||
|
||||
set_selected_area(areas[current_area].parent_id)
|
||||
if #parent_stack == 0 or
|
||||
parent_stack[#parent_stack] ~= current_area then
|
||||
parent_stack = {current_area}
|
||||
end
|
||||
parent_stack[#parent_stack + 1] = areas[current_area].parent_id
|
||||
current_area = parent_stack[#parent_stack]
|
||||
|
||||
if c and ctrl and cd[c].draft ~= false then
|
||||
if cd[c].area then
|
||||
cd[c].lu, cd[c].rd, cd[c].area = cd[c].area, cd[c].area, nil
|
||||
end
|
||||
machi.layout.set_geometry(c, areas[current_area], areas[current_area], 0, c.border_width)
|
||||
awful.layout.arrange(screen)
|
||||
end
|
||||
|
||||
draw()
|
||||
elseif (key =="e" or key == "Next") then
|
||||
local current_area = selected_area()
|
||||
if #parent_stack <= 1 or parent_stack[#parent_stack] ~= current_area then
|
||||
return
|
||||
end
|
||||
|
||||
set_selected_area(parent_stack[#parent_stack - 1])
|
||||
table.remove(parent_stack, #parent_stack)
|
||||
current_area = parent_stack[#parent_stack]
|
||||
|
||||
if c and ctrl then
|
||||
if areas[current_area].habitable and cd[c].draft ~= true then
|
||||
cd[c].lu, cd[c].rd, cd[c].area = nil, nil, current_area
|
||||
end
|
||||
machi.layout.set_geometry(c, areas[current_area], areas[current_area], 0, c.border_width)
|
||||
awful.layout.arrange(screen)
|
||||
end
|
||||
|
||||
draw()
|
||||
elseif key == "/" then
|
||||
local current_area = selected_area()
|
||||
local original_cmd = machi.engine.areas_to_command(areas, true, current_area)
|
||||
areas[current_area].hole = true
|
||||
local prefix, suffix = machi.engine.areas_to_command(
|
||||
areas, false):match("(.*)|(.*)")
|
||||
areas[current_area].hole = nil
|
||||
|
||||
workarea = {
|
||||
x = areas[current_area].x - gap * 2,
|
||||
y = areas[current_area].y - gap * 2,
|
||||
width = areas[current_area].width + gap * 4,
|
||||
height = areas[current_area].height + gap * 4,
|
||||
}
|
||||
gtimer.delayed_call(
|
||||
function ()
|
||||
layout.machi_editor.start_interactive(
|
||||
screen,
|
||||
{
|
||||
workarea = workarea,
|
||||
original_cmd = original_cmd,
|
||||
cmd_prefix = prefix,
|
||||
cmd_suffix = suffix,
|
||||
}
|
||||
)
|
||||
end
|
||||
)
|
||||
exit()
|
||||
elseif (key == "f" or key == ".") and c then
|
||||
if cd[c].draft == nil then
|
||||
cd[c].draft = true
|
||||
elseif cd[c].draft == true then
|
||||
cd[c].draft = false
|
||||
else
|
||||
cd[c].draft = nil
|
||||
end
|
||||
awful.layout.arrange(screen)
|
||||
elseif key == "Escape" or key == "Return" then
|
||||
exit()
|
||||
else
|
||||
log(DEBUG, "Unhandled key " .. key)
|
||||
end
|
||||
end
|
||||
|
||||
local ui = function()
|
||||
infobox = wibox({
|
||||
screen = screen,
|
||||
x = screen.workarea.x,
|
||||
y = screen.workarea.y,
|
||||
width = 1, -- screen.workarea.width,
|
||||
height = 1, --screen.workarea.height,
|
||||
bg = "#ffffff00",
|
||||
opacity = 1,
|
||||
ontop = false,
|
||||
type = "normal",
|
||||
})
|
||||
infotabbox = wibox({
|
||||
screen = screen,
|
||||
x = screen.workarea.x,
|
||||
y = screen.workarea.y,
|
||||
width = 1,
|
||||
height = 1,
|
||||
bg = "#ffffff00",
|
||||
ontop = true,
|
||||
type = "normal",
|
||||
visible = true,
|
||||
})
|
||||
|
||||
draw()
|
||||
|
||||
awful.client.focus.history.disable_tracking()
|
||||
local kg
|
||||
local function exit()
|
||||
awful.client.focus.history.enable_tracking()
|
||||
if capi.client.focus then
|
||||
capi.client.emit_signal("focus", capi.client.focus)
|
||||
end
|
||||
infobox.visible = false
|
||||
infotabbox.visible = false
|
||||
awful.keygrabber.stop(kg)
|
||||
end
|
||||
|
||||
kg = awful.keygrabber.run(
|
||||
function (...)
|
||||
ok, _ = pcall(handle_key, ...)
|
||||
if not ok then exit() end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
return {
|
||||
ui = ui,
|
||||
tab = tab,
|
||||
snap_client = snap_client,
|
||||
master_add = master_add,
|
||||
--- swap current window with 'master' or moves it to the master position if it's unoccupied (i.e.: largest area/client)
|
||||
-- @param all swap/move all clients in both areas, not just the top ones.
|
||||
master_swap = master_swap,
|
||||
--- focus client by direction
|
||||
-- @param dir direction (up|right|down|left)
|
||||
-- @returns true if a client was found
|
||||
traverse_clients = traverse_clients,
|
||||
traverse_areas = traverse_areas,
|
||||
move = function(dir) traverse_areas(dir, true, false) end,
|
||||
-- like traverse_clients, returns true if a client was found
|
||||
focus = function(dir) return traverse_clients(dir) end,
|
||||
}
|
||||
end
|
||||
|
||||
return module
|
||||
Reference in New Issue
Block a user