mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-09-11 14:45:31 +03:00
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
|
||||
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
|
||||
some layout you want, take a look at link:kitty/layout.py[layout.py] and submit
|
||||
a pull request!
|
||||
|
11
kitty/cli.py
11
kitty/cli.py
@ -10,7 +10,6 @@
|
||||
from .config import defaults, load_config
|
||||
from .config_utils import resolve_config
|
||||
from .constants import appname, defconf, is_macos, is_wayland, str_version
|
||||
from .layout import all_layouts
|
||||
|
||||
CONFIG_HELP = '''\
|
||||
Specify a path to the configuration file(s) to use. All configuration files are
|
||||
@ -71,12 +70,6 @@
|
||||
Detach from the controlling terminal, if any
|
||||
|
||||
|
||||
--window-layout
|
||||
type=choices
|
||||
choices={window_layout_choices}
|
||||
The window layout to use on startup.
|
||||
|
||||
|
||||
--session
|
||||
Path to a file containing the startup |_ session| (tabs, windows, layout, programs).
|
||||
See the README file for details and an example.
|
||||
@ -488,8 +481,8 @@ def parse_cmdline(oc, disabled, args=None):
|
||||
def options_spec():
|
||||
if not hasattr(options_spec, 'ans'):
|
||||
options_spec.ans = OPTIONS.format(
|
||||
appname=appname, config_help=CONFIG_HELP.format(appname=appname, conf_name=appname),
|
||||
window_layout_choices=', '.join(all_layouts)
|
||||
appname=appname, config_help=CONFIG_HELP.format(appname=appname, conf_name=appname)
|
||||
|
||||
)
|
||||
return options_spec.ans
|
||||
|
||||
|
@ -245,14 +245,24 @@ def to_modifiers(val):
|
||||
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):
|
||||
parts = [x.strip().lower() for x in raw.split(',')]
|
||||
if '*' in parts:
|
||||
return sorted(all_layouts)
|
||||
ans = []
|
||||
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))
|
||||
return parts
|
||||
ans.append(p)
|
||||
return uniq(ans)
|
||||
|
||||
|
||||
def adjust_line_height(x):
|
||||
|
@ -21,7 +21,7 @@ def idx_for_id(win_id, windows):
|
||||
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
|
||||
border_length += padding_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:
|
||||
pos += extra // 2
|
||||
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)
|
||||
while number_of_windows > 0:
|
||||
number_of_windows -= 1
|
||||
@ -62,7 +76,7 @@ class Layout:
|
||||
needs_window_borders = True
|
||||
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.tab_id = tab_id
|
||||
self.set_active_window_in_os_window = partial(set_active_window, os_window_id, tab_id)
|
||||
@ -74,6 +88,18 @@ def __init__(self, os_window_id, tab_id, opts, border_width):
|
||||
# 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
|
||||
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):
|
||||
windows = process_overlaid_windows(all_windows)[1]
|
||||
@ -199,15 +225,15 @@ def __call__(self, all_windows, active_window_idx):
|
||||
return idx_for_id(active_window.id, all_windows)
|
||||
|
||||
# Utils {{{
|
||||
def xlayout(self, num):
|
||||
def xlayout(self, num, bias=None):
|
||||
return layout_dimension(
|
||||
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(
|
||||
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):
|
||||
br = self.blank_rects
|
||||
@ -285,6 +311,15 @@ class Tall(Layout):
|
||||
|
||||
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):
|
||||
self.blank_rects = []
|
||||
if len(windows) == 1:
|
||||
@ -292,7 +327,7 @@ def do_layout(self, windows, active_window_idx):
|
||||
windows[0].set_geometry(0, wg)
|
||||
self.blank_rects = blank_rects_for_window(windows[0])
|
||||
return
|
||||
xlayout = self.xlayout(2)
|
||||
xlayout = self.xlayout(2, bias=self.layout_opts['bias'])
|
||||
xstart, xnum = next(xlayout)
|
||||
ystart, ynum = next(self.ylayout(1))
|
||||
windows[0].set_geometry(0, window_geometry(xstart, xnum, ystart, ynum))
|
||||
@ -311,7 +346,7 @@ def do_layout(self, windows, active_window_idx):
|
||||
self.bottom_blank_rect(windows[0])
|
||||
|
||||
|
||||
class Fat(Layout):
|
||||
class Fat(Tall):
|
||||
|
||||
name = 'fat'
|
||||
|
||||
@ -323,7 +358,7 @@ def do_layout(self, windows, active_window_idx):
|
||||
self.blank_rects = blank_rects_for_window(windows[0])
|
||||
return
|
||||
xstart, xnum = next(self.xlayout(1))
|
||||
ylayout = self.ylayout(2)
|
||||
ylayout = self.ylayout(2, bias=self.layout_opts['bias'])
|
||||
ystart, ynum = next(ylayout)
|
||||
windows[0].set_geometry(0, window_geometry(xstart, xnum, ystart, ynum))
|
||||
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:
|
||||
return parse_session(f.read(), opts)
|
||||
ans = Session()
|
||||
if args and args.window_layout:
|
||||
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'
|
||||
current_layout = opts.enabled_layouts[0] if opts.enabled_layouts else 'tall'
|
||||
ans.add_tab(opts)
|
||||
ans.tabs[-1].layout = current_layout
|
||||
if special_window is None:
|
||||
|
@ -137,14 +137,17 @@ def relayout_borders(self):
|
||||
if w is not None:
|
||||
w.change_titlebar_color()
|
||||
|
||||
def create_layout_object(self, idx):
|
||||
return all_layouts[idx](self.os_window_id, self.id, self.opts, self.borders.border_width)
|
||||
def create_layout_object(self, name):
|
||||
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):
|
||||
if len(self.enabled_layouts) > 1:
|
||||
try:
|
||||
idx = self.enabled_layouts.index(self.current_layout.name)
|
||||
except Exception:
|
||||
for i, layout_name in enumerate(self.enabled_layouts):
|
||||
if layout_name == self.current_layout.full_name:
|
||||
idx = i
|
||||
break
|
||||
else:
|
||||
idx = -1
|
||||
nl = self.enabled_layouts[(idx + 1) % len(self.enabled_layouts)]
|
||||
self.current_layout = self.create_layout_object(nl)
|
||||
|
Loading…
Reference in New Issue
Block a user