diff --git a/src/managers/MasterStackLayoutManager.py b/src/managers/MasterStackLayoutManager.py index 814b167..47ebcce 100644 --- a/src/managers/MasterStackLayoutManager.py +++ b/src/managers/MasterStackLayoutManager.py @@ -22,6 +22,7 @@ KEY_MASTER_WIDTH = "masterWidth" KEY_STACK_LAYOUT = "stackLayout" KEY_STACK_SIDE = "stackSide" +KEY_DEPTH_LIMIT = "depthLimit" class MasterStackLayoutManager(WorkspaceLayoutManager): @@ -36,6 +37,7 @@ def __init__(self, con, workspace, options): self.masterWidth = options.getForWorkspace(self.workspaceNum, KEY_MASTER_WIDTH) or 50 self.stackLayout = options.getForWorkspace(self.workspaceNum, KEY_STACK_LAYOUT) or "splitv" self.stackSide = options.getForWorkspace(self.workspaceNum, KEY_STACK_SIDE) or "right" + self.depthLimit = options.getForWorkspace(self.workspaceNum, KEY_DEPTH_LIMIT) or 0 # If windows exist, fit them into MasterStack self.arrangeUntrackedWindows() @@ -79,19 +81,47 @@ def windowFocused(self, event, window): def onBinding(self, command): - if command == "move up": + if command == "nop layman move up": self.moveUp() - elif command == "move down": + elif command == "nop layman move down": self.moveDown() - elif command == "rotate ccw" or command == "move left": + elif command == "nop layman move right": + focusedWindow = self.getFocusedCon() + if not focusedWindow: + return + # swap with master if direction is correct + if (focusedWindow.id == self.masterId and self.stackSide == "right" + or (focusedWindow.id != self.masterId and self.stackSide == "left" + and self.stackLayout == "splitv")): + self.swapMaster() + elif self.stackLayout == "splith" and focusedWindow.id != self.masterId: + if self.stackSide == "left": + self.moveUp() + elif self.stackSide == "right": + self.moveDown() + elif command == "nop layman move left": + focusedWindow = self.getFocusedCon() + if not focusedWindow: + return + # swap with master if direction is correct + if (focusedWindow.id == self.masterId and self.stackSide == "left" + or (focusedWindow.id != self.masterId and self.stackSide == "right" + and self.stackLayout == "splitv")): + self.swapMaster() + elif self.stackLayout == "splith" and focusedWindow.id != self.masterId: + if self.stackSide == "left": + self.moveDown() + elif self.stackSide == "right": + self.moveUp() + elif command == "nop layman rotate ccw": self.rotateCCW() - elif command == "rotate cw" or command == "move right": + elif command == "nop layman rotate cw": self.rotateCW() - elif command == "swap master": + elif (command == "nop layman swap master"): self.swapMaster() - elif command == "stack toggle": + elif command == "nop layman stack toggle": self.toggleStackLayout() - elif command == "stackside toggle": + elif command == "nop layman stackside toggle": self.toggleStackSide() @@ -143,7 +173,7 @@ def arrangeUntrackedWindows(self): untracked = [x for x in reversed(leaves) if x.id not in self.stack and x.id != self.masterId] for window in untracked: if self.stackId == 0: - if self.masterId == 0: + if not self.getConById(self.masterId) or self.masterId == 0: self.initMaster(window) else: self.initStack(window) @@ -174,6 +204,7 @@ def pushMasterToStack(self, window): self.moveWindow(self.masterId, self.stackId) self.moveToTopOfStack(self.masterId) self.masterId = window.id + self.updateSubStack() def pushWindow(self, window, topCon): @@ -207,9 +238,11 @@ def moveToTopOfStack(self, windowId): # The top of a tabbed layout is the closest to master, handle that moveDirection = "up" topIndex = 0 - if self.stackLayout == "tabbed" and self.stackSide == "right": + if ((self.stackLayout == "tabbed" and self.stackSide == "right") + or self.stackLayout == "splith" and self.stackSide == "right"): moveDirection = "left" - elif self.stackLayout == "tabbed" and self.stackSide == "left": + elif ((self.stackLayout == "tabbed" and self.stackSide == "left") + or self.stackLayout == "splith" and self.stackSide == "left"): moveDirection = "right" topIndex = -1 @@ -228,7 +261,37 @@ def moveToTopOfStack(self, windowId): if stackCon.id != self.stackId: self.moveWindow(windowId, self.stackId) stackCon = self.getConById(self.stackId) - + + def updateSubStack(self): + if (self.stackLayout != "splitv"and self.stackLayout != "splith"): + return + moveDirection = "down" + moveRedirection = "up" + if self.stackLayout == "splith": + moveDirection = self.stackSide + moveRedirection = "right" if self.stackSide == "left" else "left" + lastCon = self.getConById(self.stack[0]).parent + focusedWindow = self.getFocusedCon() + if lastCon.id == self.stackId and len(self.stack) > self.depthLimit and self.depthLimit >= 1: + # if not yet created and depthLimit reached, create second stack + self.con.command("[con_id=%d] split vertical, layout stacking" % self.stack[0]) + self.con.command("[con_id=%d] move %s" % (self.stack[1], moveDirection)) + elif lastCon.id != self.stackId: + numLast = len(lastCon.leaves()) + numFirst = len(self.stack) - numLast + if numFirst > (self.depthLimit - 1): + # if first stack number is higher than the maximum allowed, put lowest one in second stack + self.con.command("[con_id=%d] move %s" % (self.stack[numLast], moveDirection)) + elif numFirst < (self.depthLimit - 1): + # if first stack number is lower than the maximum allowed, pop one from second stack + self.con.command("[con_id=%d] move %s" % (self.stack[numLast - 1], moveRedirection)) + if numLast == 2: + # Remove also last window from SubStack if only two windows were in it + self.con.command("[con_id=%d] move %s" % (self.stack[0], moveRedirection)) + elif numLast == 1: + self.con.command("[con_id=%d] move %s" % (self.stack[0], moveRedirection)) + + self.con.command("[con_id=%d] focus" % focusedWindow.id) def popFromStack(self, windowId, leaves): # Master destroyed, pop from stack @@ -274,6 +337,8 @@ def popWindow(self, window, topCon): # Master destroyed, pop from stack newMaster = self.stack.pop() self.popFromStack(newMaster, leaves) + if len(self.stack) > 0: + self.updateSubStack() elif len(topCon.nodes) == 1 and len(leaves) > 1: # Layout is wrapped in another container, recurse self.popWindow(window, topCon.nodes[0]) @@ -284,6 +349,7 @@ def popWindow(self, window, topCon): for id in self.stack: if id not in allWindowIds: self.stack.remove(id) + self.updateSubStack() break @@ -354,7 +420,7 @@ def moveUp(self): def moveDown(self): - # Check if stack only has one window + # Check if stack only has one window if len(self.stack) < 2: return @@ -370,10 +436,11 @@ def moveDown(self): # Swap with top of stack if master is focused if focusedWindow.id == self.masterId: - self.con.command("[con_id=%d] swap container with con_id %d" % (focusedWindow.id, self.stack[-1])) - self.masterId = self.stack.pop() - self.stack.append(focusedWindow.id) - self.log("Swapped master %d with top of stack %d" % (self.stack[-1], self.masterId)) + targetId = self.stack.pop() + self.con.command("[con_id=%d] swap container with con_id %d" % (targetId, self.masterId)) + self.stack.append(self.masterId) + self.masterId = targetId + self.log("Swapped window %d with master" % targetId) return # Swap window with window below @@ -390,9 +457,13 @@ def moveDown(self): def rotateCCW(self): - # Exit if less than three windows + # Swap master and top of stack if only two windows if len(self.stack) < 2: - self.log("Only 2 windows, can't rotate") + targetId = self.stack.pop() + self.con.command("[con_id=%d] swap container with con_id %d" % (targetId, self.masterId)) + self.stack.append(self.masterId) + self.masterId = targetId + self.log("Swapped window %d with master" % targetId) return # Swap top of stack with master, then move old master to bottom @@ -408,12 +479,17 @@ def rotateCCW(self): # Update record self.masterId = newMasterId self.stack.appendleft(prevMasterId) + self.updateSubStack() def rotateCW(self): - # Exit if less than three windows + # Swap master and top of stack if only two windows if len(self.stack) < 2: - self.log("Only 2 windows, can't rotate") + targetId = self.stack.pop() + self.con.command("[con_id=%d] swap container with con_id %d" % (targetId, self.masterId)) + self.stack.append(self.masterId) + self.masterId = targetId + self.log("Swapped window %d with master" % targetId) return # Swap bottom of stack with master, then move old master to top @@ -434,6 +510,7 @@ def rotateCW(self): # Update record self.masterId = newMasterId self.stack.append(prevMasterId) + self.updateSubStack() def swapMaster(self):