139 lines
5.5 KiB
Python
139 lines
5.5 KiB
Python
import math
|
|
from typing import Optional
|
|
import PyQt6.QtGui
|
|
from PyQt6.QtCore import *
|
|
from PyQt6.QtGui import *
|
|
from PyQt6.QtWidgets import *
|
|
|
|
from highlight import Highlight
|
|
from highlight_selection import HightlightSelection
|
|
from highlighted_range import HighlightedRange
|
|
from line import Line
|
|
from logFileModel import LogFileModel
|
|
|
|
|
|
class BigText(QWidget):
|
|
_byte_offset = 0
|
|
_left_offset = 0
|
|
|
|
highlights : [Highlight] = []
|
|
|
|
def __init__(self, model: LogFileModel):
|
|
super(BigText, self).__init__()
|
|
self.model = model
|
|
self.font = QFont("monospace", 20)
|
|
self.update_font_metrics(QPainter(self))
|
|
self.lines = []
|
|
self.selection_highlight= HightlightSelection(0,0)
|
|
self.highlights = [self.selection_highlight]
|
|
|
|
def paintEvent(self, event: QPaintEvent) -> None:
|
|
self.draw()
|
|
|
|
def mousePressEvent(self, e: QMouseEvent) -> None:
|
|
if e.buttons() == Qt.MouseButton.LeftButton:
|
|
offset = self.to_byte_offset(e)
|
|
self.selection_highlight.set_start(offset)
|
|
self.selection_highlight.set_end_byte(offset)
|
|
self.update()
|
|
|
|
def mouseMoveEvent(self, e: QMouseEvent):
|
|
current_byte = self.to_byte_offset(e)
|
|
|
|
if self.selection_highlight.end_byte != current_byte:
|
|
self.selection_highlight.set_end_byte(current_byte)
|
|
self.update()
|
|
#print("-> %s,%s" %(self._selection_start_byte, self._selection_end_byte))
|
|
|
|
def to_byte_offset(self, e: QMouseEvent) -> int:
|
|
line_number = int(e.pos().y() / self.char_height)
|
|
|
|
if line_number < len(self.lines):
|
|
line = self.lines[line_number]
|
|
char_in_line = round(e.pos().x() / self.char_width) + self._left_offset
|
|
char_in_line = min(char_in_line, line.length())
|
|
#print("%s in line %s" % (char_in_line, line_number))
|
|
|
|
current_byte = line.byte_offset() + char_in_line
|
|
#print("%s + %s = %s" % (line.byte_offset(), char_in_line, current_byte))
|
|
else:
|
|
current_byte = self.model.byte_count()
|
|
return current_byte
|
|
|
|
def draw(self):
|
|
painter = QPainter()
|
|
painter.begin(self)
|
|
painter.setFont(self.font)
|
|
painter.setPen(QColor(0, 0, 0))
|
|
self.update_font_metrics(painter)
|
|
|
|
lines_to_show = self.height() / (self.fontMetrics().height())
|
|
self.lines = self.model.data(self._byte_offset, lines_to_show)
|
|
|
|
# draw hightlights first - some characters may overlap to the next line
|
|
# by drawing the background hightlights first we prevent that the hightlight
|
|
# draws over a character
|
|
y_line_offset = self.char_height;
|
|
for l in self.lines:
|
|
#if l.intersects(self._selection_start_byte, self._selection_end_byte):
|
|
# self.draw_selection(painter, l, y_line_offset)
|
|
for h in self.highlights:
|
|
optional_highlight_range = h.compute_highlight(l)
|
|
if optional_highlight_range:
|
|
self.draw_highlight(optional_highlight_range, painter, y_line_offset)
|
|
y_line_offset = y_line_offset + self.char_height
|
|
|
|
y_line_offset = self.char_height;
|
|
for l in self.lines:
|
|
painter.drawText(0, y_line_offset, l.line())
|
|
y_line_offset = y_line_offset + self.char_height
|
|
|
|
painter.end()
|
|
|
|
def draw_selection(self, painter: QPainter, line: Line, y_line_offset: int):
|
|
hightlight_color = QColor(255, 255, 0)
|
|
|
|
if line.includes_byte(self._selection_start_byte):
|
|
x1 = (self._selection_start_byte - line.byte_offset() - self._left_offset) * self.char_width
|
|
else:
|
|
x1 = 0
|
|
|
|
if line.includes_byte(self._selection_end_byte):
|
|
width = (self._selection_end_byte - line.byte_offset() - self._left_offset) * self.char_width - x1
|
|
#print("char in line: %d -> width: %d" % (self._selection_end_byte - line.byte_offset() - self._left_offset, width))
|
|
else:
|
|
width = len(line.line().rstrip()) * self.char_width -x1
|
|
|
|
y1 = y_line_offset- self.char_height + self.char_height / 7
|
|
height = self.char_height
|
|
rect = QRect(x1,y1,width,height)
|
|
#print(rect)
|
|
self.hightlight(painter,rect , hightlight_color)
|
|
|
|
def draw_highlight(self, highlight: HighlightedRange, painter: QPainter, y_line_offset:int):
|
|
x1 = highlight.get_start()*self.char_width
|
|
width = highlight.get_width()*self.char_width
|
|
|
|
y1 = y_line_offset- self.char_height + self.char_height / 7
|
|
height = self.char_height
|
|
rect = QRect(x1,y1,width,height)
|
|
#print(rect)
|
|
self.hightlight(painter,rect , highlight.get_brush(), highlight.get_pen())
|
|
|
|
def hightlight(self, painter: QPainter,rect: QRect, brush: QBrush, pen:QPen):
|
|
old_brush = painter.brush()
|
|
old_pen = painter.pen()
|
|
painter.setBrush(brush)
|
|
painter.setPen(pen)
|
|
painter.drawRoundedRect(rect, 3.0, 3.0)
|
|
painter.setBrush(old_brush)
|
|
painter.setPen(old_pen)
|
|
|
|
def update_font_metrics(self, painter: QPainter):
|
|
fm: QFontMetrics = painter.fontMetrics()
|
|
self.char_height = fm.height()
|
|
self.char_width = fm.averageCharWidth()# all chars have same with for monospace font
|
|
text = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
|
self.char_width = fm.horizontalAdvance(text)/float(len(text))
|
|
#print("bounding rect: %s"%(boundingRect))
|
|
#print("font width=%s height=%s" % (self.char_width, self.char_height)) |