Implement adding of windows to splits layout

This commit is contained in:
Kovid Goyal 2020-01-28 08:46:07 +05:30
parent a99caed693
commit c788e30b66
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 80 additions and 8 deletions

View File

@ -73,12 +73,15 @@ newly launched child process.
--location --location
type=choices type=choices
default=last default=last
choices=first,after,before,neighbor,last choices=first,after,before,neighbor,last,vsplit,hsplit
Where to place the newly created window when it is added to a tab which Where to place the newly created window when it is added to a tab which
already has existing windows in it. :code:`after` and :code:`before` place the new already has existing windows in it. :code:`after` and :code:`before` place the new
window before or after the active window. :code:`neighbor` is a synonym for :code:`after`. window before or after the active window. :code:`neighbor` is a synonym for :code:`after`.
Also applies to creating a new tab, where the value of :code:`after` Also applies to creating a new tab, where the value of :code:`after`
will cause the new tab to be placed next to the current tab instead of at the end. will cause the new tab to be placed next to the current tab instead of at the end.
The values of :code:`vsplit` and :code:`hsplit` are only used by the :code:`splits`
layout and control if the new window is placed in a vertical or horizontal split
with the currently active window.
--allow-remote-control --allow-remote-control

View File

@ -279,10 +279,19 @@ class Layout: # {{{
all_windows.append(all_windows[i]) all_windows.append(all_windows[i])
all_windows[i] = window all_windows[i] = window
active_window_idx = i active_window_idx = i
elif location is not None: if active_window_idx is None:
if location == 'neighbor': if location == 'neighbor':
location = 'after' location = 'after'
if location == 'after' and current_active_window_idx is not None and len(all_windows) > 1: active_window_idx = self.do_add_window(all_windows, window, current_active_window_idx, location)
self(all_windows, active_window_idx)
self.set_active_window_in_os_window(active_window_idx)
return active_window_idx
def do_add_window(self, all_windows, window, current_active_window_idx, location):
active_window_idx = None
if location is not None:
if location in ('after', 'vsplit', 'hsplit') and current_active_window_idx is not None and len(all_windows) > 1:
active_window_idx = min(current_active_window_idx + 1, len(all_windows)) active_window_idx = min(current_active_window_idx + 1, len(all_windows))
elif location == 'before' and current_active_window_idx is not None and len(all_windows) > 1: elif location == 'before' and current_active_window_idx is not None and len(all_windows) > 1:
active_window_idx = current_active_window_idx active_window_idx = current_active_window_idx
@ -296,8 +305,6 @@ class Layout: # {{{
if active_window_idx is None: if active_window_idx is None:
active_window_idx = len(all_windows) active_window_idx = len(all_windows)
all_windows.append(window) all_windows.append(window)
self(all_windows, active_window_idx)
self.set_active_window_in_os_window(active_window_idx)
return active_window_idx return active_window_idx
def remove_window(self, all_windows, window, current_active_window_idx, swapped=False): def remove_window(self, all_windows, window, current_active_window_idx, swapped=False):
@ -973,6 +980,16 @@ class Pair:
if isinstance(self.two, Pair): if isinstance(self.two, Pair):
yield from self.two.self_and_descendants() yield from self.two.self_and_descendants()
def pair_for_window(self, window_id):
if self.one == window_id or self.two == window_id:
return self
ans = None
if isinstance(self.one, Pair):
ans = self.one.pair_for_window(window_id)
if ans is None and isinstance(self.two, Pair):
ans = self.two.pair_for_window(window_id)
return ans
def remove_windows(self, window_ids): def remove_windows(self, window_ids):
if isinstance(self.one, int) and self.one in window_ids: if isinstance(self.one, int) and self.one in window_ids:
self.one = None self.one = None
@ -1025,6 +1042,21 @@ class Pair:
pair.balanced_add(window_id) pair.balanced_add(window_id)
return pair return pair
def split_and_add(self, existing_window_id, new_window_id, horizontal, after):
q = (existing_window_id, new_window_id) if after else (new_window_id, existing_window_id)
if self.is_redundant:
pair = self
pair.horizontal = horizontal
self.one, self.two = q
else:
pair = Pair(horizontal=horizontal)
if self.one == existing_window_id:
self.one = pair
else:
self.two = pair
tuple(map(pair.balanced_add, q))
return pair
def apply_window_geometry(self, window_id, window_geometry, id_window_map, id_idx_map): def apply_window_geometry(self, window_id, window_geometry, id_window_map, id_idx_map):
w = id_window_map[window_id] w = id_window_map[window_id]
w.set_geometry(id_idx_map[window_id], window_geometry) w.set_geometry(id_idx_map[window_id], window_geometry)
@ -1083,6 +1115,17 @@ class Splits(Layout):
def default_axis_is_horizontal(self): def default_axis_is_horizontal(self):
return self.layout_opts['default_axis_is_horizontal'] return self.layout_opts['default_axis_is_horizontal']
@property
def pairs_root(self):
root = getattr(self, '_pairs_root', None)
if root is None:
self._pairs_root = root = Pair(horizontal=self.default_axis_is_horizontal)
return root
@pairs_root.setter
def pairs_root(self, root):
self._pairs_root = root
def parse_layout_opts(self, layout_opts): def parse_layout_opts(self, layout_opts):
ans = Layout.parse_layout_opts(self, layout_opts) ans = Layout.parse_layout_opts(self, layout_opts)
ans['default_axis_is_horizontal'] = ans.get('split_axis', 'horizontal') == 'horizontal' ans['default_axis_is_horizontal'] = ans.get('split_axis', 'horizontal') == 'horizontal'
@ -1090,9 +1133,7 @@ class Splits(Layout):
def do_layout(self, windows, active_window_idx, all_windows): def do_layout(self, windows, active_window_idx, all_windows):
window_count = len(windows) window_count = len(windows)
root = getattr(self, 'pairs_root', None) root = self.pairs_root
if root is None:
self.pairs_root = root = Pair(horizontal=self.default_axis_is_horizontal)
all_present_window_ids = frozenset(w.overlay_for or w.id for w in windows) all_present_window_ids = frozenset(w.overlay_for or w.id for w in windows)
already_placed_window_ids = frozenset(root.all_window_ids()) already_placed_window_ids = frozenset(root.all_window_ids())
windows_to_remove = already_placed_window_ids - all_present_window_ids windows_to_remove = already_placed_window_ids - all_present_window_ids
@ -1117,6 +1158,34 @@ class Splits(Layout):
else: else:
root.layout_pair(central.left, central.top, central.width, central.height, id_window_map, id_idx_map, self) root.layout_pair(central.left, central.top, central.width, central.height, id_window_map, id_idx_map, self)
def do_add_window(self, all_windows, window, current_active_window_idx, location):
horizontal = self.default_axis_is_horizontal
after = True
if location is not None:
if location == 'vsplit':
horizontal = True
elif location == 'hsplit':
horizontal = False
if location in ('before', 'first'):
after = False
active_window_idx = None
if 0 <= current_active_window_idx < len(all_windows):
cw = all_windows[current_active_window_idx]
window_id = cw.overlay_for or cw.id
pair = self.pairs_root.pair_for_window(window_id)
if pair is not None:
pair.split_and_add(window_id, window.id, horizontal, after)
active_window_idx = current_active_window_idx
if after:
active_window_idx += 1
for i in range(len(all_windows), active_window_idx, -1):
self.swap_windows_in_os_window(i, i - 1)
all_windows.insert(active_window_idx, window)
if active_window_idx is None:
active_window_idx = len(all_windows)
all_windows.append(window)
return active_window_idx
# }}} # }}}