From 348fe4ada4a59640a29ed8325dcf100d060ab833 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 5 Jun 2017 23:57:17 +0530 Subject: [PATCH] Option for window padding Fixes #85 --- kitty/borders.py | 74 +++++++++++++++++++++++++++++++++++++++--------- kitty/config.py | 9 ++++-- kitty/kitty.conf | 3 ++ kitty/layout.py | 26 +++++++++++------ 4 files changed, 87 insertions(+), 25 deletions(-) diff --git a/kitty/borders.py b/kitty/borders.py index 5dc9c703a..d9e6e9fbf 100644 --- a/kitty/borders.py +++ b/kitty/borders.py @@ -5,6 +5,7 @@ from ctypes import addressof from itertools import chain from threading import Lock +from functools import partial from .constants import GLfloat, GLint, GLuint, viewport_size from .fast_data_types import GL_TRIANGLE_FAN, glMultiDrawArrays, glUniform3fv @@ -31,7 +32,8 @@ def as_rect(left, top, right, bottom, color=0): class BordersProgram(ShaderProgram): def __init__(self): - ShaderProgram.__init__(self, '''\ + ShaderProgram.__init__( + self, '''\ uniform vec3 colors[3]; in vec3 rect; out vec3 color; @@ -57,6 +59,30 @@ void main() { glUniform3fv(self.uniform_location('colors'), 3, addressof(color_buf)) +def border_maker(rects): + ' Create a function that will add all the rectangles for drawing a border to rects ' + + def r(l, t, b, r, color): + rects.extend(as_rect(l, t, b, r, color)) + + def vertical_edge(color, width, top, bottom, left): + r(left, top, left + width, bottom, color) + + def horizontal_edge(color, height, left, right, top): + r(left, top, right, top + height, color) + + def edge(func, color, sz, a, b): + return partial(func, color, sz, a, b) + + def border(color, sz, left, top, right, bottom): + horz = edge(horizontal_edge, color, sz, left, right) + horz(top), horz(bottom - sz) # top, bottom edges + vert = edge(vertical_edge, color, sz, top, bottom) + vert(left), vert(right - sz) # left, right edges + + return border + + class Borders: def __init__(self, opts): @@ -64,25 +90,42 @@ class Borders: self.lock = Lock() self.can_render = False self.border_width = pt_to_px(opts.window_border_width) + self.padding_width = pt_to_px(opts.window_padding_width) self.color_buf = (GLfloat * 9)( - *as_color(opts.background), - *as_color(opts.active_border_color), - *as_color(opts.inactive_border_color) - ) + *as_color(opts.background), *as_color(opts.active_border_color), + *as_color(opts.inactive_border_color)) - def __call__(self, windows, active_window, current_layout, extra_blank_rects, draw_window_borders=True): + def __call__( + self, + windows, + active_window, + current_layout, + extra_blank_rects, + draw_window_borders=True + ): rects = [] for br in chain(current_layout.blank_rects, extra_blank_rects): rects.extend(as_rect(*br)) - if draw_window_borders and self.border_width > 0: - bw = self.border_width + bw, pw = self.border_width, self.padding_width + fw = bw + pw + border = border_maker(rects) + + if fw > 0: for w in windows: g = w.geometry - color = 1 if w is active_window else 2 - rects.extend(as_rect(g.left - bw, g.top - bw, g.left, g.bottom + bw, color)) - rects.extend(as_rect(g.left - bw, g.top - bw, g.right + bw, g.top, color)) - rects.extend(as_rect(g.right, g.top - bw, g.right + bw, g.bottom + bw, color)) - rects.extend(as_rect(g.left - bw, g.bottom, g.right + bw, g.bottom + bw, color)) + if bw > 0 and draw_window_borders: + # Draw the border rectangles + color = 1 if w is active_window else 2 + border( + color, bw, g.left - fw, g.top - fw, g.right + fw, + g.bottom + fw) + # Now draw the blank rectangles over the padding region + if pw > 0: + color = 0 + border( + color, pw, g.left - pw, g.top - pw, g.right + pw, + g.bottom + pw) + with self.lock: self.num_of_rects = len(rects) // 12 self.rects = (GLfloat * len(rects))() @@ -106,4 +149,7 @@ class Borders: program.send_data(self.rects) program.set_colors(self.color_buf) self.is_dirty = False - glMultiDrawArrays(GL_TRIANGLE_FAN, addressof(self.starts), addressof(self.counts), self.num_of_rects) + glMultiDrawArrays( + GL_TRIANGLE_FAN, + addressof(self.starts), + addressof(self.counts), self.num_of_rects) diff --git a/kitty/config.py b/kitty/config.py index 7d5140d6f..c7ff5555a 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -150,6 +150,10 @@ def to_layout_names(raw): raise ValueError('The window layout {} is unknown'.format(p)) +def positive_float(x): + return max(0, float(x)) + + type_map = { 'scrollback_lines': int, 'scrollback_pager': shlex.split, @@ -160,8 +164,9 @@ type_map = { 'cursor_opacity': to_opacity, 'open_url_modifiers': to_open_url_modifiers, 'repaint_delay': int, - 'window_border_width': float, - 'window_margin_width': float, + 'window_border_width': positive_float, + 'window_margin_width': positive_float, + 'window_padding_width': positive_float, 'wheel_scroll_multiplier': float, 'visual_bell_duration': float, 'enable_audio_bell': to_bool, diff --git a/kitty/kitty.conf b/kitty/kitty.conf index 072d96684..a96b4d225 100644 --- a/kitty/kitty.conf +++ b/kitty/kitty.conf @@ -123,6 +123,9 @@ window_border_width 1 # The window margin (in pts) (blank area outside the border) window_margin_width 0 +# The window padding (in pts) (blank area between the text and the window border) +window_padding_width 0 + # The color for the border of the active window active_border_color #00ff00 diff --git a/kitty/layout.py b/kitty/layout.py index e7a858794..e786ee3f8 100644 --- a/kitty/layout.py +++ b/kitty/layout.py @@ -13,8 +13,9 @@ def available_height(): return viewport_size.height - get_boss().current_tab_bar_height -def layout_dimension(length, cell_length, number_of_windows=1, border_length=0, margin_length=0, left_align=False): +def layout_dimension(length, cell_length, number_of_windows=1, border_length=0, margin_length=0, padding_length=0, left_align=False): number_of_cells = length // cell_length + border_length += padding_length space_needed_for_border = number_of_windows * 2 * border_length space_needed_for_padding = number_of_windows * 2 * margin_length space_needed = space_needed_for_padding + space_needed_for_border @@ -47,6 +48,7 @@ class Layout: self.opts = opts self.border_width = border_width self.margin_width = pt_to_px(opts.window_margin_width) + self.padding_width = pt_to_px(opts.window_padding_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 = () @@ -80,9 +82,9 @@ def window_geometry(xstart, xnum, ystart, ynum): return WindowGeometry(left=xstart, top=ystart, xnum=xnum, ynum=ynum, right=xstart + cell_size.width * xnum, bottom=ystart + cell_size.height * ynum) -def layout_single_window(margin_length): - xstart, xnum = next(layout_dimension(viewport_size.width, cell_size.width, margin_length=margin_length)) - ystart, ynum = next(layout_dimension(available_height(), cell_size.height, margin_length=margin_length)) +def layout_single_window(margin_length, padding_length): + xstart, xnum = next(layout_dimension(viewport_size.width, cell_size.width, margin_length=margin_length, padding_length=padding_length)) + ystart, ynum = next(layout_dimension(available_height(), cell_size.height, margin_length=margin_length, padding_length=padding_length)) return window_geometry(xstart, xnum, ystart, ynum) @@ -124,7 +126,7 @@ class Stack(Layout): def __call__(self, windows, active_window_idx): self.blank_rects = [] - wg = layout_single_window(self.margin_width) + wg = layout_single_window(self.margin_width, self.padding_width) for i, w in enumerate(windows): w.is_visible_in_layout = i == active_window_idx w.set_geometry(wg) @@ -139,17 +141,23 @@ class Tall(Layout): def __call__(self, windows, active_window_idx): self.blank_rects = br = [] if len(windows) == 1: - wg = layout_single_window(self.margin_width) + wg = layout_single_window(self.margin_width, self.padding_width) windows[0].set_geometry(wg) self.blank_rects = blank_rects_for_window(windows[0]) return - xlayout = layout_dimension(viewport_size.width, cell_size.width, 2, self.border_width, margin_length=self.margin_width) + xlayout = layout_dimension( + viewport_size.width, cell_size.width, 2, self.border_width, + margin_length=self.margin_width, padding_length=self.padding_width) xstart, xnum = next(xlayout) - ystart, ynum = next(layout_dimension(available_height(), cell_size.height, 1, self.border_width, left_align=True, margin_length=self.margin_width)) + ystart, ynum = next(layout_dimension( + available_height(), cell_size.height, 1, self.border_width, left_align=True, + margin_length=self.margin_width, padding_length=self.padding_width)) windows[0].set_geometry(window_geometry(xstart, xnum, ystart, ynum)) vh = available_height() xstart, xnum = next(xlayout) - ylayout = layout_dimension(available_height(), cell_size.height, len(windows) - 1, self.border_width, left_align=True, margin_length=self.margin_width) + ylayout = layout_dimension( + available_height(), cell_size.height, len(windows) - 1, self.border_width, left_align=True, + margin_length=self.margin_width, padding_length=self.padding_width) for w, (ystart, ynum) in zip(islice(windows, 1, None), ylayout): w.set_geometry(window_geometry(xstart, xnum, ystart, ynum)) left_blank_rect(windows[0], br, vh), top_blank_rect(windows[0], br, vh), right_blank_rect(windows[-1], br, vh)