mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 22:28:24 +02:00
Use a rendered text cache for faster painting
This commit is contained in:
@@ -120,13 +120,13 @@ def validate_font(opts: Options):
|
||||
|
||||
def build_ansi_color_tables(opts: Options) -> Tuple[dict, dict]:
|
||||
def col(i):
|
||||
return QColor(getattr(opts, 'color{}'.format(i)))
|
||||
return QColor(getattr(opts, 'color{}'.format(i))).getRgb()[:3]
|
||||
fg = {30 + i: col(i) for i in range(8)}
|
||||
fg[39] = opts.foreground
|
||||
fg.update({90 + i: col(i + 8) for i in range(8)})
|
||||
fg[99] = opts.foreground_bold
|
||||
fg[99] = opts.foreground_bold.getRgb()[:3]
|
||||
bg = {40 + i: col(i) for i in range(8)}
|
||||
bg[49] = opts.background
|
||||
bg[49] = opts.background.getRgb()[:3]
|
||||
bg.update({100 + i: col(i + 8) for i in range(8)})
|
||||
build_ansi_color_tables.fg, build_ansi_color_tables.bg = fg, bg
|
||||
build_ansi_color_tables(defaults)
|
||||
|
||||
@@ -6,8 +6,6 @@ import array
|
||||
from typing import Tuple, Dict, Union, Iterator, Sequence
|
||||
from itertools import repeat
|
||||
|
||||
from PyQt5.QtGui import QColor
|
||||
|
||||
from pyte.graphics import FG_BG_256
|
||||
from .config import fg_color_table, bg_color_table
|
||||
|
||||
@@ -305,19 +303,19 @@ class Line:
|
||||
self.char[i] = (a << ATTRS_SHIFT) | (c & CHAR_MASK)
|
||||
|
||||
|
||||
def as_color(entry: int, color_table: Dict[int, QColor]) -> Union[QColor, None]:
|
||||
def as_color(entry: int, color_table: Dict[int, Tuple[int]]) -> Union[Tuple[int], None]:
|
||||
t = entry & 0xff
|
||||
if t == 1:
|
||||
r = (entry >> 8) & 0xff
|
||||
return color_table.get(r)
|
||||
if t == 2:
|
||||
r = (entry >> 8) & 0xff
|
||||
return QColor(*FG_BG_256[r])
|
||||
return FG_BG_256[r]
|
||||
if t == 3:
|
||||
r = (entry >> 8) & 0xff
|
||||
g = (entry >> 16) & 0xff
|
||||
b = (entry >> 24) & 0xff
|
||||
return QColor(r, g, b)
|
||||
return r, g, b
|
||||
|
||||
|
||||
def copy_char(src: Line, dest: Line, src_pos: int, dest_pos: int) -> None:
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from functools import lru_cache
|
||||
from typing import Tuple, Iterator, Sequence
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QTimer, QRect, Qt
|
||||
from PyQt5.QtGui import QColor, QPainter, QFont, QFontMetrics, QRegion, QPen
|
||||
from PyQt5.QtGui import QColor, QPainter, QFont, QFontMetrics, QRegion, QPen, QPixmap
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
from .config import build_ansi_color_tables, Options, fg_color_table, bg_color_table
|
||||
@@ -23,6 +24,20 @@ def ascii_width(fm: QFontMetrics) -> int:
|
||||
return ans
|
||||
|
||||
|
||||
@lru_cache(maxsize=2**11)
|
||||
def pixmap_for_text(text, color, default_fg, font, w, h, baseline):
|
||||
p = QPixmap(w, h)
|
||||
p.fill(Qt.transparent)
|
||||
fg = as_color(color & COL_MASK, fg_color_table()) or default_fg
|
||||
painter = QPainter(p)
|
||||
painter.setFont(font)
|
||||
painter.setPen(QPen(QColor(*fg)))
|
||||
painter.setRenderHints(QPainter.TextAntialiasing | QPainter.Antialiasing)
|
||||
painter.drawText(0, baseline, text)
|
||||
painter.end()
|
||||
return p
|
||||
|
||||
|
||||
class TerminalWidget(QWidget):
|
||||
|
||||
relayout_lines = pyqtSignal(object, object, object, object)
|
||||
@@ -46,14 +61,15 @@ class TerminalWidget(QWidget):
|
||||
|
||||
def apply_opts(self, opts):
|
||||
self.opts = opts
|
||||
pixmap_for_text.cache_clear()
|
||||
pal = self.palette()
|
||||
pal.setColor(pal.Window, QColor(opts.background))
|
||||
pal.setColor(pal.WindowText, QColor(opts.foreground))
|
||||
self.setPalette(pal)
|
||||
self.current_bg = pal.color(pal.Window)
|
||||
self.current_fg = pal.color(pal.WindowText)
|
||||
self.current_fg = pal.color(pal.WindowText).getRgb()[:3]
|
||||
build_ansi_color_tables(opts)
|
||||
f = QFont(opts.font_family)
|
||||
self.current_font = f = QFont(opts.font_family)
|
||||
f.setPointSizeF(opts.font_size)
|
||||
self.setFont(f)
|
||||
self.font_metrics = fm = QFontMetrics(self.font())
|
||||
@@ -139,7 +155,6 @@ class TerminalWidget(QWidget):
|
||||
return
|
||||
r = ev.region()
|
||||
p = QPainter(self)
|
||||
p.setRenderHints(p.TextAntialiasing | p.Antialiasing)
|
||||
|
||||
try:
|
||||
self.paint_cursor(p)
|
||||
@@ -158,6 +173,12 @@ class TerminalWidget(QWidget):
|
||||
x, y = wrap_cursor_position(self.cursor.x, self.cursor.y, len(self.line_positions), len(self.cell_positions))
|
||||
r = QRect(self.cell_positions[x], self.line_positions[y], self.cell_width, self.cell_height)
|
||||
self.last_drew_cursor_at = x, y
|
||||
line = self.linebuf[x]
|
||||
colors = line.basic_cell_data(y)[2]
|
||||
if colors & HAS_BG_MASK:
|
||||
bg = as_color(colors >> COL_SHIFT, bg_color_table())
|
||||
if bg is not None:
|
||||
painter.fillRect(r, QColor(*bg))
|
||||
if self.hasFocus():
|
||||
painter.fillRect(r, self.cursor_color)
|
||||
else:
|
||||
@@ -168,23 +189,18 @@ class TerminalWidget(QWidget):
|
||||
line = self.linebuf[row]
|
||||
ch, attrs, colors = line.basic_cell_data(col)
|
||||
x, y = self.cell_positions[col], self.line_positions[row]
|
||||
if colors & HAS_BG_MASK:
|
||||
if colors & HAS_BG_MASK and (col != self.last_drew_cursor_at[0] or row != self.last_drew_cursor_at[1]):
|
||||
bg = as_color(colors >> COL_SHIFT, bg_color_table())
|
||||
if bg is not None:
|
||||
r = QRect(x, y, self.cell_width, self.cell_height)
|
||||
painter.fillRect(r, bg)
|
||||
painter.fillRect(r, QColor(*bg))
|
||||
if ch == 0 or ch == 32:
|
||||
# An empty cell
|
||||
pass
|
||||
else:
|
||||
text = chr(ch) + line.combining_chars.get(col, '')
|
||||
fg = as_color(colors & COL_MASK, fg_color_table())
|
||||
if fg is not None:
|
||||
painter.save()
|
||||
painter.setPen(QPen(fg))
|
||||
painter.drawText(x, y + self.baseline_offset, text)
|
||||
if fg is not None:
|
||||
painter.restore()
|
||||
p = pixmap_for_text(text, colors, self.current_fg, self.current_font, self.cell_width * 2, self.cell_height, self.baseline_offset)
|
||||
painter.drawPixmap(x, y, p)
|
||||
|
||||
def keyPressEvent(self, ev):
|
||||
mods = ev.modifiers()
|
||||
|
||||
Reference in New Issue
Block a user