Draft mode
This commit is contained in:
parent
11c804266c
commit
752539bba5
51
README.md
51
README.md
|
@ -53,11 +53,12 @@ The editor is keyboard driven, each command is a key with optional digits (namel
|
||||||
1. `Up`/`Down`: restore to the history command sequence
|
1. `Up`/`Down`: restore to the history command sequence
|
||||||
2. `h`/`v`: split the current region horizontally/vertically into `#D` regions. The split will respect the ratio of digits in `D`.
|
2. `h`/`v`: split the current region horizontally/vertically into `#D` regions. The split will respect the ratio of digits in `D`.
|
||||||
3. `w`: Take the last two digits from `D` as `D = ...AB` (1 if `D` is shorter than 2 digits), and split the current region equally into A rows and B columns. If no digits are provided at all, behave the same as `Space`.
|
3. `w`: Take the last two digits from `D` as `D = ...AB` (1 if `D` is shorter than 2 digits), and split the current region equally into A rows and B columns. If no digits are provided at all, behave the same as `Space`.
|
||||||
4. `s`: shift the current editing region with other open regions. If digits are provided, shift for that many times.
|
4. `d`: Take the argument in the format of `A0B`, where `A` and `B` do not contain any `0`, apply `h` with argument `A` unless `A` is shorter than 2 digits. On each splitted region, apply `v` with argument `B` unless `B` is shorter than 2 digit. Does nothing if the argument is ill-formed.
|
||||||
5. `Space` or `-`: Without parameters, close the current region and move to the next open region. With digits, set the maximum depth of splitting (the default depth is 2).
|
5. `s`: shift the current editing region with other open regions. If digits are provided, shift for that many times.
|
||||||
6. `Enter`/`.`: close all open regions. When all regions are closed, press `Enter` will save the layout and exit the editor.
|
6. `Space` or `-`: Without parameters, close the current region and move to the next open region. With digits, set the maximum depth of splitting (the default depth is 2).
|
||||||
7. `Backspace`: undo the last command.
|
7. `Enter`/`.`: close all open regions. When all regions are closed, press `Enter` will save the layout and exit the editor.
|
||||||
8. `Escape`: exit the editor without saving the layout.
|
8. `Backspace`: undo the last command.
|
||||||
|
9. `Escape`: exit the editor without saving the layout.
|
||||||
|
|
||||||
For examples:
|
For examples:
|
||||||
|
|
||||||
|
@ -107,6 +108,32 @@ Tada!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
`12210121d`
|
||||||
|
|
||||||
|
```
|
||||||
|
11 2222 3333 44
|
||||||
|
11 2222 3333 44
|
||||||
|
|
||||||
|
55 6666 7777 88
|
||||||
|
55 6666 7777 88
|
||||||
|
55 6666 7777 88
|
||||||
|
55 6666 7777 88
|
||||||
|
|
||||||
|
99 AAAA BBBB CC
|
||||||
|
99 AAAA BBBB CC
|
||||||
|
```
|
||||||
|
|
||||||
|
### Draft mode
|
||||||
|
|
||||||
|
__This mode is experimental. Its usage may change fast.__
|
||||||
|
|
||||||
|
Unlike the original machi layout, where a window fits in a single region, draft mode allows window to span across multiple regions.
|
||||||
|
Each tiled window is associated with a upper-left region (ULR) and a bottom-right region (BRR).
|
||||||
|
The geometry of the window is from the upper-left corner of the ULR to the bottom-right corner of the BRR.
|
||||||
|
|
||||||
|
This is suppose to work with regions produced with `d` command.
|
||||||
|
To enable draft mode in a layout, configure the layout with a command with a leading `d`, for example, `d12210121d`.
|
||||||
|
|
||||||
### Persistent history
|
### Persistent history
|
||||||
|
|
||||||
By default, the last 100 command sequences are stored in `.cache/awesome/history_machi`.
|
By default, the last 100 command sequences are stored in `.cache/awesome/history_machi`.
|
||||||
|
@ -117,16 +144,12 @@ To change that, please refer to `editor.lua`. (XXX more documents)
|
||||||
Calling `machi.switcher.start()` will create a switcher supporting the following keys:
|
Calling `machi.switcher.start()` will create a switcher supporting the following keys:
|
||||||
|
|
||||||
- Arrow keys: move focus into other regions by the direction.
|
- Arrow keys: move focus into other regions by the direction.
|
||||||
- `Shift` + arrow keys: move the focused window to other regions by the direction.
|
- `Shift` + arrow keys: move the focused window to other regions by the direction. In draft mode, move the upper-left region by direction.
|
||||||
- `Tab`: switch windows in the same regions.
|
- `Control` + arrow keys: move the bottom-right region of the focused window by direction. Only work in draft mode.
|
||||||
|
- `Tab`: switch beteen windows covering the current regions.
|
||||||
|
|
||||||
So far, the key binding is not configurable. One has to modify the source code to change it.
|
So far, the key binding is not configurable. One has to modify the source code to change it.
|
||||||
|
|
||||||
## Other functions
|
|
||||||
|
|
||||||
`machi.editor.fit_region(c, cycle = false)` will fit a floating client into the closest region.
|
|
||||||
If `cycle` is true, it then moves the window by cycling all regions.
|
|
||||||
|
|
||||||
## Advanced
|
## Advanced
|
||||||
|
|
||||||
### `name` as a function in `machi.layout.create`
|
### `name` as a function in `machi.layout.create`
|
||||||
|
@ -142,10 +165,6 @@ To differentiate tags with the same name, you may need a more advanced naming fu
|
||||||
|
|
||||||
2. True transparency is required. Otherwise switcher and editor will block the clients.
|
2. True transparency is required. Otherwise switcher and editor will block the clients.
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
- Tabs on regions?
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Apache 2.0 --- See LICENSE
|
Apache 2.0 --- See LICENSE
|
||||||
|
|
99
editor.lua
99
editor.lua
|
@ -62,42 +62,6 @@ local function max(a, b)
|
||||||
if a < b then return b else return a end
|
if a < b then return b else return a end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function set_region(c, r)
|
|
||||||
c.floating = false
|
|
||||||
c.maximized = false
|
|
||||||
c.fullscreen = false
|
|
||||||
c.machi_region = r
|
|
||||||
api.layout.arrange(c.screen)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- fit the client into the machi of the screen
|
|
||||||
-- @param c the client to fit
|
|
||||||
-- @param cycle whether to cycle the region if the window is already in machi
|
|
||||||
-- @return whether any actions have been taken on the client
|
|
||||||
local function fit_region(c, cycle)
|
|
||||||
local layout = api.layout.get(c.screen)
|
|
||||||
local regions = layout.machi_get_regions and layout.machi_get_regions(c.screen.workarea, c.screen.selected_tag)
|
|
||||||
if type(regions) ~= "table" or #regions < 1 then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
local current_region = c.machi_region or 1
|
|
||||||
if not is_tiling(c) then
|
|
||||||
-- find out which region has the most intersection, calculated by a cap b / a cup b
|
|
||||||
c.machi_region = machi.layout.find_region(c, regions)
|
|
||||||
set_tiling(c)
|
|
||||||
elseif cycle then
|
|
||||||
if current_region >= #regions then
|
|
||||||
c.machi_region = 1
|
|
||||||
else
|
|
||||||
c.machi_region = current_region + 1
|
|
||||||
end
|
|
||||||
api.layout.arrange(c.screen)
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function _area_tostring(wa)
|
local function _area_tostring(wa)
|
||||||
return "{x:" .. tostring(wa.x) .. ",y:" .. tostring(wa.y) .. ",w:" .. tostring(wa.width) .. ",h:" .. tostring(wa.height) .. "}"
|
return "{x:" .. tostring(wa.x) .. ",y:" .. tostring(wa.y) .. ",w:" .. tostring(wa.width) .. ",h:" .. tostring(wa.height) .. "}"
|
||||||
end
|
end
|
||||||
|
@ -385,6 +349,64 @@ local function create(data)
|
||||||
open_areas[#open_areas + 1] = children[i]
|
open_areas[#open_areas + 1] = children[i]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
elseif method == "d" then
|
||||||
|
|
||||||
|
local x_shares = {}
|
||||||
|
local y_shares = {}
|
||||||
|
|
||||||
|
local current = x_shares
|
||||||
|
for i = 1, #args do
|
||||||
|
local arg
|
||||||
|
if not alt then
|
||||||
|
arg = tonumber(args:sub(i, i))
|
||||||
|
else
|
||||||
|
arg = tonumber(args:sub(#args - i + 1, #args - i + 1))
|
||||||
|
end
|
||||||
|
if arg == 0 then
|
||||||
|
if current == x_shares then current = y_shares else break end
|
||||||
|
else
|
||||||
|
current[#current + 1] = arg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #x_shares == 0 or #y_shares == 0 then
|
||||||
|
open_areas[#open_areas + 1] = a
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
x_shares = fair_split(a.width, x_shares)
|
||||||
|
y_shares = fair_split(a.height, y_shares)
|
||||||
|
|
||||||
|
local children = {}
|
||||||
|
for y_index = 1, #y_shares do
|
||||||
|
for x_index = 1, #x_shares do
|
||||||
|
local r = {
|
||||||
|
x = x_index == 1 and a.x or children[#children].x + children[#children].width,
|
||||||
|
y = y_index == 1 and a.y or (x_index == 1 and children[#children].y + children[#children].height or children[#children].y),
|
||||||
|
width = x_shares[x_index],
|
||||||
|
height = y_shares[y_index],
|
||||||
|
depth = a.depth + 1,
|
||||||
|
group_id = split_count,
|
||||||
|
}
|
||||||
|
if x_index == 1 then r.bl = a.bl else r.bl = false end
|
||||||
|
if x_index == #x_shares then r.br = a.br else r.br = false end
|
||||||
|
if y_index == 1 then r.bu = a.bu else r.bu = false end
|
||||||
|
if y_index == #y_shares then r.bd = a.bd else r.bd = false end
|
||||||
|
children[#children + 1] = r
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = #children, 1, -1 do
|
||||||
|
if children[i].x ~= math.floor(children[i].x)
|
||||||
|
or children[i].y ~= math.floor(children[i].y)
|
||||||
|
or children[i].width ~= math.floor(children[i].width)
|
||||||
|
or children[i].height ~= math.floor(children[i].height)
|
||||||
|
then
|
||||||
|
print("warning, splitting yields floating area " .. _area_tostring(children[i]))
|
||||||
|
end
|
||||||
|
open_areas[#open_areas + 1] = children[i]
|
||||||
|
end
|
||||||
|
|
||||||
elseif method == "p" then
|
elseif method == "p" then
|
||||||
-- XXX
|
-- XXX
|
||||||
end
|
end
|
||||||
|
@ -407,6 +429,8 @@ local function create(data)
|
||||||
else
|
else
|
||||||
handle_split("w", key == "W")
|
handle_split("w", key == "W")
|
||||||
end
|
end
|
||||||
|
elseif key == "d" or key == "D" then
|
||||||
|
handle_split("d", key == "D")
|
||||||
elseif key == "p" or key == "P" then
|
elseif key == "p" or key == "P" then
|
||||||
handle_split("p", key == "P")
|
handle_split("p", key == "P")
|
||||||
elseif key == "s" or key == "S" then
|
elseif key == "s" or key == "S" then
|
||||||
|
@ -578,7 +602,6 @@ local function create(data)
|
||||||
infobox.bgimage = draw_info
|
infobox.bgimage = draw_info
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
print("interactive layout editing starts")
|
print("interactive layout editing starts")
|
||||||
|
|
||||||
init(screen.workarea)
|
init(screen.workarea)
|
||||||
|
@ -760,8 +783,6 @@ end
|
||||||
|
|
||||||
return
|
return
|
||||||
{
|
{
|
||||||
set_region = set_region,
|
|
||||||
fit_region = fit_region,
|
|
||||||
create = create,
|
create = create,
|
||||||
restore_data = restore_data,
|
restore_data = restore_data,
|
||||||
}
|
}
|
||||||
|
|
19
init.lua
19
init.lua
|
@ -1,17 +1,16 @@
|
||||||
local layout = require(... .. ".layout")
|
local layout = require(... .. ".layout")
|
||||||
local editor = require(... .. ".editor")
|
local editor = require(... .. ".editor")
|
||||||
local switcher = require(... .. ".switcher")
|
local switcher = require(... .. ".switcher")
|
||||||
|
local function default_name(tag)
|
||||||
|
if tag.machi_name_cache == nil then
|
||||||
|
tag.machi_name_cache =
|
||||||
|
tostring(tag.screen.geometry.width) .. "x" .. tostring(tag.screen.geometry.height) .. "+" ..
|
||||||
|
tostring(tag.screen.geometry.x) .. "+" .. tostring(tag.screen.geometry.y) .. '+' .. tag.name
|
||||||
|
end
|
||||||
|
return tag.machi_name_cache, true
|
||||||
|
end
|
||||||
local default_editor = editor.create()
|
local default_editor = editor.create()
|
||||||
local default_layout = layout.create(
|
local default_layout = layout.create(default_name, default_editor)
|
||||||
function (tag)
|
|
||||||
if tag.machi_name_cache == nil then
|
|
||||||
tag.machi_name_cache =
|
|
||||||
tostring(tag.screen.geometry.width) .. "x" .. tostring(tag.screen.geometry.height) .. "+" ..
|
|
||||||
tostring(tag.screen.geometry.x) .. "+" .. tostring(tag.screen.geometry.y) .. '+' .. tag.name
|
|
||||||
end
|
|
||||||
return tag.machi_name_cache, true
|
|
||||||
end,
|
|
||||||
default_editor)
|
|
||||||
local gcolor = require("gears.color")
|
local gcolor = require("gears.color")
|
||||||
local beautiful = require("beautiful")
|
local beautiful = require("beautiful")
|
||||||
|
|
||||||
|
|
191
layout.lua
191
layout.lua
|
@ -44,6 +44,42 @@ local function find_region(c, regions)
|
||||||
return choice
|
return choice
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function distance(x1, y1, x2, y2)
|
||||||
|
-- use d1
|
||||||
|
return math.abs(x1 - x2) + math.abs(y1 - y2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find_lu(c, regions)
|
||||||
|
local lu = nil
|
||||||
|
for i, a in ipairs(regions) do
|
||||||
|
if lu == nil or distance(c.x, c.y, a.x, a.y) < distance(c.x, c.y, regions[lu].x, regions[lu].y) then
|
||||||
|
lu = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return lu
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find_rd(c, regions, lu)
|
||||||
|
assert(lu ~= nil)
|
||||||
|
local rd = nil
|
||||||
|
for i, a in ipairs(regions) do
|
||||||
|
if a.x + a.width > regions[lu].x and a.y + a.height > regions[lu].y then
|
||||||
|
if rd == nil or distance(c.x + c.width, c.y + c.height, a.x + a.width, a.y + a.height) < distance(c.x + c.width, c.y + c.height, regions[rd].x + regions[rd].width, regions[rd].y + regions[rd].height) then
|
||||||
|
rd = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return rd
|
||||||
|
end
|
||||||
|
|
||||||
|
local function set_geometry(c, region_lu, region_rd, useless_gap, border_width)
|
||||||
|
-- We try to negate the gap of outer layer8
|
||||||
|
c.x = region_lu.x - useless_gap
|
||||||
|
c.y = region_lu.y - useless_gap
|
||||||
|
c.width = region_rd.x + region_rd.width - region_lu.x + (useless_gap - border_width) * 2
|
||||||
|
c.height = region_rd.y + region_rd.height - region_lu.y + (useless_gap - border_width) * 2
|
||||||
|
end
|
||||||
|
|
||||||
local function create(name, editor)
|
local function create(name, editor)
|
||||||
local instances = {}
|
local instances = {}
|
||||||
|
|
||||||
|
@ -67,13 +103,13 @@ local function create(name, editor)
|
||||||
|
|
||||||
local function get_regions(workarea, tag)
|
local function get_regions(workarea, tag)
|
||||||
local instance = get_instance(tag)
|
local instance = get_instance(tag)
|
||||||
if instance.cmd == nil then return {} end
|
if instance.cmd == nil then return {}, false end
|
||||||
|
|
||||||
local key = tostring(workarea.width) .. "x" .. tostring(workarea.height) .. "+" .. tostring(workarea.x) .. "+" .. tostring(workarea.y)
|
local key = tostring(workarea.width) .. "x" .. tostring(workarea.height) .. "+" .. tostring(workarea.x) .. "+" .. tostring(workarea.y)
|
||||||
if instance.regions_cache[key] == nil then
|
if instance.regions_cache[key] == nil then
|
||||||
instance.regions_cache[key] = editor.run_cmd(workarea, instance.cmd)
|
instance.regions_cache[key] = editor.run_cmd(workarea, instance.cmd)
|
||||||
end
|
end
|
||||||
return instance.regions_cache[key]
|
return instance.regions_cache[key], instance.cmd:sub(1,1) == "d"
|
||||||
end
|
end
|
||||||
|
|
||||||
local function set_cmd(cmd, tag)
|
local function set_cmd(cmd, tag)
|
||||||
|
@ -88,69 +124,122 @@ local function create(name, editor)
|
||||||
local useless_gap = p.useless_gap
|
local useless_gap = p.useless_gap
|
||||||
local wa = get_screen(p.screen).workarea -- get the real workarea without the gap (instead of p.workarea)
|
local wa = get_screen(p.screen).workarea -- get the real workarea without the gap (instead of p.workarea)
|
||||||
local cls = p.clients
|
local cls = p.clients
|
||||||
local regions = get_regions(wa, get_screen(p.screen).selected_tag)
|
local regions, draft_mode = get_regions(wa, get_screen(p.screen).selected_tag)
|
||||||
|
|
||||||
if #regions == 0 then return end
|
if #regions == 0 then return end
|
||||||
|
|
||||||
for i, c in ipairs(cls) do
|
if draft_mode then
|
||||||
if c.floating then
|
for i, c in ipairs(cls) do
|
||||||
print("Ignore client " .. tostring(c))
|
if c.floating then
|
||||||
else
|
else
|
||||||
if c.machi_region == nil then
|
local skip = false
|
||||||
c.machi_region = find_region(c, regions)
|
if c.machi_lu ~= nil and c.machi_rd ~= nil and
|
||||||
elseif c.machi_region > #regions then
|
c.machi_lu <= #regions and c.machi_rd <= #regions
|
||||||
c.machi_region = #regions
|
then
|
||||||
elseif c.machi_region <= 1 then
|
if regions[c.machi_lu].x == c.x and
|
||||||
c.machi_region = 1
|
regions[c.machi_lu].y == c.y and
|
||||||
|
regions[c.machi_rd].x + regions[c.machi_rd].width - c.border_width * 2 == c.x + c.width and
|
||||||
|
regions[c.machi_rd].y + regions[c.machi_rd].height - c.border_width * 2 == c.y + c.height
|
||||||
|
then
|
||||||
|
skip = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local lu = nil
|
||||||
|
local rd = nil
|
||||||
|
if not skip then
|
||||||
|
print("Compute regions for " .. c.name)
|
||||||
|
lu = find_lu(c, regions)
|
||||||
|
if lu ~= nil then
|
||||||
|
rd = find_rd(c, regions, lu)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if lu ~= nil and rd ~= nil then
|
||||||
|
c.machi_lu, c.machi_rd = lu, rd
|
||||||
|
p.geometries[c] = {}
|
||||||
|
set_geometry(p.geometries[c], regions[lu], regions[rd], useless_gap, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i, c in ipairs(cls) do
|
||||||
|
if c.floating then
|
||||||
|
print("Ignore client " .. tostring(c))
|
||||||
|
else
|
||||||
|
if c.machi_region ~= nil and
|
||||||
|
regions[c.machi_region].x == c.x and
|
||||||
|
regions[c.machi_region].y == c.y and
|
||||||
|
regions[c.machi_region].width - c.border_width * 2 == c.width and
|
||||||
|
regions[c.machi_region].height - c.border_width * 2 == c.height
|
||||||
|
then
|
||||||
|
else
|
||||||
|
print("Compute regions for " .. c.name)
|
||||||
|
local region = find_region(c, regions)
|
||||||
|
c.machi_region = region
|
||||||
|
p.geometries[c] = {}
|
||||||
|
set_geometry(p.geometries[c], regions[region], regions[region], useless_gap, 0)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local region = c.machi_region
|
|
||||||
|
|
||||||
-- Editor already handled useless_gap in the stored regions.
|
|
||||||
-- We try to negate the gap of outer layer.
|
|
||||||
p.geometries[c] = {
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
print("Put client " .. tostring(c) .. " to region " .. region)
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- move the closest region regardingly to the center distance
|
local function resize_handler (c, context, h)
|
||||||
local function resize_handler(c, context, h)
|
|
||||||
if context ~= "mouse.move" then return end
|
|
||||||
|
|
||||||
local workarea = c.screen.workarea
|
local workarea = c.screen.workarea
|
||||||
local regions = get_regions(workarea, c.screen.selected_tag)
|
local regions, draft_mode = get_regions(workarea, c.screen.selected_tag)
|
||||||
|
|
||||||
if #regions == 0 then return end
|
if #regions == 0 then return end
|
||||||
|
|
||||||
local center_x = h.x + h.width / 2
|
if draft_mode then
|
||||||
local center_y = h.y + h.height / 2
|
local lu = find_lu(h, regions)
|
||||||
|
local rd = nil
|
||||||
|
if lu ~= nil then
|
||||||
|
if context == "mouse.move" then
|
||||||
|
local hh = {}
|
||||||
|
hh.x = regions[lu].x
|
||||||
|
hh.y = regions[lu].y
|
||||||
|
hh.width = h.width
|
||||||
|
hh.height = h.height
|
||||||
|
rd = find_rd(hh, regions, lu)
|
||||||
|
else
|
||||||
|
rd = find_rd(h, regions, lu)
|
||||||
|
end
|
||||||
|
|
||||||
local choice = 1
|
if rd ~= nil then
|
||||||
local choice_value = nil
|
c.machi_lu = lu
|
||||||
|
c.machi_rd = rd
|
||||||
for i, r in ipairs(regions) do
|
set_geometry(c, regions[lu], regions[rd], 0, c.border_width)
|
||||||
local r_x = r.x + r.width / 2
|
end
|
||||||
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
|
||||||
end
|
else
|
||||||
|
if context ~= "mouse.move" then return end
|
||||||
|
|
||||||
if c.machi_region ~= choice then
|
local workarea = c.screen.workarea
|
||||||
c.machi_region = choice
|
local regions = get_regions(workarea, c.screen.selected_tag)
|
||||||
c.x = regions[choice].x
|
|
||||||
c.y = regions[choice].y
|
if #regions == 0 then return end
|
||||||
c.width = max(1, regions[choice].width - 2 * c.border_width)
|
|
||||||
c.height = max(1, regions[choice].height - 2 * c.border_width)
|
local center_x = h.x + h.width / 2
|
||||||
|
local center_y = h.y + h.height / 2
|
||||||
|
|
||||||
|
local choice = 1
|
||||||
|
local choice_value = nil
|
||||||
|
|
||||||
|
for i, r in ipairs(regions) do
|
||||||
|
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
|
||||||
|
set_geometry(c, regions[choice], regions[choice], 0, c.border_width)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -166,5 +255,5 @@ end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
create = create,
|
create = create,
|
||||||
find_region = find_region,
|
set_geometry = set_geometry,
|
||||||
}
|
}
|
||||||
|
|
143
switcher.lua
143
switcher.lua
|
@ -1,3 +1,7 @@
|
||||||
|
local machi = {
|
||||||
|
layout = require((...):match("(.-)[^%.]+$") .. "layout"),
|
||||||
|
}
|
||||||
|
|
||||||
local api = {
|
local api = {
|
||||||
client = client,
|
client = client,
|
||||||
beautiful = require("beautiful"),
|
beautiful = require("beautiful"),
|
||||||
|
@ -11,19 +15,6 @@ local api = {
|
||||||
dpi = require("beautiful.xresources").apply_dpi,
|
dpi = require("beautiful.xresources").apply_dpi,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- -- Seems not needed?
|
|
||||||
-- local focus_timer = 0
|
|
||||||
-- api.client.connect_signal(
|
|
||||||
-- "focus",
|
|
||||||
-- function (c)
|
|
||||||
-- if c.focus_timer == nil or c.focus_timer < focus_timer then
|
|
||||||
-- c.focus_timer = focus_timer
|
|
||||||
-- end
|
|
||||||
-- focus_timer = c.focus_timer + 1
|
|
||||||
-- c.focus_timer = focus_timer
|
|
||||||
-- end
|
|
||||||
-- )
|
|
||||||
|
|
||||||
local function min(a, b)
|
local function min(a, b)
|
||||||
if a < b then return a else return b end
|
if a < b then return a else return b end
|
||||||
end
|
end
|
||||||
|
@ -59,7 +50,7 @@ local function start(c)
|
||||||
local layout = api.layout.get(screen)
|
local layout = api.layout.get(screen)
|
||||||
if c.floating or layout.machi_get_regions == nil then return end
|
if c.floating or layout.machi_get_regions == nil then return end
|
||||||
|
|
||||||
local regions = layout.machi_get_regions(c.screen.workarea, c.screen.selected_tag)
|
local regions, draft_mode = layout.machi_get_regions(c.screen.workarea, c.screen.selected_tag)
|
||||||
|
|
||||||
local infobox = api.wibox({
|
local infobox = api.wibox({
|
||||||
screen = screen,
|
screen = screen,
|
||||||
|
@ -73,6 +64,7 @@ local function start(c)
|
||||||
})
|
})
|
||||||
infobox.visible = true
|
infobox.visible = true
|
||||||
|
|
||||||
|
local tablist_region = nil
|
||||||
local tablist = nil
|
local tablist = nil
|
||||||
local tablist_index = nil
|
local tablist_index = nil
|
||||||
|
|
||||||
|
@ -83,12 +75,13 @@ local function start(c)
|
||||||
if tablist == nil then
|
if tablist == nil then
|
||||||
tablist = {}
|
tablist = {}
|
||||||
for _, tc in ipairs(screen.tiled_clients) do
|
for _, tc in ipairs(screen.tiled_clients) do
|
||||||
if tc.machi_region == c.machi_region
|
if not (tc.floating or tc.maximized or tc.maximized_horizontal or tc.maximized_vertical)
|
||||||
and not tc.maximized
|
|
||||||
and not tc.maximized_horizontal
|
|
||||||
and not tc.maximized_vertical
|
|
||||||
then
|
then
|
||||||
tablist[#tablist + 1] = tc
|
if tc.x <= traverse_x and traverse_x < tc.x + tc.width and
|
||||||
|
tc.y <= traverse_y and traverse_y < tc.y + tc.height
|
||||||
|
then
|
||||||
|
tablist[#tablist + 1] = tc
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -108,7 +101,8 @@ local function start(c)
|
||||||
cr:rectangle(a.x - start_x, a.y - start_y, a.width, a.height)
|
cr:rectangle(a.x - start_x, a.y - start_y, a.width, a.height)
|
||||||
cr:clip()
|
cr:clip()
|
||||||
|
|
||||||
if i == c.machi_region then
|
if a.x <= traverse_x and traverse_x < a.x + a.width and
|
||||||
|
a.y <= traverse_y and traverse_y < a.y + a.height then
|
||||||
|
|
||||||
local pl = api.lgi.Pango.Layout.create(cr)
|
local pl = api.lgi.Pango.Layout.create(cr)
|
||||||
pl:set_font_description(tablist_font_desc)
|
pl:set_font_description(tablist_font_desc)
|
||||||
|
@ -132,7 +126,9 @@ local function start(c)
|
||||||
local x_offset = a.x + a.width / 2 - start_x
|
local x_offset = a.x + a.width / 2 - start_x
|
||||||
local y_offset = a.y + a.height / 2 - list_height / 2 + vpadding - start_y
|
local y_offset = a.y + a.height / 2 - list_height / 2 + vpadding - start_y
|
||||||
|
|
||||||
cr:rectangle(a.x - start_x, y_offset - vpadding - start_y, a.width, list_height)
|
-- cr:rectangle(a.x - start_x, y_offset - vpadding - start_y, a.width, list_height)
|
||||||
|
-- cover the entire region
|
||||||
|
cr:rectangle(a.x - start_x, a.y - start_y, a.width, a.height)
|
||||||
cr:set_source(fill_color)
|
cr:set_source(fill_color)
|
||||||
cr:fill()
|
cr:fill()
|
||||||
|
|
||||||
|
@ -192,10 +188,33 @@ local function start(c)
|
||||||
infobox.bgimage = draw_info
|
infobox.bgimage = draw_info
|
||||||
end
|
end
|
||||||
elseif key == "Up" or key == "Down" or key == "Left" or key == "Right" then
|
elseif key == "Up" or key == "Down" or key == "Left" or key == "Right" then
|
||||||
|
local shift = false
|
||||||
|
local ctrl = false
|
||||||
|
for i, m in ipairs(mod) do
|
||||||
|
if m == "Shift" then shift = true
|
||||||
|
elseif m == "Control" then ctrl = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if shift then
|
||||||
|
traverse_x = c.x + traverse_radius
|
||||||
|
traverse_y = c.y + traverse_radius
|
||||||
|
elseif ctrl then
|
||||||
|
traverse_x = c.x + c.width - c.border_width * 2 - traverse_radius
|
||||||
|
traverse_y = c.y + c.height - c.border_width * 2 - traverse_radius
|
||||||
|
end
|
||||||
|
|
||||||
local choice = nil
|
local choice = nil
|
||||||
local choice_value
|
local choice_value
|
||||||
|
local current_region = nil
|
||||||
|
|
||||||
for i, a in ipairs(regions) do
|
for i, a in ipairs(regions) do
|
||||||
|
if a.x <= traverse_x and traverse_x < a.x + a.width and
|
||||||
|
a.y <= traverse_y and traverse_y < a.y + a.height
|
||||||
|
then
|
||||||
|
current_region = i
|
||||||
|
end
|
||||||
|
|
||||||
local v
|
local v
|
||||||
if key == "Up" then
|
if key == "Up" then
|
||||||
if a.x < traverse_x + threshold
|
if a.x < traverse_x + threshold
|
||||||
|
@ -233,43 +252,73 @@ local function start(c)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if choice ~= nil and choice_value > threshold then
|
if choice == nil then
|
||||||
local shift = false
|
choice = current_region
|
||||||
for i, m in ipairs(mod) do
|
if key == "Up" then
|
||||||
if m == "Shift" then shift = true end
|
traverse_y = screen.workarea.y
|
||||||
|
elseif key == "Down" then
|
||||||
|
traverse_y = screen.workarea.y + screen.workarea.height
|
||||||
|
elseif key == "Left" then
|
||||||
|
traverse_x = screen.workarea.x
|
||||||
|
else
|
||||||
|
traverse_x = screen.workarea.x + screen.workarea.width
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local move_traverse = false
|
if choice ~= nil then
|
||||||
|
|
||||||
if shift then
|
if shift then
|
||||||
-- move the window
|
if draft_mode then
|
||||||
c.machi_region = choice
|
-- move the left-up region
|
||||||
|
local lu = choice
|
||||||
|
local rd = c.machi_rd
|
||||||
|
if regions[rd].x + regions[rd].width <= regions[lu].x or
|
||||||
|
regions[rd].y + regions[rd].height <= regions[lu].y
|
||||||
|
then
|
||||||
|
rd = lu
|
||||||
|
end
|
||||||
|
machi.layout.set_geometry(c, regions[lu], regions[rd], 0, c.border_width)
|
||||||
|
c.machi_lu = lu
|
||||||
|
c.machi_rd = rd
|
||||||
|
else
|
||||||
|
-- move the window
|
||||||
|
machi.layout.set_geometry(c, regions[choice], regions[choice], 0, c.border_width)
|
||||||
|
c.machi_region = choice
|
||||||
|
end
|
||||||
c:emit_signal("request::activate", "mouse.move", {raise=false})
|
c:emit_signal("request::activate", "mouse.move", {raise=false})
|
||||||
c:raise()
|
c:raise()
|
||||||
api.layout.arrange(screen)
|
api.layout.arrange(screen)
|
||||||
move_traverse = true
|
|
||||||
|
tablist = nil
|
||||||
|
elseif ctrl and draft_mode then
|
||||||
|
-- move the right-down region
|
||||||
|
local lu = c.machi_lu
|
||||||
|
local rd = choice
|
||||||
|
if regions[rd].x + regions[rd].width <= regions[lu].x or
|
||||||
|
regions[rd].y + regions[rd].height <= regions[lu].y
|
||||||
|
then
|
||||||
|
lu = rd
|
||||||
|
end
|
||||||
|
machi.layout.set_geometry(c, regions[lu], regions[rd], 0, c.border_width)
|
||||||
|
c.machi_lu = lu
|
||||||
|
c.machi_rd = rd
|
||||||
|
|
||||||
|
c:emit_signal("request::activate", "mouse.move", {raise=false})
|
||||||
|
c:raise()
|
||||||
|
api.layout.arrange(screen)
|
||||||
|
|
||||||
|
tablist = nil
|
||||||
else
|
else
|
||||||
-- move the focus
|
-- move the focus
|
||||||
for _, tc in ipairs(screen.tiled_clients) do
|
|
||||||
if tc.machi_region == choice
|
|
||||||
and not tc.maximized
|
|
||||||
and not tc.maximized_horizontal
|
|
||||||
and not tc.maximized_vertical
|
|
||||||
then
|
|
||||||
c = tc
|
|
||||||
api.client.focus = c
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
move_traverse = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if move_traverse then
|
|
||||||
traverse_x = max(regions[choice].x + traverse_radius, min(regions[choice].x + regions[choice].width - traverse_radius, traverse_x))
|
|
||||||
traverse_y = max(regions[choice].y + traverse_radius, min(regions[choice].y + regions[choice].height - traverse_radius, traverse_y))
|
|
||||||
tablist = nil
|
tablist = nil
|
||||||
|
ensure_tablist()
|
||||||
|
if #tablist > 0 and tablist[1] ~= c then
|
||||||
|
c = tablist[1]
|
||||||
|
api.client.focus = c
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
traverse_x = max(regions[choice].x + traverse_radius, min(regions[choice].x + regions[choice].width - traverse_radius, traverse_x))
|
||||||
|
traverse_y = max(regions[choice].y + traverse_radius, min(regions[choice].y + regions[choice].height - traverse_radius, traverse_y))
|
||||||
infobox.bgimage = draw_info
|
infobox.bgimage = draw_info
|
||||||
end
|
end
|
||||||
elseif key == "Escape" or key == "Return" then
|
elseif key == "Escape" or key == "Return" then
|
||||||
|
|
Loading…
Reference in New Issue