mirror of https://github.com/einverne/dotfiles.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
9.7 KiB
278 lines
9.7 KiB
--- === WinWin === |
|
--- |
|
--- Windows manipulation |
|
--- |
|
--- Download: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/WinWin.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/WinWin.spoon.zip) |
|
|
|
local obj={} |
|
obj.__index = obj |
|
|
|
-- Metadata |
|
obj.name = "WinWin" |
|
obj.version = "1.0" |
|
obj.author = "ashfinal <[email protected]>" |
|
obj.homepage = "https://github.com/Hammerspoon/Spoons" |
|
obj.license = "MIT - https://opensource.org/licenses/MIT" |
|
|
|
-- Windows manipulation history. Only the last operation is stored. |
|
obj.history = {} |
|
|
|
--- WinWin.gridparts |
|
--- Variable |
|
--- An integer specifying how many gridparts the screen should be divided into. Defaults to 30. |
|
obj.gridparts = 30 |
|
|
|
--- WinWin:stepMove(direction) |
|
--- Method |
|
--- Move the focused window in the `direction` by on step. The step scale equals to the width/height of one gridpart. |
|
--- |
|
--- Parameters: |
|
--- * direction - A string specifying the direction, valid strings are: `left`, `right`, `up`, `down`. |
|
function obj:stepMove(direction) |
|
local cwin = hs.window.focusedWindow() |
|
if cwin then |
|
local cscreen = cwin:screen() |
|
local cres = cscreen:fullFrame() |
|
local stepw = cres.w/obj.gridparts |
|
local steph = cres.h/obj.gridparts |
|
local wtopleft = cwin:topLeft() |
|
if direction == "left" then |
|
cwin:setTopLeft({x=wtopleft.x-stepw, y=wtopleft.y}) |
|
elseif direction == "right" then |
|
cwin:setTopLeft({x=wtopleft.x+stepw, y=wtopleft.y}) |
|
elseif direction == "up" then |
|
cwin:setTopLeft({x=wtopleft.x, y=wtopleft.y-steph}) |
|
elseif direction == "down" then |
|
cwin:setTopLeft({x=wtopleft.x, y=wtopleft.y+steph}) |
|
end |
|
else |
|
hs.alert.show("No focused window!") |
|
end |
|
end |
|
|
|
--- WinWin:stepResize(direction) |
|
--- Method |
|
--- Resize the focused window in the `direction` by on step. |
|
--- |
|
--- Parameters: |
|
--- * direction - A string specifying the direction, valid strings are: `left`, `right`, `up`, `down`. |
|
function obj:stepResize(direction) |
|
local cwin = hs.window.focusedWindow() |
|
if cwin then |
|
local cscreen = cwin:screen() |
|
local cres = cscreen:fullFrame() |
|
local stepw = cres.w/obj.gridparts |
|
local steph = cres.h/obj.gridparts |
|
local wsize = cwin:size() |
|
if direction == "left" then |
|
cwin:setSize({w=wsize.w-stepw, h=wsize.h}) |
|
elseif direction == "right" then |
|
cwin:setSize({w=wsize.w+stepw, h=wsize.h}) |
|
elseif direction == "up" then |
|
cwin:setSize({w=wsize.w, h=wsize.h-steph}) |
|
elseif direction == "down" then |
|
cwin:setSize({w=wsize.w, h=wsize.h+steph}) |
|
end |
|
else |
|
hs.alert.show("No focused window!") |
|
end |
|
end |
|
|
|
--- WinWin:stash() |
|
--- Method |
|
--- Stash current windows's position and size. |
|
--- |
|
|
|
local function isInHistory(windowid) |
|
for idx,val in ipairs(obj.history) do |
|
if val[1] == windowid then |
|
return idx |
|
end |
|
end |
|
return false |
|
end |
|
|
|
function obj:stash() |
|
local cwin = hs.window.focusedWindow() |
|
local winid = cwin:id() |
|
local winf = cwin:frame() |
|
local id_idx = isInHistory(winid) |
|
if id_idx then |
|
-- Bring recently used window id up, so they wouldn't get removed because of exceeding capacity |
|
if id_idx == 100 then |
|
local tmptable = obj.history[id_idx] |
|
table.remove(obj.history, id_idx) |
|
table.insert(obj.history, 1, tmptable) |
|
-- Make sure the history for each application doesn't reach the maximum (100 items) |
|
local id_history = obj.history[1][2] |
|
if #id_history > 100 then table.remove(id_history) end |
|
table.insert(id_history, 1, winf) |
|
else |
|
local id_history = obj.history[id_idx][2] |
|
if #id_history > 100 then table.remove(id_history) end |
|
table.insert(id_history, 1, winf) |
|
end |
|
else |
|
-- Make sure the history of window id doesn't reach the maximum (100 items). |
|
if #obj.history > 100 then table.remove(obj.history) end |
|
-- Stash new window id and its first history |
|
local newtable = {winid, {winf}} |
|
table.insert(obj.history, 1, newtable) |
|
end |
|
end |
|
|
|
--- WinWin:moveAndResize(option) |
|
--- Method |
|
--- Move and resize the focused window. |
|
--- |
|
--- Parameters: |
|
--- * option - A string specifying the option, valid strings are: `halfleft`, `halfright`, `halfup`, `halfdown`, `cornerNW`, `cornerSW`, `cornerNE`, `cornerSE`, `center`, `fullscreen`, `expand`, `shrink`. |
|
|
|
function obj:moveAndResize(option) |
|
local cwin = hs.window.focusedWindow() |
|
if cwin then |
|
local cscreen = cwin:screen() |
|
local cres = cscreen:fullFrame() |
|
local stepw = cres.w/obj.gridparts |
|
local steph = cres.h/obj.gridparts |
|
local wf = cwin:frame() |
|
if option == "halfleft" then |
|
cwin:setFrame({x=cres.x, y=cres.y, w=cres.w/2, h=cres.h}) |
|
elseif option == "halfright" then |
|
cwin:setFrame({x=cres.x+cres.w/2, y=cres.y, w=cres.w/2, h=cres.h}) |
|
elseif option == "halfup" then |
|
cwin:setFrame({x=cres.x, y=cres.y, w=cres.w, h=cres.h/2}) |
|
elseif option == "halfdown" then |
|
cwin:setFrame({x=cres.x, y=cres.y+cres.h/2, w=cres.w, h=cres.h/2}) |
|
elseif option == "cornerNW" then |
|
cwin:setFrame({x=cres.x, y=cres.y, w=cres.w/2, h=cres.h/2}) |
|
elseif option == "cornerNE" then |
|
cwin:setFrame({x=cres.x+cres.w/2, y=cres.y, w=cres.w/2, h=cres.h/2}) |
|
elseif option == "cornerSW" then |
|
cwin:setFrame({x=cres.x, y=cres.y+cres.h/2, w=cres.w/2, h=cres.h/2}) |
|
elseif option == "cornerSE" then |
|
cwin:setFrame({x=cres.x+cres.w/2, y=cres.y+cres.h/2, w=cres.w/2, h=cres.h/2}) |
|
elseif option == "fullscreen" then |
|
cwin:setFrame({x=cres.x, y=cres.y, w=cres.w, h=cres.h}) |
|
elseif option == "center" then |
|
cwin:centerOnScreen() |
|
elseif option == "expand" then |
|
cwin:setFrame({x=wf.x-stepw, y=wf.y-steph, w=wf.w+(stepw*2), h=wf.h+(steph*2)}) |
|
elseif option == "shrink" then |
|
cwin:setFrame({x=wf.x+stepw, y=wf.y+steph, w=wf.w-(stepw*2), h=wf.h-(steph*2)}) |
|
end |
|
else |
|
hs.alert.show("No focused window!") |
|
end |
|
end |
|
|
|
--- WinWin:moveToScreen(direction) |
|
--- Method |
|
--- Move the focused window between all of the screens in the `direction`. |
|
--- |
|
--- Parameters: |
|
--- * direction - A string specifying the direction, valid strings are: `left`, `right`, `up`, `down`, `next`. |
|
function obj:moveToScreen(direction) |
|
local cwin = hs.window.focusedWindow() |
|
if cwin then |
|
local cscreen = cwin:screen() |
|
if direction == "up" then |
|
cwin:moveOneScreenNorth() |
|
elseif direction == "down" then |
|
cwin:moveOneScreenSouth() |
|
elseif direction == "left" then |
|
cwin:moveOneScreenWest() |
|
elseif direction == "right" then |
|
cwin:moveOneScreenEast() |
|
elseif direction == "next" then |
|
cwin:moveToScreen(cscreen:next()) |
|
end |
|
else |
|
hs.alert.show("No focused window!") |
|
end |
|
end |
|
|
|
--- WinWin:undo() |
|
--- Method |
|
--- Undo the last window manipulation. Only those "moveAndResize" manipulations can be undone. |
|
--- |
|
|
|
function obj:undo() |
|
local cwin = hs.window.focusedWindow() |
|
local winid = cwin:id() |
|
-- Has this window been stored previously? |
|
local id_idx = isInHistory(winid) |
|
if id_idx then |
|
-- Bring recently used window id up, so they wouldn't get removed because of exceeding capacity |
|
if id_idx == 100 then |
|
local tmptable = obj.history[id_idx] |
|
table.remove(obj.history, id_idx) |
|
table.insert(obj.history, 1, tmptable) |
|
local id_history = obj.history[1][2] |
|
cwin:setFrame(id_history[1]) |
|
-- Rewind the history |
|
local tmpframe = id_history[1] |
|
table.remove(id_history, 1) |
|
table.insert(id_history, tmpframe) |
|
else |
|
local id_history = obj.history[id_idx][2] |
|
cwin:setFrame(id_history[1]) |
|
local tmpframe = id_history[1] |
|
table.remove(id_history, 1) |
|
table.insert(id_history, tmpframe) |
|
end |
|
end |
|
end |
|
|
|
--- WinWin:redo() |
|
--- Method |
|
--- Redo the window manipulation. Only those "moveAndResize" manipulations can be undone. |
|
--- |
|
|
|
function obj:redo() |
|
local cwin = hs.window.focusedWindow() |
|
local winid = cwin:id() |
|
-- Has this window been stored previously? |
|
local id_idx = isInHistory(winid) |
|
if id_idx then |
|
-- Bring recently used window id up, so they wouldn't get removed because of exceeding capacity |
|
if id_idx == 100 then |
|
local tmptable = obj.history[id_idx] |
|
table.remove(obj.history, id_idx) |
|
table.insert(obj.history, 1, tmptable) |
|
local id_history = obj.history[1][2] |
|
cwin:setFrame(id_history[#id_history]) |
|
-- Play the history |
|
local tmpframe = id_history[#id_history] |
|
table.remove(id_history) |
|
table.insert(id_history, 1, tmpframe) |
|
else |
|
local id_history = obj.history[id_idx][2] |
|
cwin:setFrame(id_history[#id_history]) |
|
local tmpframe = id_history[#id_history] |
|
table.remove(id_history) |
|
table.insert(id_history, 1, tmpframe) |
|
end |
|
end |
|
end |
|
|
|
--- WinWin:centerCursor() |
|
--- Method |
|
--- Center the cursor on the focused window. |
|
--- |
|
|
|
function obj:centerCursor() |
|
local cwin = hs.window.focusedWindow() |
|
local wf = cwin:frame() |
|
local cscreen = cwin:screen() |
|
local cres = cscreen:fullFrame() |
|
if cwin then |
|
-- Center the cursor one the focused window |
|
hs.mouse.setAbsolutePosition({x=wf.x+wf.w/2, y=wf.y+wf.h/2}) |
|
else |
|
-- Center the cursor on the screen |
|
hs.mouse.setAbsolutePosition({x=cres.x+cres.w/2, y=cres.y+cres.h/2}) |
|
end |
|
end |
|
|
|
return obj
|
|
|