Allow specifying the width of the tall window in the Tall layout as a percentage of available space
Also remove the --window-layout option as it was redundant. Same effect can be achieved using -o enabled_layouts=some_layout,*
This commit is contained in:
parent
b59d1bda8b
commit
3fdf47c535
@ -343,6 +343,17 @@ You can switch between layouts using the {sc_next_layout} key combination. You c
|
|||||||
also create shortcuts to select particular layouts, and choose which layouts
|
also create shortcuts to select particular layouts, and choose which layouts
|
||||||
you want to enable/disable, see link:kitty/kitty.conf[kitty.conf] for examples.
|
you want to enable/disable, see link:kitty/kitty.conf[kitty.conf] for examples.
|
||||||
|
|
||||||
|
Some layouts take options to control their behavior. For example, the `fat` and `tall`
|
||||||
|
layouts accept the `bias` option to control how the available space is split up. To specify the
|
||||||
|
option, in kitty.conf use:
|
||||||
|
|
||||||
|
```
|
||||||
|
enabled_layouts tall:bias=70
|
||||||
|
```
|
||||||
|
|
||||||
|
this will make the tall window occupy `70%` of available width. `bias` can be
|
||||||
|
any number between 10 and 90.
|
||||||
|
|
||||||
Writing a new layout only requires about fifty lines of code, so if there is
|
Writing a new layout only requires about fifty lines of code, so if there is
|
||||||
some layout you want, take a look at link:kitty/layout.py[layout.py] and submit
|
some layout you want, take a look at link:kitty/layout.py[layout.py] and submit
|
||||||
a pull request!
|
a pull request!
|
||||||
|
|||||||
11
kitty/cli.py
11
kitty/cli.py
@ -10,7 +10,6 @@ from collections import deque
|
|||||||
from .config import defaults, load_config
|
from .config import defaults, load_config
|
||||||
from .config_utils import resolve_config
|
from .config_utils import resolve_config
|
||||||
from .constants import appname, defconf, is_macos, is_wayland, str_version
|
from .constants import appname, defconf, is_macos, is_wayland, str_version
|
||||||
from .layout import all_layouts
|
|
||||||
|
|
||||||
CONFIG_HELP = '''\
|
CONFIG_HELP = '''\
|
||||||
Specify a path to the configuration file(s) to use. All configuration files are
|
Specify a path to the configuration file(s) to use. All configuration files are
|
||||||
@ -71,12 +70,6 @@ condition=not is_macos
|
|||||||
Detach from the controlling terminal, if any
|
Detach from the controlling terminal, if any
|
||||||
|
|
||||||
|
|
||||||
--window-layout
|
|
||||||
type=choices
|
|
||||||
choices={window_layout_choices}
|
|
||||||
The window layout to use on startup.
|
|
||||||
|
|
||||||
|
|
||||||
--session
|
--session
|
||||||
Path to a file containing the startup |_ session| (tabs, windows, layout, programs).
|
Path to a file containing the startup |_ session| (tabs, windows, layout, programs).
|
||||||
See the README file for details and an example.
|
See the README file for details and an example.
|
||||||
@ -488,8 +481,8 @@ def parse_cmdline(oc, disabled, args=None):
|
|||||||
def options_spec():
|
def options_spec():
|
||||||
if not hasattr(options_spec, 'ans'):
|
if not hasattr(options_spec, 'ans'):
|
||||||
options_spec.ans = OPTIONS.format(
|
options_spec.ans = OPTIONS.format(
|
||||||
appname=appname, config_help=CONFIG_HELP.format(appname=appname, conf_name=appname),
|
appname=appname, config_help=CONFIG_HELP.format(appname=appname, conf_name=appname)
|
||||||
window_layout_choices=', '.join(all_layouts)
|
|
||||||
)
|
)
|
||||||
return options_spec.ans
|
return options_spec.ans
|
||||||
|
|
||||||
|
|||||||
@ -245,14 +245,24 @@ def to_modifiers(val):
|
|||||||
return parse_mods(val.split('+'), val) or 0
|
return parse_mods(val.split('+'), val) or 0
|
||||||
|
|
||||||
|
|
||||||
|
def uniq(vals, result_type=list):
|
||||||
|
seen = set()
|
||||||
|
seen_add = seen.add
|
||||||
|
return result_type(x for x in vals if x not in seen and not seen_add(x))
|
||||||
|
|
||||||
|
|
||||||
def to_layout_names(raw):
|
def to_layout_names(raw):
|
||||||
parts = [x.strip().lower() for x in raw.split(',')]
|
parts = [x.strip().lower() for x in raw.split(',')]
|
||||||
if '*' in parts:
|
ans = []
|
||||||
return sorted(all_layouts)
|
|
||||||
for p in parts:
|
for p in parts:
|
||||||
if p not in all_layouts:
|
if p == '*':
|
||||||
|
ans.extend(sorted(all_layouts))
|
||||||
|
continue
|
||||||
|
name = p.partition(':')[0]
|
||||||
|
if name not in all_layouts:
|
||||||
raise ValueError('The window layout {} is unknown'.format(p))
|
raise ValueError('The window layout {} is unknown'.format(p))
|
||||||
return parts
|
ans.append(p)
|
||||||
|
return uniq(ans)
|
||||||
|
|
||||||
|
|
||||||
def adjust_line_height(x):
|
def adjust_line_height(x):
|
||||||
|
|||||||
@ -21,7 +21,7 @@ def idx_for_id(win_id, windows):
|
|||||||
return i
|
return i
|
||||||
|
|
||||||
|
|
||||||
def layout_dimension(start_at, length, cell_length, number_of_windows=1, border_length=0, margin_length=0, padding_length=0, left_align=False):
|
def layout_dimension(start_at, length, cell_length, number_of_windows=1, border_length=0, margin_length=0, padding_length=0, left_align=False, bias=None):
|
||||||
number_of_cells = length // cell_length
|
number_of_cells = length // cell_length
|
||||||
border_length += padding_length
|
border_length += padding_length
|
||||||
space_needed_for_border = number_of_windows * 2 * border_length
|
space_needed_for_border = number_of_windows * 2 * border_length
|
||||||
@ -37,8 +37,22 @@ def layout_dimension(start_at, length, cell_length, number_of_windows=1, border_
|
|||||||
if not left_align:
|
if not left_align:
|
||||||
pos += extra // 2
|
pos += extra // 2
|
||||||
pos += border_length + margin_length
|
pos += border_length + margin_length
|
||||||
inner_length = cells_per_window * cell_length
|
|
||||||
window_length = 2 * (border_length + margin_length) + inner_length
|
def calc_window_length(cells_in_window):
|
||||||
|
inner_length = cells_in_window * cell_length
|
||||||
|
return 2 * (border_length + margin_length) + inner_length
|
||||||
|
|
||||||
|
if bias is not None and number_of_windows == 2:
|
||||||
|
cells_per_window = int(bias * number_of_cells)
|
||||||
|
window_length = calc_window_length(cells_per_window)
|
||||||
|
yield pos, cells_per_window
|
||||||
|
pos += window_length
|
||||||
|
cells_per_window = number_of_cells - cells_per_window
|
||||||
|
window_length = calc_window_length(cells_per_window)
|
||||||
|
yield pos, cells_per_window
|
||||||
|
return
|
||||||
|
|
||||||
|
window_length = calc_window_length(cells_per_window)
|
||||||
extra = number_of_cells - (cells_per_window * number_of_windows)
|
extra = number_of_cells - (cells_per_window * number_of_windows)
|
||||||
while number_of_windows > 0:
|
while number_of_windows > 0:
|
||||||
number_of_windows -= 1
|
number_of_windows -= 1
|
||||||
@ -62,7 +76,7 @@ class Layout:
|
|||||||
needs_window_borders = True
|
needs_window_borders = True
|
||||||
only_active_window_visible = False
|
only_active_window_visible = False
|
||||||
|
|
||||||
def __init__(self, os_window_id, tab_id, opts, border_width):
|
def __init__(self, os_window_id, tab_id, opts, border_width, layout_opts=''):
|
||||||
self.os_window_id = os_window_id
|
self.os_window_id = os_window_id
|
||||||
self.tab_id = tab_id
|
self.tab_id = tab_id
|
||||||
self.set_active_window_in_os_window = partial(set_active_window, os_window_id, tab_id)
|
self.set_active_window_in_os_window = partial(set_active_window, os_window_id, tab_id)
|
||||||
@ -74,6 +88,18 @@ class Layout:
|
|||||||
# A set of rectangles corresponding to the blank spaces at the edges of
|
# A set of rectangles corresponding to the blank spaces at the edges of
|
||||||
# this layout, i.e. spaces that are not covered by any window
|
# this layout, i.e. spaces that are not covered by any window
|
||||||
self.blank_rects = ()
|
self.blank_rects = ()
|
||||||
|
self.layout_opts = self.parse_layout_opts(layout_opts)
|
||||||
|
self.full_name = self.name + ((':' + layout_opts) if layout_opts else '')
|
||||||
|
|
||||||
|
def parse_layout_opts(self, layout_opts):
|
||||||
|
if not layout_opts:
|
||||||
|
return {}
|
||||||
|
ans = {}
|
||||||
|
for x in layout_opts.split(';'):
|
||||||
|
k, v = x.partition('=')[::2]
|
||||||
|
if k and v:
|
||||||
|
ans[k] = v
|
||||||
|
return ans
|
||||||
|
|
||||||
def nth_window(self, all_windows, num, make_active=True):
|
def nth_window(self, all_windows, num, make_active=True):
|
||||||
windows = process_overlaid_windows(all_windows)[1]
|
windows = process_overlaid_windows(all_windows)[1]
|
||||||
@ -199,15 +225,15 @@ class Layout:
|
|||||||
return idx_for_id(active_window.id, all_windows)
|
return idx_for_id(active_window.id, all_windows)
|
||||||
|
|
||||||
# Utils {{{
|
# Utils {{{
|
||||||
def xlayout(self, num):
|
def xlayout(self, num, bias=None):
|
||||||
return layout_dimension(
|
return layout_dimension(
|
||||||
central.left, central.width, cell_width, num, self.border_width,
|
central.left, central.width, cell_width, num, self.border_width,
|
||||||
margin_length=self.margin_width, padding_length=self.padding_width)
|
margin_length=self.margin_width, padding_length=self.padding_width, bias=bias)
|
||||||
|
|
||||||
def ylayout(self, num, left_align=True):
|
def ylayout(self, num, left_align=True, bias=None):
|
||||||
return layout_dimension(
|
return layout_dimension(
|
||||||
central.top, central.height, cell_height, num, self.border_width, left_align=left_align,
|
central.top, central.height, cell_height, num, self.border_width, left_align=left_align,
|
||||||
margin_length=self.margin_width, padding_length=self.padding_width)
|
margin_length=self.margin_width, padding_length=self.padding_width, bias=bias)
|
||||||
|
|
||||||
def simple_blank_rects(self, first_window, last_window):
|
def simple_blank_rects(self, first_window, last_window):
|
||||||
br = self.blank_rects
|
br = self.blank_rects
|
||||||
@ -285,6 +311,15 @@ class Tall(Layout):
|
|||||||
|
|
||||||
name = 'tall'
|
name = 'tall'
|
||||||
|
|
||||||
|
def parse_layout_opts(self, layout_opts):
|
||||||
|
ans = Layout.parse_layout_opts(self, layout_opts)
|
||||||
|
try:
|
||||||
|
ans['bias'] = int(ans.get('bias', 50)) / 100
|
||||||
|
except Exception:
|
||||||
|
ans['bias'] = 0.5
|
||||||
|
ans['bias'] = max(0.1, min(ans['bias'], 0.9))
|
||||||
|
return ans
|
||||||
|
|
||||||
def do_layout(self, windows, active_window_idx):
|
def do_layout(self, windows, active_window_idx):
|
||||||
self.blank_rects = []
|
self.blank_rects = []
|
||||||
if len(windows) == 1:
|
if len(windows) == 1:
|
||||||
@ -292,7 +327,7 @@ class Tall(Layout):
|
|||||||
windows[0].set_geometry(0, wg)
|
windows[0].set_geometry(0, wg)
|
||||||
self.blank_rects = blank_rects_for_window(windows[0])
|
self.blank_rects = blank_rects_for_window(windows[0])
|
||||||
return
|
return
|
||||||
xlayout = self.xlayout(2)
|
xlayout = self.xlayout(2, bias=self.layout_opts['bias'])
|
||||||
xstart, xnum = next(xlayout)
|
xstart, xnum = next(xlayout)
|
||||||
ystart, ynum = next(self.ylayout(1))
|
ystart, ynum = next(self.ylayout(1))
|
||||||
windows[0].set_geometry(0, window_geometry(xstart, xnum, ystart, ynum))
|
windows[0].set_geometry(0, window_geometry(xstart, xnum, ystart, ynum))
|
||||||
@ -311,7 +346,7 @@ class Tall(Layout):
|
|||||||
self.bottom_blank_rect(windows[0])
|
self.bottom_blank_rect(windows[0])
|
||||||
|
|
||||||
|
|
||||||
class Fat(Layout):
|
class Fat(Tall):
|
||||||
|
|
||||||
name = 'fat'
|
name = 'fat'
|
||||||
|
|
||||||
@ -323,7 +358,7 @@ class Fat(Layout):
|
|||||||
self.blank_rects = blank_rects_for_window(windows[0])
|
self.blank_rects = blank_rects_for_window(windows[0])
|
||||||
return
|
return
|
||||||
xstart, xnum = next(self.xlayout(1))
|
xstart, xnum = next(self.xlayout(1))
|
||||||
ylayout = self.ylayout(2)
|
ylayout = self.ylayout(2, bias=self.layout_opts['bias'])
|
||||||
ystart, ynum = next(ylayout)
|
ystart, ynum = next(ylayout)
|
||||||
windows[0].set_geometry(0, window_geometry(xstart, xnum, ystart, ynum))
|
windows[0].set_geometry(0, window_geometry(xstart, xnum, ystart, ynum))
|
||||||
xlayout = self.xlayout(len(windows) - 1)
|
xlayout = self.xlayout(len(windows) - 1)
|
||||||
|
|||||||
@ -110,12 +110,7 @@ def create_session(opts, args=None, special_window=None, cwd_from=None, respect_
|
|||||||
with open(args.session) as f:
|
with open(args.session) as f:
|
||||||
return parse_session(f.read(), opts)
|
return parse_session(f.read(), opts)
|
||||||
ans = Session()
|
ans = Session()
|
||||||
if args and args.window_layout:
|
current_layout = opts.enabled_layouts[0] if opts.enabled_layouts else 'tall'
|
||||||
if args.window_layout not in opts.enabled_layouts:
|
|
||||||
opts.enabled_layouts.insert(0, args.window_layout)
|
|
||||||
current_layout = args.window_layout
|
|
||||||
else:
|
|
||||||
current_layout = opts.enabled_layouts[0] if opts.enabled_layouts else 'tall'
|
|
||||||
ans.add_tab(opts)
|
ans.add_tab(opts)
|
||||||
ans.tabs[-1].layout = current_layout
|
ans.tabs[-1].layout = current_layout
|
||||||
if special_window is None:
|
if special_window is None:
|
||||||
|
|||||||
@ -137,14 +137,17 @@ class Tab: # {{{
|
|||||||
if w is not None:
|
if w is not None:
|
||||||
w.change_titlebar_color()
|
w.change_titlebar_color()
|
||||||
|
|
||||||
def create_layout_object(self, idx):
|
def create_layout_object(self, name):
|
||||||
return all_layouts[idx](self.os_window_id, self.id, self.opts, self.borders.border_width)
|
name, rest = name.partition(':')[::2]
|
||||||
|
return all_layouts[name](self.os_window_id, self.id, self.opts, self.borders.border_width, rest)
|
||||||
|
|
||||||
def next_layout(self):
|
def next_layout(self):
|
||||||
if len(self.enabled_layouts) > 1:
|
if len(self.enabled_layouts) > 1:
|
||||||
try:
|
for i, layout_name in enumerate(self.enabled_layouts):
|
||||||
idx = self.enabled_layouts.index(self.current_layout.name)
|
if layout_name == self.current_layout.full_name:
|
||||||
except Exception:
|
idx = i
|
||||||
|
break
|
||||||
|
else:
|
||||||
idx = -1
|
idx = -1
|
||||||
nl = self.enabled_layouts[(idx + 1) % len(self.enabled_layouts)]
|
nl = self.enabled_layouts[(idx + 1) % len(self.enabled_layouts)]
|
||||||
self.current_layout = self.create_layout_object(nl)
|
self.current_layout = self.create_layout_object(nl)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user