diff --git a/libqtile/layout/columns.py b/libqtile/layout/columns.py index 72aee89a91..93b52dc6a0 100644 --- a/libqtile/layout/columns.py +++ b/libqtile/layout/columns.py @@ -172,6 +172,7 @@ class Columns(Layout): "(one of ``Columns._left`` or ``Columns._right``). " "Ignored if 'fair=True'.", ), + ("initial_ratio", 1, "Ratio of first column to second column."), ] def __init__(self, **config): @@ -226,6 +227,16 @@ def focus(self, client: Window) -> None: def cc(self): return self.columns[self.current] + def get_ratio_widths(self): + # Total width is 200 + # main + secondary = 200 + # main = secondary * ratio + # secondary column is therefore 200 / (1 + ratio) + # main column is 200 - secondary column + secondary = 200 // (1 + self.initial_ratio) + main = 200 - secondary + return main, secondary + def add_column(self, prepend=False): c = _Column(self.split, self.insert_position) if prepend: @@ -233,6 +244,10 @@ def add_column(self, prepend=False): self.current += 1 else: self.columns.append(c) + if len(self.columns) == 2 and not self.fair: + main, secondary = self.get_ratio_widths() + self.cc.width = main + c.width = secondary return c def remove_column(self, col): @@ -549,12 +564,31 @@ def grow_down(self): @expose_command() def normalize(self): + """Give columns equal widths.""" for col in self.columns: for client in col: col.heights[client] = 100 col.width = 100 self.group.layout_all() + @expose_command() + def reset(self): + """Resets column widths, respecting 'initial_ratio' value.""" + if self.initial_ratio == 1 or len(self.columns) == 1 or self.fair: + self.normalize() + return + + main, secondary = self.get_ratio_widths() + + if self.align == Columns._right: + self.columns[0].width = main + self.columns[1].width = secondary + else: + self.columns[-1].width = main + self.columns[-2].width = secondary + + self.group.layout_all() + def swap_column(self, src, dst): self.columns[src], self.columns[dst] = self.columns[dst], self.columns[src] self.current = dst diff --git a/test/layouts/test_columns.py b/test/layouts/test_columns.py index 17fc23f52e..28be305395 100644 --- a/test/layouts/test_columns.py +++ b/test/layouts/test_columns.py @@ -58,6 +58,13 @@ class ColumnsLeftAlign(ColumnsConfig): layouts = [layout.Columns(align=layout.Columns._left, border_width=0)] +class ColumnsInitialRatio(ColumnsConfig): + layouts = [ + layout.Columns(initial_ratio=3, border_width=0), + layout.Columns(initial_ratio=3, align=layout.Columns._left, border_width=0), + ] + + columns_config = pytest.mark.parametrize("manager", [ColumnsConfig], indirect=True) columns_single_border_disabled_config = pytest.mark.parametrize( "manager", [ColumnsSingleBorderDisabledConfig], indirect=True @@ -66,6 +73,7 @@ class ColumnsLeftAlign(ColumnsConfig): "manager", [ColumnsSingleBorderEnabledConfig], indirect=True ) columns_left_align = pytest.mark.parametrize("manager", [ColumnsLeftAlign], indirect=True) +columns_initial_ratio = pytest.mark.parametrize("manager", [ColumnsInitialRatio], indirect=True) # This currently only tests the window focus cycle @@ -229,3 +237,62 @@ def test_columns_left_align(manager): assert info["y"] == 0 assert info["width"] == WIDTH / 2 assert info["height"] == HEIGHT / 2 + + +@columns_initial_ratio +def test_columns_initial_ratio_right(manager): + manager.test_window("1") + manager.test_window("2") + + # initial_ratio is 3 (i.e. main column is 3 times size of secondary column) + # so secondary column is 1/4 of screen width + info = manager.c.window.info() + assert info["x"] == 3 * WIDTH / 4 + assert info["y"] == 0 + assert info["width"] == WIDTH / 4 + assert info["height"] == HEIGHT + + # Growing right means secondary column is now smaller + manager.c.layout.grow_right() + info = manager.c.window.info() + assert info["width"] < WIDTH / 4 + + # Reset to restore initial_ratio + manager.c.layout.reset() + info = manager.c.window.info() + assert info["width"] == WIDTH / 4 + + # Normalize to make columns equal + manager.c.layout.normalize() + info = manager.c.window.info() + assert info["width"] == WIDTH / 2 + + +@columns_initial_ratio +def test_columns_initial_ratio_left(manager): + manager.c.next_layout() + manager.test_window("1") + manager.test_window("2") + + # initial_ratio is 3 (i.e. main column is 3 times size of secondary column) + # so secondary column is 1/4 of screen width + info = manager.c.window.info() + assert info["x"] == 0 + assert info["y"] == 0 + assert info["width"] == WIDTH / 4 + assert info["height"] == HEIGHT + + # Growing right means secondary column is now smaller + manager.c.layout.grow_left() + info = manager.c.window.info() + assert info["width"] < WIDTH / 4 + + # Reset to restore initial_ratio + manager.c.layout.reset() + info = manager.c.window.info() + assert info["width"] == WIDTH / 4 + + # Normalize to make columns equal + manager.c.layout.normalize() + info = manager.c.window.info() + assert info["width"] == WIDTH / 2