diff --git a/MiroWindowsManager.spoon/docs.json b/MiroWindowsManager.spoon/docs.json index c0bbc6c..3b4320a 100644 --- a/MiroWindowsManager.spoon/docs.json +++ b/MiroWindowsManager.spoon/docs.json @@ -11,17 +11,15 @@ ], "Variable" : [ { - "def" : "MiroWindowsManager.sizes", + "doc" : "The sizes that the window can have. \nThe sizes are expressed as dividend of the entire screen's size. \nFor example `{2, 3, 3\/2}` means that it can be 1\/2, 1\/3 and 2\/3 of the total screen's size. \nMake sure that these numbers divide both dimensions of MiroWindowsManager.GRID to give integers.", "stripped_doc" : [ "The sizes that the window can have. ", "The sizes are expressed as dividend of the entire screen's size. ", - "For example `{2, 3, 3\/2}` means that it can be 1\/2, 1\/3 and 2\/3 of the total", - "screen's size. ", - "Ensuring that these numbers all divide both dimensions of", - "MiroWindowsManager.GRID to give integers makes everything work better." + "For example `{2, 3, 3\/2}` means that it can be 1\/2, 1\/3 and 2\/3 of the total screen's size. ", + "Make sure that these numbers divide both dimensions of MiroWindowsManager.GRID to give integers." ], - "desc" : "The sizes that the window can have.", - "doc" : "The sizes that the window can have. \nThe sizes are expressed as dividend of the entire screen's size. \nFor example `{2, 3, 3\/2}` means that it can be 1\/2, 1\/3 and 2\/3 of the total\nscreen's size. \nEnsuring that these numbers all divide both dimensions of\nMiroWindowsManager.GRID to give integers makes everything work better.", + "def" : "MiroWindowsManager.sizes", + "name" : "sizes", "notes" : [ ], @@ -30,25 +28,22 @@ "returns" : [ ], - "name" : "sizes", + "desc" : "The sizes that the window can have.", "parameters" : [ ] }, { - "def" : "MiroWindowsManager.fullScreenSizes", + "doc" : "The sizes that the window can have in full-screen. \nThe sizes are expressed as dividend of the entire screen's size. \nFor example `{1, 4\/3, 2}` means that it can be 1\/1 (hence full screen), 3\/4 and 1\/2 of the total screen's size. \nMake sure that these numbers divide both dimensions of MiroWindowsManager.GRID to give integers.\nUse 'c' for the original size and shape of the window before starting to move it.", "stripped_doc" : [ "The sizes that the window can have in full-screen. ", "The sizes are expressed as dividend of the entire screen's size. ", - "For example `{1, 4\/3, 2}` means that it can be 1\/1 (hence full screen), 3\/4", - "and 1\/2 of the total screen's size. ", - "Ensuring that these numbers all divide both dimensions of", - "MiroWindowsManager.GRID to give integers makes everything work better. ", - "Special: Use 'c' for the original size and shape of the window before", - "starting to move it, but centered." + "For example `{1, 4\/3, 2}` means that it can be 1\/1 (hence full screen), 3\/4 and 1\/2 of the total screen's size. ", + "Make sure that these numbers divide both dimensions of MiroWindowsManager.GRID to give integers.", + "Use 'c' for the original size and shape of the window before starting to move it." ], - "desc" : "The sizes that the window can have in full-screen.", - "doc" : "The sizes that the window can have in full-screen. \nThe sizes are expressed as dividend of the entire screen's size. \nFor example `{1, 4\/3, 2}` means that it can be 1\/1 (hence full screen), 3\/4\nand 1\/2 of the total screen's size. \nEnsuring that these numbers all divide both dimensions of\nMiroWindowsManager.GRID to give integers makes everything work better. \nSpecial: Use 'c' for the original size and shape of the window before\nstarting to move it, but centered.", + "def" : "MiroWindowsManager.fullScreenSizes", + "name" : "fullScreenSizes", "notes" : [ ], @@ -57,21 +52,19 @@ "returns" : [ ], - "name" : "fullScreenSizes", + "desc" : "The sizes that the window can have in full-screen.", "parameters" : [ ] }, { - "def" : "MiroWindowsManager.GRID", + "doc" : "The screen's grid size. \nMake sure that the numbers in MiroWindowsManager.sizes and MiroWindowsManager.fullScreenSizes divide h and w to give integers.", "stripped_doc" : [ "The screen's grid size. ", - "Ensuring that the numbers in MiroWindowsManager.sizes and", - "MiroWindowsManager.fullScreenSizes divide these numbers to give integers", - "makes everything work better." + "Make sure that the numbers in MiroWindowsManager.sizes and MiroWindowsManager.fullScreenSizes divide h and w to give integers." ], - "desc" : "The screen's grid size.", - "doc" : "The screen's grid size. \nEnsuring that the numbers in MiroWindowsManager.sizes and\nMiroWindowsManager.fullScreenSizes divide these numbers to give integers\nmakes everything work better.", + "def" : "MiroWindowsManager.GRID", + "name" : "GRID", "notes" : [ ], @@ -80,28 +73,67 @@ "returns" : [ ], - "name" : "GRID", + "desc" : "The screen's grid size.", "parameters" : [ ] }, { - "def" : "MiroWindowsManager.moveToNextScreen", + "doc" : "Boolean value to decide whether or not to move the window on the next screen if the window is moved the screen edge.", "stripped_doc" : [ - "Boolean value to decide wether or not to move the window on the next screen", - "if the window is moved the screen edge." + "Boolean value to decide whether or not to move the window on the next screen if the window is moved the screen edge." ], - "desc" : "Boolean value to decide wether or not to move the window on the next screen", - "doc" : "Boolean value to decide wether or not to move the window on the next screen\nif the window is moved the screen edge.", + "def" : "MiroWindowsManager.pushToNextScreen", + "name" : "pushToNextScreen", "notes" : [ ], - "signature" : "MiroWindowsManager.moveToNextScreen", + "signature" : "MiroWindowsManager.pushToNextScreen", "type" : "Variable", "returns" : [ ], - "name" : "moveToNextScreen", + "desc" : "Boolean value to decide whether or not to move the window on the next screen if the window is moved the screen edge.", + "parameters" : [ + + ] + }, + { + "doc" : "Boolean value to decide whether or not to stick the window to the edge of the screen if shrinking it would detatch it from the screen edge.", + "stripped_doc" : [ + "Boolean value to decide whether or not to stick the window to the edge of the screen if shrinking it would detatch it from the screen edge." + ], + "def" : "MiroWindowsManager.stickySides", + "name" : "stickySides", + "notes" : [ + + ], + "signature" : "MiroWindowsManager.stickySides", + "type" : "Variable", + "returns" : [ + + ], + "desc" : "Boolean value to decide whether or not to stick the window to the edge of the screen if shrinking it would detatch it from the screen edge.", + "parameters" : [ + + ] + }, + { + "doc" : "Float value to decide the rate at which to resize windows. A value of 1.05 means that the window is made taller\/wider (or shorter\/thinner) in 5% increments.", + "stripped_doc" : [ + "Float value to decide the rate at which to resize windows. A value of 1.05 means that the window is made taller\/wider (or shorter\/thinner) in 5% increments." + ], + "def" : "MiroWindowsManager.resizeRate", + "name" : "resizeRate", + "notes" : [ + + ], + "signature" : "MiroWindowsManager.resizeRate", + "type" : "Variable", + "returns" : [ + + ], + "desc" : "Float value to decide the rate at which to resize windows. A value of 1.05 means that the window is made taller\/wider (or shorter\/thinner) in 5% increments.", "parameters" : [ ] @@ -110,26 +142,24 @@ "stripped_doc" : [ ], + "desc" : "With this Spoon you will be able to move the window in halves and in corners using your keyboard and mainly using arrows. You would also be able to resize them by thirds, quarters, or halves.", "Deprecated" : [ ], "type" : "Module", - "desc" : "With this Spoon you will be able to move the window in halves and in", "Constructor" : [ ], - "Field" : [ - - ], + "doc" : "With this Spoon you will be able to move the window in halves and in corners using your keyboard and mainly using arrows. You would also be able to resize them by thirds, quarters, or halves. \nOfficial homepage for more info and documentation:\n[https:\/\/github.com\/miromannino\/miro-windows-manager](https:\/\/github.com\/miromannino\/miro-windows-manager)\n\nNOTE: This Spoon sets `hs.grid` globals with `hs.grid.setGrid()`, `hs.grid.MARGINX`, and `hs.grid.MARGINY`.\nChanging MiroWindowsManager.GRID will change these globals.\n\nDownload:\nhttps:\/\/github.com\/miromannino\/miro-windows-manager\/raw\/master\/MiroWindowsManager.spoon.zip", "Method" : [ { - "def" : "MiroWindowsManager:move(side)", + "doc" : "Move the frontmost window up, down, left, right. \n\nParameters:\n * side - 'up', 'down', 'left', or 'right'\n\nReturns:\n * The MiroWindowsManager object", "stripped_doc" : [ "Move the frontmost window up, down, left, right. ", "" ], - "desc" : "Move the frontmost window up, down, left, right.", - "doc" : "Move the frontmost window up, down, left, right. \n\nParameters:\n * side - 'up', 'down', 'left', or 'right'\n\nReturns:\n * The MiroWindowsManager object", + "def" : "MiroWindowsManager:move(side)", + "name" : "move", "notes" : [ ], @@ -138,43 +168,65 @@ "returns" : [ " * The MiroWindowsManager object" ], - "name" : "move", + "desc" : "Move the frontmost window up, down, left, right.", "parameters" : [ " * side - 'up', 'down', 'left', or 'right'", "" ] }, { - "def" : "MiroWindowsManager:growFully(growth)", + "doc" : "Resize the frontmost window taller, shorter, wider, or thinner.\n\nParameters:\n * growth - 'taller', 'shorter', 'wider', or 'thinner'\n\nReturns:\n * The MiroWindowsManager object", "stripped_doc" : [ - "Grow the frontmost window to full width \/ height taller, wider. ", + "Resize the frontmost window taller, shorter, wider, or thinner.", "" ], - "desc" : "Grow the frontmost window to full width \/ height taller, wider.", - "doc" : "Grow the frontmost window to full width \/ height taller, wider. \n\nParameters:\n * growth - 'taller', or 'wider'\n\nReturns:\n * The MiroWindowsManager object", + "def" : "MiroWindowsManager:resize(growth)", + "name" : "resize", "notes" : [ ], - "signature" : "MiroWindowsManager:growFully(growth)", + "signature" : "MiroWindowsManager:resize(growth)", "type" : "Method", "returns" : [ " * The MiroWindowsManager object" ], + "desc" : "Resize the frontmost window taller, shorter, wider, or thinner.", + "parameters" : [ + " * growth - 'taller', 'shorter', 'wider', or 'thinner'", + "" + ] + }, + { + "doc" : "Grow the frontmost window to full width \/ height.\n\nParameters:\n * dimension - 'h', or 'w'\n\nReturns:\n * The MiroWindowsManager object", + "stripped_doc" : [ + "Grow the frontmost window to full width \/ height.", + "" + ], + "def" : "MiroWindowsManager:growFully(growth)", "name" : "growFully", + "notes" : [ + + ], + "signature" : "MiroWindowsManager:growFully(growth)", + "type" : "Method", + "returns" : [ + " * The MiroWindowsManager object" + ], + "desc" : "Grow the frontmost window to full width \/ height.", "parameters" : [ - " * growth - 'taller', or 'wider'", + " * dimension - 'h', or 'w'", "" ] }, { - "def" : "MiroWindowsManager:go(move)", + "doc" : "Move to screen edge, or cycle to next horizontal or vertical size if already there. \nTap both directions to go full width \/ height. \n\nParameters:\n * move - 'up', 'down', 'left', or 'right'\n\nReturns:\n * The MiroWindowsManager object", "stripped_doc" : [ "Move to screen edge, or cycle to next horizontal or vertical size if already there. ", "Tap both directions to go full width \/ height. ", "" ], - "desc" : "Move to screen edge, or cycle to next horizontal or vertical size if already there.", - "doc" : "Move to screen edge, or cycle to next horizontal or vertical size if already there. \nTap both directions to go full width \/ height. \n\nParameters:\n * move - 'up', 'down', 'left', 'right'\n\nReturns:\n * The MiroWindowsManager object", + "def" : "MiroWindowsManager:go(move)", + "name" : "go", "notes" : [ ], @@ -183,20 +235,20 @@ "returns" : [ " * The MiroWindowsManager object" ], - "name" : "go", + "desc" : "Move to screen edge, or cycle to next horizontal or vertical size if already there.", "parameters" : [ - " * move - 'up', 'down', 'left', 'right'", + " * move - 'up', 'down', 'left', or 'right'", "" ] }, { - "def" : "MiroWindowsManager:fullscreen()", + "doc" : "Fullscreen, or cycle to next fullscreen option\n\nParameters:\n * None.\n\nReturns:\n * The MiroWindowsManager object", "stripped_doc" : [ "Fullscreen, or cycle to next fullscreen option", "" ], - "desc" : "Fullscreen, or cycle to next fullscreen option", - "doc" : "Fullscreen, or cycle to next fullscreen option\n\nParameters:\n * None.\n\nReturns:\n * The MiroWindowsManager object", + "def" : "MiroWindowsManager:fullscreen()", + "name" : "fullscreen", "notes" : [ ], @@ -205,20 +257,20 @@ "returns" : [ " * The MiroWindowsManager object" ], - "name" : "fullscreen", + "desc" : "Fullscreen, or cycle to next fullscreen option", "parameters" : [ " * None.", "" ] }, { - "def" : "MiroWindowsManager:center()", + "doc" : "Center\n\nParameters:\n * None.\n\nReturns:\n * The MiroWindowsManager object", "stripped_doc" : [ "Center", "" ], - "desc" : "Center", - "doc" : "Center\n\nParameters:\n * None.\n\nReturns:\n * The MiroWindowsManager object", + "def" : "MiroWindowsManager:center()", + "name" : "center", "notes" : [ ], @@ -227,20 +279,20 @@ "returns" : [ " * The MiroWindowsManager object" ], - "name" : "center", + "desc" : "Center", "parameters" : [ " * None.", "" ] }, { - "def" : "MiroWindowsManager:bindHotkeys()", + "doc" : "Binds hotkeys for Miro's Windows Manager\n\nParameters:\n * mapping - A table containing hotkey details for the following items:\n * left: for the left action (usually `{hyper, \"left\"}`)\n * right: for the right action (usually `{hyper, \"right\"}`)\n * up: for the up action (usually {hyper, \"up\"})\n * down: for the down action (usually `{hyper, \"down\"}`)\n * fullscreen: for the full-screen action (e.g. `{hyper, \"f\"}`)\n * center: for the center action (e.g. `{hyper, \"c\"}`)\n * move: for the move action (e.g. `{hyper, \"v\"}`). The move action is active as soon as the hotkey is pressed. While active the left, right, up or down keys can be used (these are configured by the actions above). \n * resize: for the resize action (e.g. `{hyper, \"d\"}`). The resize action is active as soon as the hotkey is pressed. While active the left, right, up or down keys can be used (these are configured by the actions above).\n\nA configuration example:\n``` lua\nlocal hyper = {\"ctrl\", \"alt\", \"cmd\"}\nspoon.MiroWindowsManager:bindHotkeys({\n up = {hyper, \"up\"},\n down = {hyper, \"down\"},\n left = {hyper, \"left\"},\n right = {hyper, \"right\"},\n fullscreen = {hyper, \"f\"},\n center = {hyper, \"c\"},\n move = {hyper, \"v\"},\n resize = {hyper, \"d\" }\n})\n```\n\nIn this example ctrl+alt+cmd+up will perform the 'up' action.\nPressing ctrl+alt+cmd+c the window will be centered.\nPressing ctrl+alt+cmd+f the window will be maximized.\nKeeping ctrl+alt+cmd+v pressed you can move the window using the arrow keys up, down, left, and right.\nKeeping ctrl+alt+cmd+d pressed you can resize the window using the arrow keys up, down, left, and right.", "stripped_doc" : [ "Binds hotkeys for Miro's Windows Manager", "" ], - "desc" : "Binds hotkeys for Miro's Windows Manager", - "doc" : "Binds hotkeys for Miro's Windows Manager\n\nParameters:\n * mapping - A table containing hotkey details for the following items:\n * left: for the left action (usually `{hyper, \"left\"}`)\n * right: for the right action (usually `{hyper, \"right\"}`)\n * up: for the up action (usually {hyper, \"up\"})\n * down: for the down action (usually `{hyper, \"down\"}`)\n * fullscreen: for the full-screen action (e.g. `{hyper, \"f\"}`)\n\nA configuration example can be:\n``` lua\nlocal mods = {\"ctrl\", \"alt\", \"cmd\"}\nspoon.MiroWindowsManager:bindHotkeys({\n up = {mods, \"up\"},\n down = {mods, \"down\"},\n left = {mods, \"left\"},\n right = {mods, \"right\"},\n fullscreen = {mods, \"f\"},\n center = {mods, \"c\"},\n move = {mods, \"v\"},\n resize = {mods, \"d\"}\n})\n```", + "def" : "MiroWindowsManager:bindHotkeys()", + "name" : "bindHotkeys", "notes" : [ ], @@ -249,7 +301,7 @@ "returns" : [ ], - "name" : "bindHotkeys", + "desc" : "Binds hotkeys for Miro's Windows Manager", "parameters" : [ " * mapping - A table containing hotkey details for the following items:", " * left: for the left action (usually `{hyper, \"left\"}`)", @@ -257,30 +309,39 @@ " * up: for the up action (usually {hyper, \"up\"})", " * down: for the down action (usually `{hyper, \"down\"}`)", " * fullscreen: for the full-screen action (e.g. `{hyper, \"f\"}`)", + " * center: for the center action (e.g. `{hyper, \"c\"}`)", + " * move: for the move action (e.g. `{hyper, \"v\"}`). The move action is active as soon as the hotkey is pressed. While active the left, right, up or down keys can be used (these are configured by the actions above). ", + " * resize: for the resize action (e.g. `{hyper, \"d\"}`). The resize action is active as soon as the hotkey is pressed. While active the left, right, up or down keys can be used (these are configured by the actions above).", "", - "A configuration example can be:", + "A configuration example:", "``` lua", - "local mods = {\"ctrl\", \"alt\", \"cmd\"}", + "local hyper = {\"ctrl\", \"alt\", \"cmd\"}", "spoon.MiroWindowsManager:bindHotkeys({", - " up = {mods, \"up\"},", - " down = {mods, \"down\"},", - " left = {mods, \"left\"},", - " right = {mods, \"right\"},", - " fullscreen = {mods, \"f\"},", - " center = {mods, \"c\"},", - " move = {mods, \"v\"},", - " resize = {mods, \"d\"}", + " up = {hyper, \"up\"},", + " down = {hyper, \"down\"},", + " left = {hyper, \"left\"},", + " right = {hyper, \"right\"},", + " fullscreen = {hyper, \"f\"},", + " center = {hyper, \"c\"},", + " move = {hyper, \"v\"},", + " resize = {hyper, \"d\" }", "})", - "```" + "```", + "", + "In this example ctrl+alt+cmd+up will perform the 'up' action.", + "Pressing ctrl+alt+cmd+c the window will be centered.", + "Pressing ctrl+alt+cmd+f the window will be maximized.", + "Keeping ctrl+alt+cmd+v pressed you can move the window using the arrow keys up, down, left, and right.", + "Keeping ctrl+alt+cmd+d pressed you can resize the window using the arrow keys up, down, left, and right." ] }, { - "def" : "MiroWindowsManager:init()", + "doc" : "Currently does nothing (implemented so that treating this Spoon like others won't cause errors).", "stripped_doc" : [ - + "Currently does nothing (implemented so that treating this Spoon like others won't cause errors)." ], - "desc" : "UNKNOWN DESC", - "doc" : "", + "def" : "MiroWindowsManager:init()", + "name" : "init", "notes" : [ ], @@ -289,7 +350,7 @@ "returns" : [ ], - "name" : "init", + "desc" : "Currently does nothing (implemented so that treating this Spoon like others won't cause errors).", "parameters" : [ ] @@ -298,18 +359,15 @@ "Command" : [ ], - "doc" : "With this Spoon you will be able to move the window in halves and in\ncorners using your keyboard and mainly using arrows. You would also be able\nto resize them by thirds, quarters, or halves. \nOfficial homepage for more info and documentation:\n[https:\/\/github.com\/miromannino\/miro-windows-manager](https:\/\/github.com\/miromannino\/miro-windows-manager)\n\nNOTE: This Spoon sets `hs.grid` globals with `hs.grid.setGrid()`,\n`hs.grid.MARGINX`, and `hs.grid.MARGINY`. Changing MiroWindowsManager.GRID\nwill change these globals.\n\nDownload:\nhttps:\/\/github.com\/miromannino\/miro-windows-manager\/raw\/master\/MiroWindowsManager.spoon.zip", "items" : [ { - "def" : "MiroWindowsManager.GRID", + "doc" : "The screen's grid size. \nMake sure that the numbers in MiroWindowsManager.sizes and MiroWindowsManager.fullScreenSizes divide h and w to give integers.", "stripped_doc" : [ "The screen's grid size. ", - "Ensuring that the numbers in MiroWindowsManager.sizes and", - "MiroWindowsManager.fullScreenSizes divide these numbers to give integers", - "makes everything work better." + "Make sure that the numbers in MiroWindowsManager.sizes and MiroWindowsManager.fullScreenSizes divide h and w to give integers." ], - "desc" : "The screen's grid size.", - "doc" : "The screen's grid size. \nEnsuring that the numbers in MiroWindowsManager.sizes and\nMiroWindowsManager.fullScreenSizes divide these numbers to give integers\nmakes everything work better.", + "def" : "MiroWindowsManager.GRID", + "name" : "GRID", "notes" : [ ], @@ -318,25 +376,22 @@ "returns" : [ ], - "name" : "GRID", + "desc" : "The screen's grid size.", "parameters" : [ ] }, { - "def" : "MiroWindowsManager.fullScreenSizes", + "doc" : "The sizes that the window can have in full-screen. \nThe sizes are expressed as dividend of the entire screen's size. \nFor example `{1, 4\/3, 2}` means that it can be 1\/1 (hence full screen), 3\/4 and 1\/2 of the total screen's size. \nMake sure that these numbers divide both dimensions of MiroWindowsManager.GRID to give integers.\nUse 'c' for the original size and shape of the window before starting to move it.", "stripped_doc" : [ "The sizes that the window can have in full-screen. ", "The sizes are expressed as dividend of the entire screen's size. ", - "For example `{1, 4\/3, 2}` means that it can be 1\/1 (hence full screen), 3\/4", - "and 1\/2 of the total screen's size. ", - "Ensuring that these numbers all divide both dimensions of", - "MiroWindowsManager.GRID to give integers makes everything work better. ", - "Special: Use 'c' for the original size and shape of the window before", - "starting to move it, but centered." + "For example `{1, 4\/3, 2}` means that it can be 1\/1 (hence full screen), 3\/4 and 1\/2 of the total screen's size. ", + "Make sure that these numbers divide both dimensions of MiroWindowsManager.GRID to give integers.", + "Use 'c' for the original size and shape of the window before starting to move it." ], - "desc" : "The sizes that the window can have in full-screen.", - "doc" : "The sizes that the window can have in full-screen. \nThe sizes are expressed as dividend of the entire screen's size. \nFor example `{1, 4\/3, 2}` means that it can be 1\/1 (hence full screen), 3\/4\nand 1\/2 of the total screen's size. \nEnsuring that these numbers all divide both dimensions of\nMiroWindowsManager.GRID to give integers makes everything work better. \nSpecial: Use 'c' for the original size and shape of the window before\nstarting to move it, but centered.", + "def" : "MiroWindowsManager.fullScreenSizes", + "name" : "fullScreenSizes", "notes" : [ ], @@ -345,44 +400,61 @@ "returns" : [ ], - "name" : "fullScreenSizes", + "desc" : "The sizes that the window can have in full-screen.", "parameters" : [ ] }, { - "def" : "MiroWindowsManager.moveToNextScreen", + "doc" : "Boolean value to decide whether or not to move the window on the next screen if the window is moved the screen edge.", "stripped_doc" : [ - "Boolean value to decide wether or not to move the window on the next screen", - "if the window is moved the screen edge." + "Boolean value to decide whether or not to move the window on the next screen if the window is moved the screen edge." ], - "desc" : "Boolean value to decide wether or not to move the window on the next screen", - "doc" : "Boolean value to decide wether or not to move the window on the next screen\nif the window is moved the screen edge.", + "def" : "MiroWindowsManager.pushToNextScreen", + "name" : "pushToNextScreen", "notes" : [ ], - "signature" : "MiroWindowsManager.moveToNextScreen", + "signature" : "MiroWindowsManager.pushToNextScreen", "type" : "Variable", "returns" : [ ], - "name" : "moveToNextScreen", + "desc" : "Boolean value to decide whether or not to move the window on the next screen if the window is moved the screen edge.", "parameters" : [ ] }, { - "def" : "MiroWindowsManager.sizes", + "doc" : "Float value to decide the rate at which to resize windows. A value of 1.05 means that the window is made taller\/wider (or shorter\/thinner) in 5% increments.", + "stripped_doc" : [ + "Float value to decide the rate at which to resize windows. A value of 1.05 means that the window is made taller\/wider (or shorter\/thinner) in 5% increments." + ], + "def" : "MiroWindowsManager.resizeRate", + "name" : "resizeRate", + "notes" : [ + + ], + "signature" : "MiroWindowsManager.resizeRate", + "type" : "Variable", + "returns" : [ + + ], + "desc" : "Float value to decide the rate at which to resize windows. A value of 1.05 means that the window is made taller\/wider (or shorter\/thinner) in 5% increments.", + "parameters" : [ + + ] + }, + { + "doc" : "The sizes that the window can have. \nThe sizes are expressed as dividend of the entire screen's size. \nFor example `{2, 3, 3\/2}` means that it can be 1\/2, 1\/3 and 2\/3 of the total screen's size. \nMake sure that these numbers divide both dimensions of MiroWindowsManager.GRID to give integers.", "stripped_doc" : [ "The sizes that the window can have. ", "The sizes are expressed as dividend of the entire screen's size. ", - "For example `{2, 3, 3\/2}` means that it can be 1\/2, 1\/3 and 2\/3 of the total", - "screen's size. ", - "Ensuring that these numbers all divide both dimensions of", - "MiroWindowsManager.GRID to give integers makes everything work better." + "For example `{2, 3, 3\/2}` means that it can be 1\/2, 1\/3 and 2\/3 of the total screen's size. ", + "Make sure that these numbers divide both dimensions of MiroWindowsManager.GRID to give integers." ], - "desc" : "The sizes that the window can have.", - "doc" : "The sizes that the window can have. \nThe sizes are expressed as dividend of the entire screen's size. \nFor example `{2, 3, 3\/2}` means that it can be 1\/2, 1\/3 and 2\/3 of the total\nscreen's size. \nEnsuring that these numbers all divide both dimensions of\nMiroWindowsManager.GRID to give integers makes everything work better.", + "def" : "MiroWindowsManager.sizes", + "name" : "sizes", "notes" : [ ], @@ -391,19 +463,39 @@ "returns" : [ ], - "name" : "sizes", + "desc" : "The sizes that the window can have.", "parameters" : [ ] }, { - "def" : "MiroWindowsManager:bindHotkeys()", + "doc" : "Boolean value to decide whether or not to stick the window to the edge of the screen if shrinking it would detatch it from the screen edge.", + "stripped_doc" : [ + "Boolean value to decide whether or not to stick the window to the edge of the screen if shrinking it would detatch it from the screen edge." + ], + "def" : "MiroWindowsManager.stickySides", + "name" : "stickySides", + "notes" : [ + + ], + "signature" : "MiroWindowsManager.stickySides", + "type" : "Variable", + "returns" : [ + + ], + "desc" : "Boolean value to decide whether or not to stick the window to the edge of the screen if shrinking it would detatch it from the screen edge.", + "parameters" : [ + + ] + }, + { + "doc" : "Binds hotkeys for Miro's Windows Manager\n\nParameters:\n * mapping - A table containing hotkey details for the following items:\n * left: for the left action (usually `{hyper, \"left\"}`)\n * right: for the right action (usually `{hyper, \"right\"}`)\n * up: for the up action (usually {hyper, \"up\"})\n * down: for the down action (usually `{hyper, \"down\"}`)\n * fullscreen: for the full-screen action (e.g. `{hyper, \"f\"}`)\n * center: for the center action (e.g. `{hyper, \"c\"}`)\n * move: for the move action (e.g. `{hyper, \"v\"}`). The move action is active as soon as the hotkey is pressed. While active the left, right, up or down keys can be used (these are configured by the actions above). \n * resize: for the resize action (e.g. `{hyper, \"d\"}`). The resize action is active as soon as the hotkey is pressed. While active the left, right, up or down keys can be used (these are configured by the actions above).\n\nA configuration example:\n``` lua\nlocal hyper = {\"ctrl\", \"alt\", \"cmd\"}\nspoon.MiroWindowsManager:bindHotkeys({\n up = {hyper, \"up\"},\n down = {hyper, \"down\"},\n left = {hyper, \"left\"},\n right = {hyper, \"right\"},\n fullscreen = {hyper, \"f\"},\n center = {hyper, \"c\"},\n move = {hyper, \"v\"},\n resize = {hyper, \"d\" }\n})\n```\n\nIn this example ctrl+alt+cmd+up will perform the 'up' action.\nPressing ctrl+alt+cmd+c the window will be centered.\nPressing ctrl+alt+cmd+f the window will be maximized.\nKeeping ctrl+alt+cmd+v pressed you can move the window using the arrow keys up, down, left, and right.\nKeeping ctrl+alt+cmd+d pressed you can resize the window using the arrow keys up, down, left, and right.", "stripped_doc" : [ "Binds hotkeys for Miro's Windows Manager", "" ], - "desc" : "Binds hotkeys for Miro's Windows Manager", - "doc" : "Binds hotkeys for Miro's Windows Manager\n\nParameters:\n * mapping - A table containing hotkey details for the following items:\n * left: for the left action (usually `{hyper, \"left\"}`)\n * right: for the right action (usually `{hyper, \"right\"}`)\n * up: for the up action (usually {hyper, \"up\"})\n * down: for the down action (usually `{hyper, \"down\"}`)\n * fullscreen: for the full-screen action (e.g. `{hyper, \"f\"}`)\n\nA configuration example can be:\n``` lua\nlocal mods = {\"ctrl\", \"alt\", \"cmd\"}\nspoon.MiroWindowsManager:bindHotkeys({\n up = {mods, \"up\"},\n down = {mods, \"down\"},\n left = {mods, \"left\"},\n right = {mods, \"right\"},\n fullscreen = {mods, \"f\"},\n center = {mods, \"c\"},\n move = {mods, \"v\"},\n resize = {mods, \"d\"}\n})\n```", + "def" : "MiroWindowsManager:bindHotkeys()", + "name" : "bindHotkeys", "notes" : [ ], @@ -412,7 +504,7 @@ "returns" : [ ], - "name" : "bindHotkeys", + "desc" : "Binds hotkeys for Miro's Windows Manager", "parameters" : [ " * mapping - A table containing hotkey details for the following items:", " * left: for the left action (usually `{hyper, \"left\"}`)", @@ -420,31 +512,40 @@ " * up: for the up action (usually {hyper, \"up\"})", " * down: for the down action (usually `{hyper, \"down\"}`)", " * fullscreen: for the full-screen action (e.g. `{hyper, \"f\"}`)", + " * center: for the center action (e.g. `{hyper, \"c\"}`)", + " * move: for the move action (e.g. `{hyper, \"v\"}`). The move action is active as soon as the hotkey is pressed. While active the left, right, up or down keys can be used (these are configured by the actions above). ", + " * resize: for the resize action (e.g. `{hyper, \"d\"}`). The resize action is active as soon as the hotkey is pressed. While active the left, right, up or down keys can be used (these are configured by the actions above).", "", - "A configuration example can be:", + "A configuration example:", "``` lua", - "local mods = {\"ctrl\", \"alt\", \"cmd\"}", + "local hyper = {\"ctrl\", \"alt\", \"cmd\"}", "spoon.MiroWindowsManager:bindHotkeys({", - " up = {mods, \"up\"},", - " down = {mods, \"down\"},", - " left = {mods, \"left\"},", - " right = {mods, \"right\"},", - " fullscreen = {mods, \"f\"},", - " center = {mods, \"c\"},", - " move = {mods, \"v\"},", - " resize = {mods, \"d\"}", + " up = {hyper, \"up\"},", + " down = {hyper, \"down\"},", + " left = {hyper, \"left\"},", + " right = {hyper, \"right\"},", + " fullscreen = {hyper, \"f\"},", + " center = {hyper, \"c\"},", + " move = {hyper, \"v\"},", + " resize = {hyper, \"d\" }", "})", - "```" + "```", + "", + "In this example ctrl+alt+cmd+up will perform the 'up' action.", + "Pressing ctrl+alt+cmd+c the window will be centered.", + "Pressing ctrl+alt+cmd+f the window will be maximized.", + "Keeping ctrl+alt+cmd+v pressed you can move the window using the arrow keys up, down, left, and right.", + "Keeping ctrl+alt+cmd+d pressed you can resize the window using the arrow keys up, down, left, and right." ] }, { - "def" : "MiroWindowsManager:center()", + "doc" : "Center\n\nParameters:\n * None.\n\nReturns:\n * The MiroWindowsManager object", "stripped_doc" : [ "Center", "" ], - "desc" : "Center", - "doc" : "Center\n\nParameters:\n * None.\n\nReturns:\n * The MiroWindowsManager object", + "def" : "MiroWindowsManager:center()", + "name" : "center", "notes" : [ ], @@ -453,20 +554,20 @@ "returns" : [ " * The MiroWindowsManager object" ], - "name" : "center", + "desc" : "Center", "parameters" : [ " * None.", "" ] }, { - "def" : "MiroWindowsManager:fullscreen()", + "doc" : "Fullscreen, or cycle to next fullscreen option\n\nParameters:\n * None.\n\nReturns:\n * The MiroWindowsManager object", "stripped_doc" : [ "Fullscreen, or cycle to next fullscreen option", "" ], - "desc" : "Fullscreen, or cycle to next fullscreen option", - "doc" : "Fullscreen, or cycle to next fullscreen option\n\nParameters:\n * None.\n\nReturns:\n * The MiroWindowsManager object", + "def" : "MiroWindowsManager:fullscreen()", + "name" : "fullscreen", "notes" : [ ], @@ -475,21 +576,21 @@ "returns" : [ " * The MiroWindowsManager object" ], - "name" : "fullscreen", + "desc" : "Fullscreen, or cycle to next fullscreen option", "parameters" : [ " * None.", "" ] }, { - "def" : "MiroWindowsManager:go(move)", + "doc" : "Move to screen edge, or cycle to next horizontal or vertical size if already there. \nTap both directions to go full width \/ height. \n\nParameters:\n * move - 'up', 'down', 'left', or 'right'\n\nReturns:\n * The MiroWindowsManager object", "stripped_doc" : [ "Move to screen edge, or cycle to next horizontal or vertical size if already there. ", "Tap both directions to go full width \/ height. ", "" ], - "desc" : "Move to screen edge, or cycle to next horizontal or vertical size if already there.", - "doc" : "Move to screen edge, or cycle to next horizontal or vertical size if already there. \nTap both directions to go full width \/ height. \n\nParameters:\n * move - 'up', 'down', 'left', 'right'\n\nReturns:\n * The MiroWindowsManager object", + "def" : "MiroWindowsManager:go(move)", + "name" : "go", "notes" : [ ], @@ -498,20 +599,20 @@ "returns" : [ " * The MiroWindowsManager object" ], - "name" : "go", + "desc" : "Move to screen edge, or cycle to next horizontal or vertical size if already there.", "parameters" : [ - " * move - 'up', 'down', 'left', 'right'", + " * move - 'up', 'down', 'left', or 'right'", "" ] }, { - "def" : "MiroWindowsManager:growFully(growth)", + "doc" : "Grow the frontmost window to full width \/ height.\n\nParameters:\n * dimension - 'h', or 'w'\n\nReturns:\n * The MiroWindowsManager object", "stripped_doc" : [ - "Grow the frontmost window to full width \/ height taller, wider. ", + "Grow the frontmost window to full width \/ height.", "" ], - "desc" : "Grow the frontmost window to full width \/ height taller, wider.", - "doc" : "Grow the frontmost window to full width \/ height taller, wider. \n\nParameters:\n * growth - 'taller', or 'wider'\n\nReturns:\n * The MiroWindowsManager object", + "def" : "MiroWindowsManager:growFully(growth)", + "name" : "growFully", "notes" : [ ], @@ -520,19 +621,19 @@ "returns" : [ " * The MiroWindowsManager object" ], - "name" : "growFully", + "desc" : "Grow the frontmost window to full width \/ height.", "parameters" : [ - " * growth - 'taller', or 'wider'", + " * dimension - 'h', or 'w'", "" ] }, { - "def" : "MiroWindowsManager:init()", + "doc" : "Currently does nothing (implemented so that treating this Spoon like others won't cause errors).", "stripped_doc" : [ - + "Currently does nothing (implemented so that treating this Spoon like others won't cause errors)." ], - "desc" : "UNKNOWN DESC", - "doc" : "", + "def" : "MiroWindowsManager:init()", + "name" : "init", "notes" : [ ], @@ -541,19 +642,19 @@ "returns" : [ ], - "name" : "init", + "desc" : "Currently does nothing (implemented so that treating this Spoon like others won't cause errors).", "parameters" : [ ] }, { - "def" : "MiroWindowsManager:move(side)", + "doc" : "Move the frontmost window up, down, left, right. \n\nParameters:\n * side - 'up', 'down', 'left', or 'right'\n\nReturns:\n * The MiroWindowsManager object", "stripped_doc" : [ "Move the frontmost window up, down, left, right. ", "" ], - "desc" : "Move the frontmost window up, down, left, right.", - "doc" : "Move the frontmost window up, down, left, right. \n\nParameters:\n * side - 'up', 'down', 'left', or 'right'\n\nReturns:\n * The MiroWindowsManager object", + "def" : "MiroWindowsManager:move(side)", + "name" : "move", "notes" : [ ], @@ -562,12 +663,37 @@ "returns" : [ " * The MiroWindowsManager object" ], - "name" : "move", + "desc" : "Move the frontmost window up, down, left, right.", "parameters" : [ " * side - 'up', 'down', 'left', or 'right'", "" ] + }, + { + "doc" : "Resize the frontmost window taller, shorter, wider, or thinner.\n\nParameters:\n * growth - 'taller', 'shorter', 'wider', or 'thinner'\n\nReturns:\n * The MiroWindowsManager object", + "stripped_doc" : [ + "Resize the frontmost window taller, shorter, wider, or thinner.", + "" + ], + "def" : "MiroWindowsManager:resize(growth)", + "name" : "resize", + "notes" : [ + + ], + "signature" : "MiroWindowsManager:resize(growth)", + "type" : "Method", + "returns" : [ + " * The MiroWindowsManager object" + ], + "desc" : "Resize the frontmost window taller, shorter, wider, or thinner.", + "parameters" : [ + " * growth - 'taller', 'shorter', 'wider', or 'thinner'", + "" + ] } + ], + "Field" : [ + ], "name" : "MiroWindowsManager" } diff --git a/MiroWindowsManager.spoon/init.lua b/MiroWindowsManager.spoon/init.lua index d3fe87a..c99670f 100644 --- a/MiroWindowsManager.spoon/init.lua +++ b/MiroWindowsManager.spoon/init.lua @@ -17,21 +17,19 @@ --- === MiroWindowsManager === --- ---- With this Spoon you will be able to move the window in halves and in ---- corners using your keyboard and mainly using arrows. You would also be able ---- to resize them by thirds, quarters, or halves. +--- With this Spoon you will be able to move the window in halves and in corners using your keyboard and mainly using arrows. You would also be able to resize them by thirds, quarters, or halves. --- Official homepage for more info and documentation: --- [https://github.com/miromannino/miro-windows-manager](https://github.com/miromannino/miro-windows-manager) --- ---- NOTE: This Spoon sets `hs.grid` globals with `hs.grid.setGrid()`, ---- `hs.grid.MARGINX`, and `hs.grid.MARGINY`. Changing MiroWindowsManager.GRID ---- will change these globals. +--- NOTE: This Spoon sets `hs.grid` globals with `hs.grid.setGrid()`, `hs.grid.MARGINX`, and `hs.grid.MARGINY`. +--- Changing MiroWindowsManager.GRID will change these globals. --- --- Download: --- https://github.com/miromannino/miro-windows-manager/raw/master/MiroWindowsManager.spoon.zip --- -- ## TODO +-- sticky sides option when shrinking windows -- different sizes lists for specific apps local obj={} @@ -63,24 +61,20 @@ obj.sizes = {2, 3, 3/2} --- Variable --- The sizes that the window can have in full-screen. --- The sizes are expressed as dividend of the entire screen's size. ---- For example `{1, 4/3, 2}` means that it can be 1/1 (hence full screen), 3/4 ---- and 1/2 of the total screen's size. +--- For example `{1, 4/3, 2}` means that it can be 1/1 (hence full screen), 3/4 and 1/2 of the total screen's size. --- Make sure that these numbers divide both dimensions of MiroWindowsManager.GRID to give integers. --- Use 'c' for the original size and shape of the window before starting to move it. obj.fullScreenSizes = {1, 2, 'c'} --- Comment: Lots of work here to save users a little work. Previous versions --- required users to call MiroWindowsManager:start() every time they changed --- GRID. The metatable work here watches for those changes and does the work --- :start() would have done. +-- Comment: Lots of work here to save users a little work. Previous versions required users to call +-- MiroWindowsManager:start() every time they changed GRID. The metatable work here watches for those changes and does the work :start() would have done. package.path = package.path..";Spoons/".. ... ..".spoon/?.lua" require('extend_GRID').extend(obj, logger) --- MiroWindowsManager.GRID --- Variable --- The screen's grid size. ---- Ensuring that the numbers in MiroWindowsManager.sizes and ---- Make sure that the numbers in MiroWindowsManager.fullScreenSizes divide h and w to give integers. +--- Make sure that the numbers in MiroWindowsManager.sizes and MiroWindowsManager.fullScreenSizes divide h and w to give integers. obj.GRID = { w = 24, h = 24, margins = hs.geometry.point(0,0) } function obj.GRID.cell() return hs.geometry(obj.GRID.margins, hs.geometry.size(obj.GRID.w, obj.GRID.h)) @@ -89,15 +83,19 @@ end --- MiroWindowsManager.pushToNextScreen --- Variable ---- Boolean value to decide wether or not to move the window on the next screen ---- if the window is moved the screen edge. +--- Boolean value to decide whether or not to move the window on the next screen if the window is moved the screen edge. obj.pushToNextScreen = false +--- MiroWindowsManager.stickySides +--- Variable +--- Boolean value to decide whether or not to stick the window to the edge of the screen if shrinking it would detatch it from the screen edge. +obj.stickySides = false + + --- MiroWindowsManager.resizeRate --- Variable ---- Float value to decide the the rate to resize windows. With a value of 1.05 it means that ---- everytime the window is made taller/wider by 5% more (or shorter/thinner by 5% less) +--- Float value to decide the rate at which to resize windows. A value of 1.05 means that the window is made taller/wider (or shorter/thinner) in 5% increments. obj.resizeRate = 1.05 -- ## Internal @@ -117,46 +115,26 @@ obj._growthsRel = { thinner = { opp = 'wider', dim = 'w', pos = 'x', growthSign = -1 }, } --- The keys used to move, generally the arrow keys, but they could also be WASD or something else +-- The keys used to move, generally the arrow keys, but they could also be WASD or something else. obj._movingKeys = { } for _,move in ipairs(obj._directions) do obj._movingKeys[move] = move end obj._originalPositionStore = { fullscreen = {} } +setmetatable(obj._originalPositionStore.fullscreen, {__mode = 'kv'}) -- weak table, so it doesn't become a memory hog -obj._moveModeKeyWatcher = nil -obj._resizeModeKeyWatcher = nil - -obj._pressed = {} -obj._pressTimers = {} obj._lastSeq = {} obj._lastFullscreenSeq = nil -local function initPressed(move) - obj._pressed[move] = false - obj._pressTimers[move] = hs.timer.doAfter(1, function() obj._pressed[move] = false end) -end -hs.fnutils.each(obj._directions, initPressed) -local function registerPress(direction) - obj._pressed[direction] = true - obj._pressTimers[direction]:start() -end -local function cancelPress(direction) - obj._pressed[direction] = false - obj._pressTimers[direction]:stop() -end -local function currentlyPressed(direction) - return obj._pressed[direction] -end -- ### Utilities -function titleCase(str) +local function titleCase(str) return (str:gsub('^%l', string.upper)) end -function round(num) +local function round(num) if num >= 0 then return math.floor(num+.499999999) else @@ -164,20 +142,26 @@ function round(num) end end --- Accessor for functions on the frontmost window -function frontmostWindow() +-- Accessor for functions on the frontmost window. +local function frontmostWindow() return hs.window.frontmostWindow() end -function frontmostScreen() +local function frontmostScreen() return frontmostWindow():screen() end -function frontmostCell() +local function frontmostCell() local win = frontmostWindow() return hs.grid.get(win, win:screen()) end +-- Set window to cell +local function setPosition(cell) + local win = frontmostWindow() + hs.grid.set(win, cell, win:screen()) +end + -- ## Public --- MiroWindowsManager:move(side) @@ -191,90 +175,53 @@ end --- * The MiroWindowsManager object function obj:move(side) if self:currentlyBound(side) and not self.pushToNextScreen then - logger.i("`self.pushToNextScreen` == false so not moving to ".. side .." screen.") + logger.d("`self.pushToNextScreen` == false so not moving to ".. side .." screen.") else logger.i('Moving '.. side) + hs.grid['pushWindow'.. titleCase(side)](frontmostWindow()) end return self end -function obj:_moveModeOn() - logger.i("Move Mode on") - self._moveModeKeyWatcher = hs.eventtap.new({ hs.eventtap.event.types.keyDown }, function(ev) - local keyCode = ev:getKeyCode() - - if keyCode == hs.keycodes.map[self._movingKeys['left']] then - self:move('left') - return true - elseif keyCode == hs.keycodes.map[self._movingKeys['right']] then - self:move('right') - return true - elseif keyCode == hs.keycodes.map[self._movingKeys['down']] then - self:move('down') - return true - elseif keyCode == hs.keycodes.map[self._movingKeys['up']] then - self:move('up') - return true - else - return false - end - end):start() -end -function obj:_moveModeOff() - logger.i("Move Mode off"); - self._moveModeKeyWatcher:stop() -end --- MiroWindowsManager:resize(growth) --- Method ---- Resize the frontmost window taller, shorter, wider, thinner. +--- Resize the frontmost window taller, shorter, wider, or thinner. --- --- Parameters: ---- * growth - 'taller', 'shorter', 'wider', 'thinner' +--- * growth - 'taller', 'shorter', 'wider', or 'thinner' --- --- Returns: --- * The MiroWindowsManager object function obj:resize(growth) - logger.i('resize ' .. growth) + logger.i('Resizing '.. growth) local w = frontmostWindow() local fr = w:frame() - local growthDiff = fr[self._growthsRel[growth].dim] * (self.resizeRate - 1) - fr[self._growthsRel[growth].pos] = fr[self._growthsRel[growth].pos] - (self._growthsRel[growth].growthSign * growthDiff / 2) - fr[self._growthsRel[growth].dim] = fr[self._growthsRel[growth].dim] + (self._growthsRel[growth].growthSign * growthDiff) - - if fr['y'] < 0 then fr['y'] = 0 end - if fr['x'] < 0 then fr['x'] = 0 end + local growthDiff = fr[self._growthsRel[growth].dim] * (self.resizeRate - 1) + fr[self._growthsRel[growth].pos] = + fr[self._growthsRel[growth].pos] - (self._growthsRel[growth].growthSign * growthDiff / 2) + fr[self._growthsRel[growth].dim] = + fr[self._growthsRel[growth].dim] + (self._growthsRel[growth].growthSign * growthDiff) + + fr = fr:intersect(frontmostScreen():frame()) -- avoid sizing out of bounds + + if self.stickySides then + if growth == 'shorter' and self:currentlyBound('up') then + fr.y = 0 + elseif growth == 'shorter' and self:currentlyBound('down') then + fr.y = fr.y + growthDiff / 2 + elseif growth == 'thinner' and self:currentlyBound('left') then + fr.x = 0 + elseif growth == 'thinner' and self:currentlyBound('right') then + fr.x = fr.x + growthDiff / 2 + end + end w:setFrame(fr) return self end -function obj:_resizeModeOn() - logger.i("Resize Mode on") - self._resizeModeKeyWatcher = hs.eventtap.new({ hs.eventtap.event.types.keyDown }, function(ev) - local keyCode = ev:getKeyCode() - if keyCode == hs.keycodes.map[self._movingKeys['left']] then - self:resize('thinner') - return true - elseif keyCode == hs.keycodes.map[self._movingKeys['right']] then - self:resize('wider') - return true - elseif keyCode == hs.keycodes.map[self._movingKeys['down']] then - self:resize('shorter') - return true - elseif keyCode == hs.keycodes.map[self._movingKeys['up']] then - self:resize('taller') - return true - else - return false - end - end):start() -end -function obj:_resizeModeOff() - logger.i("Resize Mode off"); - self._resizeModeKeyWatcher:stop() -end --- MiroWindowsManager:growFully(growth) --- Method @@ -286,10 +233,12 @@ end --- Returns: --- * The MiroWindowsManager object function obj:growFully(dimension) + logger.i('Growing '.. dimension) + local cell = frontmostCell() cell[dimension == 'h' and 'y' or 'x'] = 0 cell[dimension] = self.GRID[dimension] - self._setPosition(cell) + setPosition(cell) return self end @@ -300,28 +249,20 @@ end --- Tap both directions to go full width / height. --- --- Parameters: ---- * move - 'up', 'down', 'left', 'right' +--- * move - 'up', 'down', 'left', or 'right' --- --- Returns: --- * The MiroWindowsManager object function obj:go(move) - registerPress(move) - if currentlyPressed(self._directionsRel[move].opp) then - -- if still keydown moving the in the opposite direction, go full width/height - logger.i("Maximising " .. self._directionsRel[move].dim .. " since " - .. self._directionsRel[move].opp .." still active.") - self:growFully(self._directionsRel[move].dim) -- full width/height - else - local cell = frontmostCell() - local seq = self:currentSeq(move) -- current sequence index or 0 if out of sequence + local cell = frontmostCell() + local seq = self:currentSeq(move) -- current sequence index or 0 if out of sequence - logger.i("We're at ".. move .." sequence ".. tostring(seq) .." (".. cell.string ..")") + logger.d("We're at ".. move .." sequence ".. tostring(seq) .." (".. cell.string ..")") - seq = seq % #self.sizes -- if at end of #self.sizes then wrap to 0 - logger.i("Updating seq to " .. tostring(seq + 1) .." (size: ".. tostring(self.sizes[seq + 1]) ..")") + seq = seq % #self.sizes -- if at end of #self.sizes then wrap to 0 + logger.d("Updating seq to " .. tostring(seq + 1) .." (size: ".. tostring(self.sizes[seq + 1]) ..")") - self:setToSeq(move, seq + 1) - end + self:setToSeq(move, seq + 1) return self end @@ -336,21 +277,23 @@ end --- * The MiroWindowsManager object function obj:fullscreen() local seq = self:currentFullscreenSeq() -- current sequence index or 0 if out of sequence - logger.i("We're at fullscreen sequence ".. tostring(seq) .." (".. frontmostCell().string ..")") + logger.d("We're at fullscreen sequence ".. tostring(seq) .." (".. frontmostCell().string ..")") if seq == 0 then if hs.fnutils.contains(self.fullScreenSizes, 'c') then - logger.i("Since we are at seq 0, storing current position to use it with 'c' for window " .. frontmostWindow():id()) + logger.d("Since we are at seq 0, storing current position to use it with 'c' for window " .. + frontmostWindow():id()) self._originalPositionStore['fullscreen'][frontmostWindow():id()] = frontmostCell() end end - seq = seq % #self.fullScreenSizes + 1 -- if seq = #self.fullScreenSizes then 0 so next seq = 1 (we cycle through sizes) - logger.i("Updating seq to " .. tostring(seq) .." (size: ".. tostring(self.fullScreenSizes[seq]) ..")") + -- if seq = #self.fullScreenSizes then 0 so next seq = 1 (we cycle through sizes) + seq = seq % #self.fullScreenSizes + 1 + logger.d("Updating seq to " .. tostring(seq) .." (size: ".. tostring(self.fullScreenSizes[seq]) ..")") if self.fullScreenSizes[seq] == 'c' then - logger.i("Seq is 'c' but we don't have a saved position, skip to the next one") - if not self._originalPositionStore['fullscreen'][frontmostWindow():id()] then + logger.d("Seq is 'c' but we don't have a saved position, skip to the next one") + if not self._originalPositionStore['fullscreen'][frontmostWindow():id()] then seq = seq % #self.fullScreenSizes + 1 end end @@ -370,9 +313,11 @@ end --- Returns: --- * The MiroWindowsManager object function obj:center() + logger.i('Centering') + local cell = frontmostCell() cell.center = self.GRID.cell().center - self._setPosition(cell) + setPosition(cell) return self end @@ -384,12 +329,11 @@ function obj:currentSeq(side) local width = frontmostCell()[dim] local relative_size = self.GRID[dim] / width - -- TODO local lastMatchedSeq = self._lastSeq[side] and -- we've recorded a last seq, and self.sizes[self._lastSeq[side]] and -- it's a valid index to sizes self._lastSeq[side] - local lastMatchedSeqMatchesFrontmost = + local lastMatchedSeqMatchesFrontmost = lastMatchedSeq and (self.sizes[lastMatchedSeq] == relative_size) -- cleanup @@ -422,7 +366,7 @@ function obj:setToSeq(move, seq) cell = self:snap_to_grid(cell) - self._setPosition(cell) + setPosition(cell) self._lastSeq[move] = seq return self end @@ -432,22 +376,21 @@ function obj:currentlyBound(side) local cell = frontmostCell() if side == 'up' then return cell.y == 0 - elseif side == 'down' then - return cell.y + cell.h == self.GRID.h - elseif side == 'left' then - return cell.x == 0 - elseif side == 'right' then - return cell.x + cell.w == self.GRID.w - end - end + elseif side == 'down' then + return cell.y + cell.h == self.GRID.h + elseif side == 'left' then + return cell.x == 0 + elseif side == 'right' then + return cell.x + cell.w == self.GRID.w + end +end -- ### Fullscreen methods -- Query whether window is centered function obj:currentlyCentered() local cell = frontmostCell() - return cell.w + 2 * cell.x == self.GRID.w and - cell.h + 2 * cell.y == self.GRID.h + return cell.w + 2 * cell.x == self.GRID.w and cell.h + 2 * cell.y == self.GRID.h end function obj:snap_to_grid(cell) @@ -463,35 +406,33 @@ function obj:currentFullscreenSeq() if self._lastFullscreenSeq and -- if there is a saved last matched seq, and self.fullScreenSizes[self._lastFullscreenSeq] and -- it's (still) a valid index to fullScreenSizes cell == self:getFullscreenCell(self._lastFullscreenSeq) then -- last matched seq is same as the current fullscreen - logger.i('last matched seq is same as current cell, so returning seq = ' .. tostring(self._lastFullscreenSeq)) - return self._lastFullscreenSeq - else + logger.d('last matched seq is same as current cell, so returning seq = ' .. tostring(self._lastFullscreenSeq)) + return self._lastFullscreenSeq + else self._lastFullscreenSeq = nil -- cleanup if the last matched seq doesn't match the frontmost end -- trying to see which fullscreen size is the current window for i = 1,#self.fullScreenSizes do - logger.i('analyze seq = ' .. tostring(i)) + logger.d('analyze seq = ' .. tostring(i)) if cell == self:getFullscreenCell(i) then - logger.i('cell == self:getFullscreenCell(seq)') + logger.d('cell == self:getFullscreenCell(seq)') return i end end - -- we cannot find any fullscreen size that match the current window state, so we start with 0 + -- we cannot find any fullscreen size that matches the current window state, so we start with 0 return 0 end -- Set fullscreen sequence function obj:setToFullscreenSeq(seq) - logger.i('lastMatchedSeq: ' .. tostring(lastMatchedSeq)) - - self._setPosition(self:getFullscreenCell(seq)) + setPosition(self:getFullscreenCell(seq)) if self.fullScreenSizes[seq] == 'c' then - -- we want to use the value only once and then discarge - -- this is in case the window was in one of the full screen position/size + -- we want to use the value only once and then discard it + -- this is in case the window was in one of the full screen positions/sizes self._originalPositionStore['fullscreen'][frontmostWindow():id()] = nil end @@ -508,8 +449,8 @@ function obj:getFullscreenCell(seq) return self._originalPositionStore['fullscreen'][frontmostWindow():id()] end - logger.i('window id: ' .. tostring(frontmostWindow():id())) - logger.i('windows: ' .. hs.inspect(self._originalPositionStore['fullscreen'])) + logger.d('window id: ' .. tostring(frontmostWindow():id())) + logger.d('windows: ' .. hs.inspect(self._originalPositionStore['fullscreen'])) size = hs.geometry.size( self.GRID.w / seq_factor, @@ -523,12 +464,6 @@ function obj:getFullscreenCell(seq) return self:snap_to_grid(hs.geometry(pnt, size)) end --- Set window to cell -function obj._setPosition(cell) - local win = frontmostWindow() - hs.grid.set(win, cell, win:screen()) -end - -- ## Spoon mechanics (`bind`, `init`) @@ -546,12 +481,10 @@ obj.hotkeys = {} --- * down: for the down action (usually `{hyper, "down"}`) --- * fullscreen: for the full-screen action (e.g. `{hyper, "f"}`) --- * center: for the center action (e.g. `{hyper, "c"}`) ---- * move: for the move action (e.g. `{hyper, "v"}`). The move action is ---- active as soon as the hotkey is pressed. While active the left, ---- right, up or down keys can be used (these are configured by ---- the actions above). +--- * move: for the move action (e.g. `{hyper, "v"}`). The move action is active as soon as the hotkey is pressed. While active the left, right, up or down keys can be used (these are configured by the actions above). +--- * resize: for the resize action (e.g. `{hyper, "d"}`). The resize action is active as soon as the hotkey is pressed. While active the left, right, up or down keys can be used (these are configured by the actions above). --- ---- A configuration example can be: +--- A configuration example: --- ``` lua --- local hyper = {"ctrl", "alt", "cmd"} --- spoon.MiroWindowsManager:bindHotkeys({ @@ -561,72 +494,122 @@ obj.hotkeys = {} --- right = {hyper, "right"}, --- fullscreen = {hyper, "f"}, --- center = {hyper, "c"}, ---- move = {hyper, "v"} +--- move = {hyper, "v"}, +--- resize = {hyper, "d" } --- }) +--- ``` --- ---- In this example ctrl+alt+cmd+up will perform the 'up' action ---- Keeping ctrl+alt+cmd+v pressed you can move the window using the arrow keys up,down,left, and right +--- In this example ctrl+alt+cmd+up will perform the 'up' action. +--- Pressing ctrl+alt+cmd+c the window will be centered. --- Pressing ctrl+alt+cmd+f the window will be maximized. ---- ``` +--- Keeping ctrl+alt+cmd+v pressed you can move the window using the arrow keys up, down, left, and right. +--- Keeping ctrl+alt+cmd+d pressed you can resize the window using the arrow keys up, down, left, and right. function obj:bindHotkeys(mapping) logger.i("Bind Hotkeys for Miro's Windows Manager") + -- movingKeys for _,direction in ipairs(self._directions) do - if mapping[direction] then - self.hotkeys[#self.hotkeys + 1] = hs.hotkey.bind( - mapping[direction][1], - mapping[direction][2], - function() self:go(direction) end, - function() cancelPress(direction) end) + -- save the keys that the user decided to be for directions, + -- generally the arrows keys, but it could be also WASD. + self._movingKeys[direction] = mapping[direction][2] + end - -- save the keys that the user decided to be for directions, - -- generally the arrows keys, but it could be also WASD. - self._movingKeys[direction] = mapping[direction][2] - end + -- `growFully` modals + local growFullyModals = {} + for _,direction in ipairs(self._directions) do + local modal = hs.hotkey.modal.new() + + -- primary direction + function modal.entered(_) logger.d(direction..' modal entered.') end + function modal.exited(_) logger.d(direction..' modal exited.') end + + -- opposite direction: growFully() + if mapping[direction] and mapping[self._directionsRel[direction].opp] then + modal:bind( + mapping[direction][1], + mapping[self._directionsRel[direction].opp][2], + function() + logger.i('… from '..direction..', `grow`ing.') + self:growFully(self._directionsRel[direction].dim) + end) + growFullyModals[direction] = modal end + end - if mapping.fullscreen then + -- `go` hotkeys + for _,direction in ipairs(self._directions) do + if mapping[direction] then self.hotkeys[#self.hotkeys + 1] = hs.hotkey.bind( - mapping.fullscreen[1], - mapping.fullscreen[2], - function() self:fullscreen() end) + mapping[direction][1], + mapping[direction][2], + function() + growFullyModals[direction]:enter() + self:go(direction) + end, + function() + growFullyModals[direction]:exit() + end) end + end - if mapping.center then - self.hotkeys[#self.hotkeys + 1] = hs.hotkey.bind( - mapping.center[1], - mapping.center[2], - function() self:center() end) - end + -- `fullscreen` hotkey + if mapping.fullscreen then + self.hotkeys[#self.hotkeys + 1] = hs.hotkey.bind( + mapping.fullscreen[1], + mapping.fullscreen[2], + function() self:fullscreen() end) + end - if mapping.move then - self.hotkeys[#self.hotkeys + 1] = hs.hotkey.bind( - mapping.move[1], - mapping.move[2], - function() self:_moveModeOn() end, - function() self:_moveModeOff() end) - end + -- `center` hotkey + if mapping.center then + self.hotkeys[#self.hotkeys + 1] = hs.hotkey.bind( + mapping.center[1], + mapping.center[2], + function() self:center() end) + end - if mapping.resize then - self.hotkeys[#self.hotkeys + 1] = hs.hotkey.bind( - mapping.resize[1], - mapping.resize[2], - function() self:_resizeModeOn() end, - function() self:_resizeModeOff() end) + -- `move` modifier + if mapping.move then + local modal = hs.hotkey.modal.new() + function modal.entered(_) logger.i("Move Mode on") end + function modal.exited(_) logger.i("Move Mode off") end + for move,key in pairs(self._movingKeys) do + modal:bind(mapping.move[1], key, + function() growFullyModals[move]:enter(); self:move(move) end, + function() growFullyModals[move]:exit() end, + function() self:move(move) end) end + self.hotkeys[#self.hotkeys + 1] = hs.hotkey.bind( + mapping.move[1], + mapping.move[2], + function() modal:enter() end, + function() modal:exit() end) + end - hs.hotkey.bind( - {"ctrl", "alt", "cmd"}, - "l", - function () - logger.i('window id: ' .. tostring(frontmostWindow():id())) - logger.i('windows: ' .. hs.inspect(self._originalPositionStore['fullscreen'])) - end) - + -- `resize` modifier + if mapping.resize then + local modal = hs.hotkey.modal.new() + function modal:entered() logger.i("Resize Mode on") end + function modal:exited() logger.i("Resize Mode off") end + local map = { left = 'thinner', right = 'wider', down = 'shorter', up = 'taller' } + for move,key in pairs(self._movingKeys) do + modal:bind(mapping.move[1], key, + function() growFullyModals[move]:enter(); self:resize(map[move]) end, + function() growFullyModals[move]:exit() end, + function() self:resize(map[move]) end) + end + self.hotkeys[#self.hotkeys + 1] = hs.hotkey.bind( + mapping.resize[1], + mapping.resize[2], + function() modal:enter() end, + function() modal:exit() end) end +end + --- MiroWindowsManager:init() --- Method +--- Currently does nothing (implemented so that treating this Spoon like others won't cause errors). function obj:init() -- void (but it could be used to initialize the module) end diff --git a/README.md b/README.md index bc9343d..f86c13e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Miro's windows manager -With this script you will be able to move the window in halves and in corners using your keyboard and mainly using arrows. You would also be able to resize them by thirds, quarters, or halves. +With this Hammerspoon Spoon you will be able to move windows in halves and in corners using your keyboard, mainly using arrows. You will also be able to resize them by thirds, quarters, or halves. Other projects (e.g. Spectacle) move windows in halves using arrows, and in corners using other counterintuitive shortcuts, like letters, which makes things confusing. @@ -12,19 +12,20 @@ This script needs Hammerspoon in order to work. - Extract the zip file, containing `MiroWindowsManager.spoon` in `~/.hammerspoon/Spoons` - Now you need to configure Hammerspoon in order to load this spoon in `~/.hammerspoon/Spoons/MiroWindowsManager.spoon` adding the following snippet of code in your `init.lua` file: -``` -local hyper = {"ctrl", "alt", "cmd"} - +``` lua hs.loadSpoon("MiroWindowsManager") - -hs.window.animationDuration = 0.3 +local hyper = {"ctrl", "alt", "cmd"} spoon.MiroWindowsManager:bindHotkeys({ - up = {hyper, "up"}, - right = {hyper, "right"}, - down = {hyper, "down"}, - left = {hyper, "left"}, - fullscreen = {hyper, "f"} + up = {hyper, "up"}, + down = {hyper, "down"}, + left = {hyper, "left"}, + right = {hyper, "right"}, + fullscreen = {hyper, "f"}, + center = {hyper, "c"}, + move = {hyper, "v"}, + resize = {hyper, "d" } }) +hs.window.animationDuration = 0.3 ``` ## Shortcuts @@ -33,7 +34,7 @@ In the snippet above configure Miro'w Windows Manager in the following way: ### Hyper key - The hyper key is defined as `ctrl` + `alt` + `cmd`. This means that each shortcut will start by pressing these three keys. If you consider this too verbose for your personal keyboard interactions, you can also change it, for example replacing it with an unused key (e.g. caps lock key) with [Karabiner](https://pqrs.org/osx/karabiner/) and [Seil](https://pqrs.org/osx/karabiner/seil.html.en) to act as hyper key. + The hyper key is defined as `ctrl` + `alt` + `cmd`. This means that each shortcut will start by pressing these three keys. If you consider this too verbose for your personal keyboard interactions, you can also change it, for example replacing it with an unused modifier key (e.g. caps lock key with [Karabiner Elements](https://pqrs.org/osx/karabiner/)). ### Move in halves @@ -70,6 +71,18 @@ Note that in case the window is resized to be a half of the screen, you can also As the other shortcuts, `hyper` + `f` can be pressed multiple times to obtain a centered window of three fourth and one half of height and width. This behaviour can be customized. +### Center window + + - `hyper` + `c`: center window without changing its size + +### Move Mode + + - Press and hold `hyper` + `v`, then tap the move keys to move the window in increments of 5% of the screen size + +### Resize Mode + + - Press and hold `hyper` + `d`, then tap the move keys to resize the window in increments of 5% of the screen size. + ## Animations The snippet above configures the animation to last `0.3s` with `hs.window.animationDuration = 0.3`. To remove the animations completely change this value to `0`. @@ -86,6 +99,10 @@ Here comments from the users, just as reviews. > > — Gaurav +> the only issue I have with miro-windows-manager is the fact that I didn't discover it sooner. just getting into HammerSpoon and love this 🥄 ... so handy, nice work @miromannino ! +> +> — [zanuka](https://github.com/miromannino/miro-windows-manager/issues/13) + ## Articles A suggested tutorial on Mic Sumner: https://www.micsumner.com/how-to-organise-window-viewing-areas-in-mac-os/