diff --git a/kittens/icat/main.py b/kittens/icat/main.py index 038f4f96b..e2c2464b5 100755 --- a/kittens/icat/main.py +++ b/kittens/icat/main.py @@ -22,7 +22,6 @@ from ..tui.images import ( ) from ..tui.operations import clear_images_on_screen, serialize_gr_command -screen_size = None OPTIONS = '''\ --align type=choices @@ -97,6 +96,16 @@ Do not print out anything to stdout during operation. ''' +screen_size = None + + +def get_screen_size(): + global screen_size + if screen_size is None: + screen_size = screen_size_function() + return screen_size() + + def options_spec(): if not hasattr(options_spec, 'ans'): options_spec.ans = OPTIONS.format( @@ -122,7 +131,7 @@ def calculate_in_cell_x_offset(width, cell_width, align): def set_cursor(cmd, width, height, align): - ss = screen_size() + ss = get_screen_size() cw = int(ss.width / ss.cols) num_of_cells_needed = int(ceil(width / cw)) if num_of_cells_needed > ss.cols: @@ -143,7 +152,7 @@ def set_cursor(cmd, width, height, align): def set_cursor_for_place(place, cmd, width, height, align): x = place.left + 1 - ss = screen_size() + ss = get_screen_size() cw = int(ss.width / ss.cols) num_of_cells_needed = int(ceil(width / cw)) cmd['X'] = calculate_in_cell_x_offset(width, cw, align) @@ -189,7 +198,7 @@ def show(outfile, width, height, fmt, transmit_mode='t', align='center', place=N def process(path, args, is_tempfile): m = identify(path) - ss = screen_size() + ss = get_screen_size() available_width = args.place.width * (ss.width / ss.cols) if args.place else ss.width available_height = args.place.height * (ss.height / ss.rows) if args.place else 10 * m.height needs_scaling = m.width > available_width or m.height > available_height @@ -334,7 +343,7 @@ def main(args=sys.argv): sys.stdin.close() sys.stdin = open(os.ctermid(), 'r') - screen_size = screen_size_function() + screen_size = get_screen_size() signal.signal(signal.SIGWINCH, lambda signum, frame: setattr(screen_size, 'changed', True)) if screen_size().width == 0: if args.detect_support: diff --git a/kitty/fonts.c b/kitty/fonts.c index 8059685bd..a2a0b3a9e 100644 --- a/kitty/fonts.c +++ b/kitty/fonts.c @@ -543,6 +543,14 @@ in_symbol_maps(FontGroup *fg, char_type ch) { } +// Decides which 'font' to use for a given cell. +// +// Possible results: +// - NO_FONT +// - MISSING_FONT +// - BLANK_FONT +// - BOX_FONT +// - an index in the fonts list static inline ssize_t font_for_cell(FontGroup *fg, CPUCell *cpu_cell, GPUCell *gpu_cell, bool *is_fallback_font, bool *is_emoji_presentation) { *is_fallback_font = false; @@ -558,6 +566,10 @@ START_ALLOW_CASE_RANGE case 0x2574 ... 0x259f: case 0xe0b0 ... 0xe0b4: case 0xe0b6: + case 0xe0b8: //  + case 0xe0ba: //  + case 0xe0bc: //  + case 0xe0be: //  return BOX_FONT; default: ans = in_symbol_maps(fg, cpu_cell->ch); @@ -586,14 +598,15 @@ set_sprite(GPUCell *cell, sprite_index x, sprite_index y, sprite_index z) { cell->sprite_x = x; cell->sprite_y = y; cell->sprite_z = z; } +// Gives a unique (arbitrary) id to a box glyph static inline glyph_index box_glyph_id(char_type ch) { START_ALLOW_CASE_RANGE switch(ch) { case 0x2500 ... 0x259f: - return ch - 0x2500; + return ch - 0x2500; // IDs from 0x00 to 0x9f case 0xe0b0 ... 0xe0d4: - return 0xa0 + ch - 0xe0b0; + return 0xa0 + ch - 0xe0b0; // IDs from 0xa0 to 0xc4 default: return 0xff; } diff --git a/kitty/fonts/box_drawing.py b/kitty/fonts/box_drawing.py index 88f050a96..e87109612 100644 --- a/kitty/fonts/box_drawing.py +++ b/kitty/fonts/box_drawing.py @@ -2,6 +2,11 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2017, Kovid Goyal +# +# NOTE: to add a new glyph, add an entry to the `box_chars` dict, then update +# the functions `font_for_cell` and `box_glyph_id` in `kitty/fonts.c`. +# + import math from functools import partial as p from itertools import repeat @@ -172,6 +177,22 @@ def triangle(buf, width, height, left=True): fill_region(buf, width, height, xlimits) +def corner_triangle(buf, width, height, corner): + if corner == 'top-right' or corner == 'bottom-left': + diagonal_y = line_equation(0, 0, width - 1, height - 1) + if corner == 'top-right': + xlimits = [(0, diagonal_y(x)) for x in range(width)] + elif corner == 'bottom-left': + xlimits = [(diagonal_y(x), height - 1) for x in range(width)] + else: + diagonal_y = line_equation(width - 1, 0, 0, height - 1) + if corner == 'top-left': + xlimits = [(0, diagonal_y(x)) for x in range(width)] + elif corner == 'bottom-right': + xlimits = [(diagonal_y(x), height - 1) for x in range(width)] + fill_region(buf, width, height, xlimits) + + def antialiased_1px_line(buf, width, height, p1, p2): # Draw an antialiased line using the Wu algorithm x1, y1 = p1 @@ -552,6 +573,10 @@ box_chars = { '': [p(D, left=False)], '': [p(half_cross_line, which='tl'), p(half_cross_line, which='bl')], '': [p(half_cross_line, which='tr'), p(half_cross_line, which='br')], + '': [p(corner_triangle, corner='bottom-left')], + '': [p(corner_triangle, corner='bottom-right')], + '': [p(corner_triangle, corner='top-left')], + '': [p(corner_triangle, corner='top-right')], '═': [dhline], '║': [dvline], '╞': [vline, p(half_dhline, which='right')], @@ -647,60 +672,60 @@ def render_missing_glyph(buf, width, height): def test_char(ch, sz=48): - # kitty +runpy "from kitty.fonts.box_drawing import test_char; import sys; test_char('XXX')" + # kitty +runpy "from kitty.fonts.box_drawing import test_char; test_char('XXX')" from .render import display_bitmap, setup_for_testing from kitty.fast_data_types import concat_cells, set_send_sprite_to_gpu - width, height = setup_for_testing('monospace', sz)[1:] - buf = bytearray(width * height) - try: - render_box_char(ch, buf, width, height) + with setup_for_testing('monospace', sz) as (_, width, height): + buf = bytearray(width * height) + try: + render_box_char(ch, buf, width, height) - def join_cells(*cells): - cells = tuple(bytes(x) for x in cells) - return concat_cells(width, height, False, cells) + def join_cells(*cells): + cells = tuple(bytes(x) for x in cells) + return concat_cells(width, height, False, cells) - rgb_data = join_cells(buf) - display_bitmap(rgb_data, width, height) - print() - finally: - set_send_sprite_to_gpu(None) + rgb_data = join_cells(buf) + display_bitmap(rgb_data, width, height) + print() + finally: + set_send_sprite_to_gpu(None) def test_drawing(sz=48, family='monospace'): from .render import display_bitmap, setup_for_testing from kitty.fast_data_types import concat_cells, set_send_sprite_to_gpu - width, height = setup_for_testing(family, sz)[1:] - space = bytearray(width * height) + with setup_for_testing(family, sz) as (_, width, height): + space = bytearray(width * height) - def join_cells(cells): - cells = tuple(bytes(x) for x in cells) - return concat_cells(width, height, False, cells) + def join_cells(cells): + cells = tuple(bytes(x) for x in cells) + return concat_cells(width, height, False, cells) - def render_chr(ch): - if ch in box_chars: - cell = bytearray(len(space)) - render_box_char(ch, cell, width, height) - return cell - return space + def render_chr(ch): + if ch in box_chars: + cell = bytearray(len(space)) + render_box_char(ch, cell, width, height) + return cell + return space - pos = 0x2500 - rows = [] - space_row = join_cells(repeat(space, 32)) + pos = 0x2500 + rows = [] + space_row = join_cells(repeat(space, 32)) - try: - for r in range(10): - row = [] - for i in range(16): - row.append(render_chr(chr(pos))) - row.append(space) - pos += 1 - rows.append(join_cells(row)) - rows.append(space_row) - rgb_data = b''.join(rows) - width *= 32 - height *= len(rows) - assert len(rgb_data) == width * height * 4, '{} != {}'.format(len(rgb_data), width * height * 4) - display_bitmap(rgb_data, width, height) - finally: - set_send_sprite_to_gpu(None) + try: + for r in range(10): + row = [] + for i in range(16): + row.append(render_chr(chr(pos))) + row.append(space) + pos += 1 + rows.append(join_cells(row)) + rows.append(space_row) + rgb_data = b''.join(rows) + width *= 32 + height *= len(rows) + assert len(rgb_data) == width * height * 4, '{} != {}'.format(len(rgb_data), width * height * 4) + display_bitmap(rgb_data, width, height) + finally: + set_send_sprite_to_gpu(None)