import math from PyQt6.QtCore import * from PyQt6.QtGui import * from PyQt6.QtWidgets import * from line import Line from logFileModel import LogFileModel class BigText(QWidget): _byte_offset = 0 _left_offset = 0 _selection_start_byte = 0 _selection_end_byte = 0 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 = [] def paintEvent(self, event: QPaintEvent) -> None: self.draw() def mousePressEvent(self, e: QMouseEvent) -> None: if e.buttons() == Qt.MouseButton.LeftButton: self._selection_start_byte = self.to_byte_offset(e) self._selection_end_byte = self._selection_start_byte self.update() def mouseMoveEvent(self, e: QMouseEvent): current_byte = self.to_byte_offset(e) if self._selection_end_byte != current_byte: self._selection_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) 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 hightlight(self, painter: QPainter,rect: QRect, color: QColor): old_brush = painter.brush() old_pen = painter.pen() painter.setBrush(color) painter.setPen(Qt.PenStyle.NoPen) 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))