Start work on implementing multiple tab management
This commit is contained in:
parent
26c7297de6
commit
6bfd6d6dbb
@ -220,8 +220,7 @@ class Boss(Thread):
|
||||
|
||||
def apply_pending_resize(self, w, h):
|
||||
viewport_size.width, viewport_size.height = w, h
|
||||
for tab in self.tab_manager:
|
||||
tab.relayout()
|
||||
self.tab_manager.resize()
|
||||
self.resize_gl_viewport = True
|
||||
self.pending_resize = False
|
||||
glfw_post_empty_event()
|
||||
@ -367,6 +366,7 @@ class Boss(Thread):
|
||||
tab.render()
|
||||
render_data = {window: window.char_grid.prepare_for_render(self.sprites) for window in tab.visible_windows() if not window.needs_layout}
|
||||
with self.cell_program:
|
||||
self.tab_manager.render(self.cell_program, self.sprites)
|
||||
for window, rd in render_data.items():
|
||||
if rd is not None:
|
||||
window.char_grid.render_cells(rd, self.cell_program, self.sprites)
|
||||
|
||||
@ -207,6 +207,15 @@ class Selection: # {{{
|
||||
# }}}
|
||||
|
||||
|
||||
def calculate_gl_geometry(window_geometry):
|
||||
dx, dy = 2 * cell_size.width / viewport_size.width, 2 * cell_size.height / viewport_size.height
|
||||
xmargin = window_geometry.left / viewport_size.width
|
||||
ymargin = window_geometry.top / viewport_size.height
|
||||
xstart = -1 + 2 * xmargin
|
||||
ystart = 1 - 2 * ymargin
|
||||
return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy)
|
||||
|
||||
|
||||
class CharGrid:
|
||||
|
||||
url_pat = re.compile('(?:http|https|file|ftp)://\S+', re.IGNORECASE)
|
||||
@ -237,12 +246,7 @@ class CharGrid:
|
||||
self.sprite_map_type = self.main_sprite_map = self.scroll_sprite_map = self.render_buf = None
|
||||
|
||||
def update_position(self, window_geometry):
|
||||
dx, dy = 2 * cell_size.width / viewport_size.width, 2 * cell_size.height / viewport_size.height
|
||||
xmargin = window_geometry.left / viewport_size.width
|
||||
ymargin = window_geometry.top / viewport_size.height
|
||||
xstart = -1 + 2 * xmargin
|
||||
ystart = 1 - 2 * ymargin
|
||||
self.screen_geometry = ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy)
|
||||
self.screen_geometry = calculate_gl_geometry(window_geometry)
|
||||
|
||||
def resize(self, window_geometry):
|
||||
self.update_position(window_geometry)
|
||||
|
||||
@ -3,10 +3,18 @@
|
||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from collections import deque
|
||||
from threading import Lock
|
||||
from ctypes import addressof
|
||||
|
||||
from .child import Child
|
||||
from .constants import get_boss, appname, shell_path, cell_size, queue_action
|
||||
from .fast_data_types import glfw_post_empty_event
|
||||
from .config import build_ansi_color_table
|
||||
from .constants import get_boss, appname, shell_path, cell_size, queue_action, viewport_size, WindowGeometry, GLuint
|
||||
from .fast_data_types import (
|
||||
glfw_post_empty_event, Screen, DECAWM, DATA_CELL_SIZE,
|
||||
ColorProfile, glUniform2ui, glUniform4f, glUniform1i, glUniform2f,
|
||||
glDrawArraysInstanced, GL_TRIANGLE_FAN
|
||||
)
|
||||
from .char_grid import calculate_gl_geometry
|
||||
from .layout import all_layouts
|
||||
from .borders import Borders
|
||||
from .window import Window
|
||||
@ -14,8 +22,9 @@ from .window import Window
|
||||
|
||||
class Tab:
|
||||
|
||||
def __init__(self, opts, args, session_tab=None):
|
||||
def __init__(self, opts, args, on_title_change, session_tab=None):
|
||||
self.opts, self.args = opts, args
|
||||
self.on_title_change = on_title_change
|
||||
self.enabled_layouts = list((session_tab or opts).enabled_layouts)
|
||||
self.borders = Borders(opts)
|
||||
self.windows = deque()
|
||||
@ -46,6 +55,10 @@ class Tab:
|
||||
def title(self):
|
||||
return getattr(self.active_window, 'title', appname)
|
||||
|
||||
def title_changed(self, window):
|
||||
if window is self.active_window:
|
||||
self.on_title_change(window.title)
|
||||
|
||||
def visible_windows(self):
|
||||
for w in self.windows:
|
||||
if w.is_visible_in_layout:
|
||||
@ -141,8 +154,28 @@ class TabManager:
|
||||
|
||||
def __init__(self, opts, args, startup_session):
|
||||
self.opts, self.args = opts, args
|
||||
self.tabs = [Tab(opts, args, t) for t in startup_session.tabs]
|
||||
self.tabs = [Tab(opts, args, self.title_changed, t) for t in startup_session.tabs]
|
||||
self.active_tab_idx = startup_session.active_tab_idx
|
||||
self.tabbar_lock = Lock()
|
||||
self.tabbar_dirty = True
|
||||
self.color_profile = ColorProfile()
|
||||
self.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
|
||||
|
||||
def resize(self):
|
||||
for tab in self.tabs:
|
||||
tab.relayout()
|
||||
ncells = viewport_size.width // cell_size.width
|
||||
s = Screen(None, 1, ncells)
|
||||
s.reset_mode(DECAWM)
|
||||
self.sprite_map_type = (GLuint * (s.lines * s.columns * DATA_CELL_SIZE))
|
||||
with self.tabbar_lock:
|
||||
self.sprite_map = self.sprite_map_type()
|
||||
self.tab_bar_screen = s
|
||||
self.tabbar_dirty = True
|
||||
margin = (viewport_size.width - ncells * cell_size.width) // 2
|
||||
self.screen_geometry = calculate_gl_geometry(WindowGeometry(
|
||||
margin, viewport_size.height - cell_size.height, viewport_size.width - margin, viewport_size.height, s.columns, s.lines))
|
||||
self.screen = s
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.tabs)
|
||||
@ -158,7 +191,46 @@ class TabManager:
|
||||
def tab_bar_height(self):
|
||||
return 0 if len(self.tabs) < 2 else cell_size.height
|
||||
|
||||
def title_changed(self, new_title):
|
||||
with self.tabbar_lock:
|
||||
self.tabbar_dirty = True
|
||||
|
||||
def remove(self, tab):
|
||||
' Must be called in the GUI thread '
|
||||
self.tabs.remove(tab)
|
||||
tab.destroy()
|
||||
|
||||
def update_tab_bar_data(self, sprites):
|
||||
s = self.tab_bar_screen
|
||||
for t in self.tabs:
|
||||
title = (t.title or appname)
|
||||
s.draw(title)
|
||||
if s.cursor.x > s.columns - 3:
|
||||
# TODO: Handle trailing wide character
|
||||
s.cursor.x = s.columns - 4
|
||||
s.draw('…')
|
||||
s.draw(' X┇')
|
||||
if s.cursor.x > s.columns - 5:
|
||||
s.draw('…')
|
||||
break
|
||||
s.update_cell_data(
|
||||
sprites.backend, self.color_profile, addressof(self.sprite_map), self.default_fg, self.default_bg, True)
|
||||
if self.buffer_id is None:
|
||||
self.buffer_id = sprites.add_sprite_map()
|
||||
sprites.set_sprite_map(self.buffer_id, self.sprite_map)
|
||||
|
||||
def render(self, cell_program, sprites):
|
||||
if not hasattr(self, 'screen_geometry') or len(self.tabs) < 2:
|
||||
return
|
||||
with self.tabbar_lock:
|
||||
if self.tabbar_dirty:
|
||||
self.update_tab_bar_data(sprites)
|
||||
sprites.bind_sprite_map(self.buffer_id)
|
||||
ul, sg = cell_program.uniform_location, self.screen_geometry
|
||||
ul = cell_program.uniform_location
|
||||
glUniform2ui(ul('dimensions'), sg.xnum, sg.ynum)
|
||||
glUniform4f(ul('steps'), sg.xstart, sg.ystart, sg.dx, sg.dy)
|
||||
glUniform1i(ul('sprites'), sprites.sampler_num)
|
||||
glUniform1i(ul('sprite_map'), sprites.buffer_sampler_num)
|
||||
glUniform2f(ul('sprite_layout'), *(sprites.layout))
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, sg.xnum * sg.ynum)
|
||||
|
||||
@ -115,6 +115,9 @@ class Window:
|
||||
|
||||
def title_changed(self, new_title):
|
||||
self.title = sanitize_title(new_title or appname)
|
||||
t = self.tabref()
|
||||
if t is not None:
|
||||
t.title_changed(self)
|
||||
glfw_post_empty_event()
|
||||
|
||||
def icon_changed(self, new_icon):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user