set layout directly by command. restore the last layout
This commit is contained in:
parent
358c2cee18
commit
8891f371a8
54
README.md
54
README.md
|
@ -7,55 +7,50 @@ A manual layout for Awesome with a rapid interactive editor.
|
|||
TL;DR --- I want the control of my layout.
|
||||
|
||||
1. Dynamic tiling is an overkill, since tiling is only useful for persistent windows, and people extensively use hibernate/sleep these days.
|
||||
2. I don't want to have all windows moving around whenever a new window shows up.
|
||||
2. I don't want to have all windows moving around whenever a new window shows up.
|
||||
3. I want to have a flexible layout such that I can quickly adjust to whatever I need.
|
||||
|
||||
## Use the layout
|
||||
|
||||
Use `layout_machi.layout.create_layout([LAYOUT_NAME}, [DEFAULT_REGIONS])` to instantiate the layout.
|
||||
For example:
|
||||
|
||||
```
|
||||
layout_machi.layout.create_layout("default", {})
|
||||
```
|
||||
|
||||
Creates a layout with no regions
|
||||
Use `layotu = layout_machi.layout.create()` to instantiate the layout.
|
||||
|
||||
## Use the editor
|
||||
|
||||
Call `layout_machi.editor.start_editor(data)` to enter the editor for the current layout (given it is a machi instance).
|
||||
`data` is am object for storing the history of the editing, initially `{}`.
|
||||
The editor starts with the open area of the entire workarea, taking command to split the current area into multiple sub-areas, then editing each of them.
|
||||
Call `editor = layout_machi.editor.create(data)` to create an editor that can either
|
||||
|
||||
- Interactively edit layout by calling `editor.start_interactive()`
|
||||
- Set the layout with batched commands by calling `editor.set_by_cmd(cmd)`, where cmd is a string
|
||||
|
||||
`data` is an object for storing the history of the editing, initially `{}`.
|
||||
|
||||
### The layout editing command
|
||||
|
||||
The editor starts with the open area of the entire workarea, taking command to split the current area into multiple sub-areas, then editing each of them.
|
||||
The editor is keyboard driven, accepting a number of command keys.
|
||||
Before each command, you can optionally provide at most 2 digits for parameters (A, B) of the command.
|
||||
Undefined parameters are (mostly) treated as 1.
|
||||
|
||||
1. `Up`/`Down`: restore to the history command sequence
|
||||
2. `h`/`v`: split the current region horizontally/vertically into 2 regions. The split will respect the ratio A:B.
|
||||
1. `Up`/`Down`: restore to the history command sequence
|
||||
2. `h`/`v`: split the current region horizontally/vertically into 2 regions. The split will respect the ratio A:B.
|
||||
3. `w`: Take two parameters (A, B), and split the current region equally into A columns and B rows. If no parameter is defined, behave the same as `Space` without parameters.
|
||||
4. `s`: shift the current editing region with other open regions. If A is defined, shift for A times.
|
||||
5. `Space` or `-`: Without parameters, close the current region and move to the next open region. With parameters, set the maximum depth of splitting (default is 2).
|
||||
6. `Enter`/`.`: close all open regions. When all regions are closed, press `Enter` will save the layout and exit the editor.
|
||||
6. `Enter`/`.`: close all open regions. When all regions are closed, press `Enter` will save the layout and exit the editor.
|
||||
7. `Backspace`: undo the last command.
|
||||
8. `Escape`: exit the editor without saving the layout.
|
||||
|
||||
### Demos:
|
||||
|
||||
I used `Super + /` for the editor and `Super + Tab` for fitting the windows.
|
||||
|
||||
For examples:
|
||||
|
||||
h-v
|
||||
|
||||
```
|
||||
11 22
|
||||
11 22
|
||||
11
|
||||
11
|
||||
11 33
|
||||
11 33
|
||||
```
|
||||
|
||||
![](https://i.imgur.com/QbvMRTW.gif)
|
||||
|
||||
|
||||
hvv (or 22w)
|
||||
|
||||
|
@ -67,8 +62,6 @@ hvv (or 22w)
|
|||
22 44
|
||||
```
|
||||
|
||||
![](https://i.imgur.com/xJebxcF.gif)
|
||||
|
||||
|
||||
3-13h2v--2h-12v
|
||||
|
||||
|
@ -97,24 +90,17 @@ Tada!
|
|||
```
|
||||
|
||||
|
||||
history
|
||||
|
||||
![](https://i.imgur.com/gzFr48V.gif)
|
||||
|
||||
### Persistent history
|
||||
|
||||
You need to specify the path of the history file in the editor data, then restore the persistent history by `layout_machi.editor.restore_data`. For example,
|
||||
If you want all command persisted, you need to specify the path of the history file in the editor data.
|
||||
The persisted history can be restored by `layout_machi.editor.restore_data(...)`. For example,
|
||||
|
||||
```
|
||||
machi_layout_data = layout_machi.editor.restore_data({ history_file = ".machi-layout", history_save_max = 10 })
|
||||
machi_editor_data = layout_machi.editor.restore_data({ history_file = ".machi-layout", history_save_max = 10 })
|
||||
```
|
||||
|
||||
Then start the editor with the restored data.
|
||||
The last `history_save_max` commands are persisted.
|
||||
|
||||
## Other goodies
|
||||
|
||||
- Moving a window using the mouse will move it across regions
|
||||
|
||||
## Other functions
|
||||
|
||||
|
|
498
editor.lua
498
editor.lua
|
@ -86,7 +86,7 @@ function cycle_region(c)
|
|||
end
|
||||
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
|
||||
-- find out which region has the most intersection, calculated by a cap b / a cup b
|
||||
c.machi_region = fit_region(c, regions)
|
||||
set_tiling(c)
|
||||
elseif current_region >= #regions then
|
||||
|
@ -107,40 +107,9 @@ function shrink_area_with_gap(a, gap)
|
|||
height = a.height - (a.bu and 0 or gap / 2) - (a.bd and 0 or gap / 2) }
|
||||
end
|
||||
|
||||
function start_editor(data)
|
||||
function create(data)
|
||||
local gap = data.gap or 0
|
||||
|
||||
if data.cmds == nil then
|
||||
data.cmds = {}
|
||||
end
|
||||
|
||||
local cmd_index = #data.cmds + 1
|
||||
data.cmds[cmd_index] = ""
|
||||
|
||||
local screen = api.screen.focused()
|
||||
local init_area = {
|
||||
x = screen.workarea.x,
|
||||
y = screen.workarea.y,
|
||||
width = screen.workarea.width,
|
||||
height = screen.workarea.height,
|
||||
border = 15,
|
||||
depth = 0,
|
||||
group_id = 0,
|
||||
-- we do not want to rely on BitOp
|
||||
bl = true, br = true, bu = true, bd = true,
|
||||
}
|
||||
local kg
|
||||
local infobox = api.wibox({
|
||||
x = screen.workarea.x,
|
||||
y = screen.workarea.y,
|
||||
width = screen.workarea.width,
|
||||
height = screen.workarea.height,
|
||||
bg = "#ffffff00",
|
||||
opacity = 1,
|
||||
ontop = true
|
||||
})
|
||||
infobox.visible = true
|
||||
|
||||
local closed_areas
|
||||
local open_areas
|
||||
local history
|
||||
|
@ -152,9 +121,21 @@ function start_editor(data)
|
|||
local to_exit
|
||||
local to_apply
|
||||
|
||||
local function init()
|
||||
local function init(init_area)
|
||||
closed_areas = {}
|
||||
open_areas = {init_area}
|
||||
open_areas = {
|
||||
{
|
||||
x = init_area.x,
|
||||
y = init_area.y,
|
||||
width = init_area.width,
|
||||
height = init_area.height,
|
||||
border = 15,
|
||||
depth = 0,
|
||||
group_id = 0,
|
||||
-- we do not want to rely on BitOp
|
||||
bl = true, br = true, bu = true, bd = true,
|
||||
}
|
||||
}
|
||||
history = {}
|
||||
num_1 = nil
|
||||
num_2 = nil
|
||||
|
@ -165,68 +146,6 @@ function start_editor(data)
|
|||
to_apply = false
|
||||
end
|
||||
|
||||
local function draw_info(context, cr, width, height)
|
||||
cr:set_source_rgba(0, 0, 0, 0)
|
||||
cr:rectangle(0, 0, width, height)
|
||||
cr:fill()
|
||||
|
||||
local msg, ext
|
||||
|
||||
for i, a in ipairs(closed_areas) do
|
||||
local sa = shrink_area_with_gap(a, gap)
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:clip()
|
||||
cr:set_source(api.gears.color(closed_color))
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:fill()
|
||||
cr:set_source(api.gears.color(border_color))
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:set_line_width(10.0)
|
||||
cr:stroke()
|
||||
cr:reset_clip()
|
||||
end
|
||||
|
||||
for i, a in ipairs(open_areas) do
|
||||
local sa = shrink_area_with_gap(a, gap)
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:clip()
|
||||
if i == #open_areas then
|
||||
cr:set_source(api.gears.color(active_color))
|
||||
else
|
||||
cr:set_source(api.gears.color(open_color))
|
||||
end
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:fill()
|
||||
|
||||
cr:set_source(api.gears.color(border_color))
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:set_line_width(10.0)
|
||||
if i ~= #open_areas then
|
||||
cr:set_dash({5, 5}, 0)
|
||||
cr:stroke()
|
||||
cr:set_dash({}, 0)
|
||||
else
|
||||
cr:stroke()
|
||||
end
|
||||
cr:reset_clip()
|
||||
end
|
||||
|
||||
cr:select_font_face(label_font_family, "normal", "normal")
|
||||
cr:set_font_size(info_size)
|
||||
cr:set_font_face(cr:get_font_face())
|
||||
msg = current_info
|
||||
ext = cr:text_extents(msg)
|
||||
cr:move_to(width / 2 - ext.width / 2 - ext.x_bearing, height / 2 - ext.height / 2 - ext.y_bearing)
|
||||
cr:text_path(msg)
|
||||
cr:set_source_rgba(1, 1, 1, 1)
|
||||
cr:fill()
|
||||
cr:move_to(width / 2 - ext.width / 2 - ext.x_bearing, height / 2 - ext.height / 2 - ext.y_bearing)
|
||||
cr:text_path(msg)
|
||||
cr:set_source_rgba(0, 0, 0, 1)
|
||||
cr:set_line_width(2.0)
|
||||
cr:stroke()
|
||||
end
|
||||
|
||||
local function push_history()
|
||||
history[#history + 1] = {#closed_areas, #open_areas, {}, current_info, current_cmd, max_depth, num_1, num_2}
|
||||
end
|
||||
|
@ -269,18 +188,6 @@ function start_editor(data)
|
|||
return a
|
||||
end
|
||||
|
||||
local function refresh()
|
||||
print("closed areas:")
|
||||
for i, a in ipairs(closed_areas) do
|
||||
print(" " .. _area_tostring(a))
|
||||
end
|
||||
print("open areas:")
|
||||
for i, a in ipairs(open_areas) do
|
||||
print(" " .. _area_tostring(a))
|
||||
end
|
||||
infobox.bgimage = draw_info
|
||||
end
|
||||
|
||||
local split_count = 0
|
||||
|
||||
local function handle_split(method, alt)
|
||||
|
@ -362,13 +269,8 @@ function start_editor(data)
|
|||
num_2 = nil
|
||||
end
|
||||
|
||||
local function cleanup()
|
||||
infobox.visible = false
|
||||
end
|
||||
|
||||
local function push_area()
|
||||
closed_areas[#closed_areas + 1] = pop_open_area()
|
||||
infobox.bgimage = draw_info
|
||||
end
|
||||
|
||||
local function handle_command(key)
|
||||
|
@ -434,141 +336,285 @@ function start_editor(data)
|
|||
return key
|
||||
end
|
||||
|
||||
print("interactive layout editing starts")
|
||||
local function start_interactive()
|
||||
if data.cmds == nil then
|
||||
data.cmds = {}
|
||||
end
|
||||
|
||||
init()
|
||||
refresh()
|
||||
local cmd_index = #data.cmds + 1
|
||||
data.cmds[cmd_index] = ""
|
||||
|
||||
kg = keygrabber.run(function (mod, key, event)
|
||||
if event == "release" then
|
||||
return
|
||||
local screen = api.screen.focused()
|
||||
local kg
|
||||
local infobox = api.wibox({
|
||||
x = screen.workarea.x,
|
||||
y = screen.workarea.y,
|
||||
width = screen.workarea.width,
|
||||
height = screen.workarea.height,
|
||||
bg = "#ffffff00",
|
||||
opacity = 1,
|
||||
ontop = true
|
||||
})
|
||||
infobox.visible = true
|
||||
|
||||
local function cleanup()
|
||||
infobox.visible = false
|
||||
end
|
||||
|
||||
local function draw_info(context, cr, width, height)
|
||||
cr:set_source_rgba(0, 0, 0, 0)
|
||||
cr:rectangle(0, 0, width, height)
|
||||
cr:fill()
|
||||
|
||||
local msg, ext
|
||||
|
||||
for i, a in ipairs(closed_areas) do
|
||||
local sa = shrink_area_with_gap(a, gap)
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:clip()
|
||||
cr:set_source(api.gears.color(closed_color))
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:fill()
|
||||
cr:set_source(api.gears.color(border_color))
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:set_line_width(10.0)
|
||||
cr:stroke()
|
||||
cr:reset_clip()
|
||||
end
|
||||
|
||||
if key == "BackSpace" then
|
||||
pop_history()
|
||||
elseif key == "Escape" then
|
||||
table.remove(data.cmds, #data.cmds)
|
||||
to_exit = true
|
||||
elseif key == "Up" or key == "Down" then
|
||||
if current_cmd ~= data.cmds[cmd_index] then
|
||||
data.cmds[#data.cmds] = current_cmd
|
||||
end
|
||||
|
||||
if key == "Up" and cmd_index > 1 then
|
||||
cmd_index = cmd_index - 1
|
||||
elseif key == "Down" and cmd_index < #data.cmds then
|
||||
cmd_index = cmd_index + 1
|
||||
end
|
||||
|
||||
print("restore history #" .. tostring(cmd_index) .. ":" .. data.cmds[cmd_index])
|
||||
init()
|
||||
for i = 1, #data.cmds[cmd_index] do
|
||||
cmd = data.cmds[cmd_index]:sub(i, i)
|
||||
|
||||
push_history()
|
||||
local ret = handle_command(cmd)
|
||||
|
||||
current_info = current_info .. ret
|
||||
current_cmd = current_cmd .. ret
|
||||
end
|
||||
|
||||
if #open_areas == 0 then
|
||||
current_info = current_info .. " (enter to save)"
|
||||
end
|
||||
elseif #open_areas > 0 then
|
||||
push_history()
|
||||
local ret = handle_command(key)
|
||||
if ret ~= nil then
|
||||
current_info = current_info .. ret
|
||||
current_cmd = current_cmd .. ret
|
||||
for i, a in ipairs(open_areas) do
|
||||
local sa = shrink_area_with_gap(a, gap)
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:clip()
|
||||
if i == #open_areas then
|
||||
cr:set_source(api.gears.color(active_color))
|
||||
else
|
||||
discard_history()
|
||||
cr:set_source(api.gears.color(open_color))
|
||||
end
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:fill()
|
||||
|
||||
cr:set_source(api.gears.color(border_color))
|
||||
cr:rectangle(sa.x, sa.y, sa.width, sa.height)
|
||||
cr:set_line_width(10.0)
|
||||
if i ~= #open_areas then
|
||||
cr:set_dash({5, 5}, 0)
|
||||
cr:stroke()
|
||||
cr:set_dash({}, 0)
|
||||
else
|
||||
cr:stroke()
|
||||
end
|
||||
cr:reset_clip()
|
||||
end
|
||||
|
||||
cr:select_font_face(label_font_family, "normal", "normal")
|
||||
cr:set_font_size(info_size)
|
||||
cr:set_font_face(cr:get_font_face())
|
||||
msg = current_info
|
||||
ext = cr:text_extents(msg)
|
||||
cr:move_to(width / 2 - ext.width / 2 - ext.x_bearing, height / 2 - ext.height / 2 - ext.y_bearing)
|
||||
cr:text_path(msg)
|
||||
cr:set_source_rgba(1, 1, 1, 1)
|
||||
cr:fill()
|
||||
cr:move_to(width / 2 - ext.width / 2 - ext.x_bearing, height / 2 - ext.height / 2 - ext.y_bearing)
|
||||
cr:text_path(msg)
|
||||
cr:set_source_rgba(0, 0, 0, 1)
|
||||
cr:set_line_width(2.0)
|
||||
cr:stroke()
|
||||
end
|
||||
|
||||
local function refresh()
|
||||
print("closed areas:")
|
||||
for i, a in ipairs(closed_areas) do
|
||||
print(" " .. _area_tostring(a))
|
||||
end
|
||||
print("open areas:")
|
||||
for i, a in ipairs(open_areas) do
|
||||
print(" " .. _area_tostring(a))
|
||||
end
|
||||
infobox.bgimage = draw_info
|
||||
end
|
||||
|
||||
|
||||
print("interactive layout editing starts")
|
||||
|
||||
init(screen.workarea)
|
||||
refresh()
|
||||
|
||||
kg = keygrabber.run(function (mod, key, event)
|
||||
if event == "release" then
|
||||
return
|
||||
end
|
||||
|
||||
if #open_areas == 0 then
|
||||
current_info = current_info .. " (enter to save)"
|
||||
end
|
||||
else
|
||||
if key == "Return" then
|
||||
if key == "BackSpace" then
|
||||
pop_history()
|
||||
elseif key == "Escape" then
|
||||
table.remove(data.cmds, #data.cmds)
|
||||
-- remove duplicated entries
|
||||
local j = 1
|
||||
for i = 1, #data.cmds do
|
||||
if data.cmds[i] ~= current_cmd then
|
||||
data.cmds[j] = data.cmds[i]
|
||||
j = j + 1
|
||||
end
|
||||
to_exit = true
|
||||
elseif key == "Up" or key == "Down" then
|
||||
if current_cmd ~= data.cmds[cmd_index] then
|
||||
data.cmds[#data.cmds] = current_cmd
|
||||
end
|
||||
for i = #data.cmds, j, -1 do
|
||||
table.remove(data.cmds, i)
|
||||
end
|
||||
-- bring the current cmd to the front
|
||||
data.cmds[#data.cmds + 1] = current_cmd
|
||||
|
||||
if data.history_file then
|
||||
local file, err = io.open(data.history_file, "w")
|
||||
if err then
|
||||
print("cannot save history to " .. data.history_file)
|
||||
else
|
||||
for i = max(1, #data.cmds - data.history_save_max + 1), #data.cmds do
|
||||
print("save cmd " .. data.cmds[i])
|
||||
file:write(data.cmds[i] .. "\n")
|
||||
if key == "Up" and cmd_index > 1 then
|
||||
cmd_index = cmd_index - 1
|
||||
elseif key == "Down" and cmd_index < #data.cmds then
|
||||
cmd_index = cmd_index + 1
|
||||
end
|
||||
|
||||
print("restore history #" .. tostring(cmd_index) .. ":" .. data.cmds[cmd_index])
|
||||
init(screen.workarea)
|
||||
for i = 1, #data.cmds[cmd_index] do
|
||||
cmd = data.cmds[cmd_index]:sub(i, i)
|
||||
|
||||
push_history()
|
||||
local ret = handle_command(cmd)
|
||||
|
||||
current_info = current_info .. ret
|
||||
current_cmd = current_cmd .. ret
|
||||
end
|
||||
|
||||
if #open_areas == 0 then
|
||||
current_info = current_info .. " (enter to save)"
|
||||
end
|
||||
elseif #open_areas > 0 then
|
||||
push_history()
|
||||
local ret = handle_command(key)
|
||||
if ret ~= nil then
|
||||
current_info = current_info .. ret
|
||||
current_cmd = current_cmd .. ret
|
||||
else
|
||||
discard_history()
|
||||
end
|
||||
|
||||
if #open_areas == 0 then
|
||||
current_info = current_info .. " (enter to save)"
|
||||
end
|
||||
else
|
||||
if key == "Return" then
|
||||
table.remove(data.cmds, #data.cmds)
|
||||
-- remove duplicated entries
|
||||
local j = 1
|
||||
for i = 1, #data.cmds do
|
||||
if data.cmds[i] ~= current_cmd then
|
||||
data.cmds[j] = data.cmds[i]
|
||||
j = j + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
current_info = "Saved!"
|
||||
to_exit = true
|
||||
to_apply = true
|
||||
end
|
||||
end
|
||||
|
||||
refresh()
|
||||
|
||||
if to_exit then
|
||||
print("interactive layout editing ends")
|
||||
if to_apply then
|
||||
layout = api.layout.get(screen)
|
||||
if layout.set_regions then
|
||||
local areas_with_gap = {}
|
||||
for _, a in ipairs(closed_areas) do
|
||||
areas_with_gap[#areas_with_gap + 1] = shrink_area_with_gap(a, gap)
|
||||
for i = #data.cmds, j, -1 do
|
||||
table.remove(data.cmds, i)
|
||||
end
|
||||
table.sort(
|
||||
areas_with_gap,
|
||||
function (a1, a2)
|
||||
local s1 = a1.width * a1.height
|
||||
local s2 = a2.width * a2.height
|
||||
if math.abs(s1 - s2) < 0.01 then
|
||||
return (a1.x + a1.y) < (a2.x + a2.y)
|
||||
else
|
||||
return s1 > s2
|
||||
-- bring the current cmd to the front
|
||||
data.cmds[#data.cmds + 1] = current_cmd
|
||||
|
||||
if data.history_file then
|
||||
local file, err = io.open(data.history_file, "w")
|
||||
if err then
|
||||
print("cannot save history to " .. data.history_file)
|
||||
else
|
||||
for i = max(1, #data.cmds - data.history_save_max + 1), #data.cmds do
|
||||
print("save cmd " .. data.cmds[i])
|
||||
file:write(data.cmds[i] .. "\n")
|
||||
end
|
||||
end
|
||||
)
|
||||
layout.set_regions(areas_with_gap)
|
||||
api.layout.arrange(screen)
|
||||
end
|
||||
|
||||
current_info = "Saved!"
|
||||
to_exit = true
|
||||
to_apply = true
|
||||
end
|
||||
api.gears.timer{
|
||||
timeout = 1,
|
||||
autostart = true,
|
||||
singleshot = true,
|
||||
callback = cleanup
|
||||
}
|
||||
else
|
||||
cleanup()
|
||||
end
|
||||
keygrabber.stop(kg)
|
||||
return
|
||||
|
||||
refresh()
|
||||
|
||||
if to_exit then
|
||||
print("interactive layout editing ends")
|
||||
if to_apply then
|
||||
local layout = api.layout.get(screen)
|
||||
if layout.set_regions then
|
||||
local areas_with_gap = {}
|
||||
for _, a in ipairs(closed_areas) do
|
||||
areas_with_gap[#areas_with_gap + 1] = shrink_area_with_gap(a, gap)
|
||||
end
|
||||
table.sort(
|
||||
areas_with_gap,
|
||||
function (a1, a2)
|
||||
local s1 = a1.width * a1.height
|
||||
local s2 = a2.width * a2.height
|
||||
if math.abs(s1 - s2) < 0.01 then
|
||||
return (a1.x + a1.y) < (a2.x + a2.y)
|
||||
else
|
||||
return s1 > s2
|
||||
end
|
||||
end
|
||||
)
|
||||
layout.cmd = current_cmd
|
||||
layout.set_regions(areas_with_gap)
|
||||
api.layout.arrange(screen)
|
||||
end
|
||||
api.gears.timer{
|
||||
timeout = 1,
|
||||
autostart = true,
|
||||
singleshot = true,
|
||||
callback = cleanup
|
||||
}
|
||||
else
|
||||
cleanup()
|
||||
end
|
||||
keygrabber.stop(kg)
|
||||
return
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function set_by_cmd(layout, screen, cmd)
|
||||
init(screen.workarea)
|
||||
push_history()
|
||||
|
||||
for i = 1, #cmd do
|
||||
local key = handle_command(cmd:sub(i, i))
|
||||
end
|
||||
|
||||
local areas_with_gap = {}
|
||||
for _, a in ipairs(closed_areas) do
|
||||
areas_with_gap[#areas_with_gap + 1] = shrink_area_with_gap(a, gap)
|
||||
end
|
||||
table.sort(
|
||||
areas_with_gap,
|
||||
function (a1, a2)
|
||||
local s1 = a1.width * a1.height
|
||||
local s2 = a2.width * a2.height
|
||||
if math.abs(s1 - s2) < 0.01 then
|
||||
return (a1.x + a1.y) < (a2.x + a2.y)
|
||||
else
|
||||
return s1 > s2
|
||||
end
|
||||
end
|
||||
end)
|
||||
)
|
||||
layout.cmd = cmd
|
||||
layout.set_regions(areas_with_gap)
|
||||
api.layout.arrange(screen)
|
||||
end
|
||||
|
||||
local function try_restore_last(layout, screen)
|
||||
local index = #data.cmds
|
||||
if index == 0 then return end
|
||||
|
||||
set_by_cmd(layout, screen, data.cmds[#data.cmds])
|
||||
end
|
||||
|
||||
return {
|
||||
start_interactive = start_interactive,
|
||||
set_by_cmd = set_by_cmd,
|
||||
try_restore_last = try_restore_last,
|
||||
}
|
||||
end
|
||||
|
||||
function restore_data(data)
|
||||
if data.history_file then
|
||||
local file, err = io.open(data.history_file, "r")
|
||||
if err then
|
||||
print("cannot read history from " .. data.history_file)
|
||||
print("cannot read history from " .. data.history_file)
|
||||
else
|
||||
data.cmds = {}
|
||||
for line in file:lines() do
|
||||
|
@ -585,6 +631,6 @@ return
|
|||
{
|
||||
set_region = set_region,
|
||||
cycle_region = cycle_region,
|
||||
start_editor = start_editor,
|
||||
create = create,
|
||||
restore_data = restore_data,
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ function do_arrange(p, priv)
|
|||
end
|
||||
end
|
||||
|
||||
function create_layout(name, regions)
|
||||
function create()
|
||||
local priv = { regions = {} }
|
||||
|
||||
local function set_regions(regions)
|
||||
|
@ -72,10 +72,7 @@ function create_layout(name, regions)
|
|||
end
|
||||
end
|
||||
|
||||
set_regions(regions)
|
||||
|
||||
return {
|
||||
name = "machi[" .. name .. "]",
|
||||
arrange = function (p) do_arrange(p, priv) end,
|
||||
get_region_count = function () return #priv.regions end,
|
||||
set_regions = set_regions,
|
||||
|
@ -85,5 +82,5 @@ function create_layout(name, regions)
|
|||
end
|
||||
|
||||
return {
|
||||
create_layout = create_layout,
|
||||
create = create,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue