somewhat working state

This commit is contained in:
2024-07-06 10:22:22 +02:00
parent 9c64acf77e
commit 00d4f2317a

View File

@@ -9,9 +9,9 @@ from io import TextIOWrapper
from typing import List from typing import List
from PySide6 import QtCore, QtGui from PySide6 import QtCore, QtGui
from PySide6.QtGui import QPaintEvent, QPainter, QFont, QFontMetrics, QColor from PySide6.QtGui import QPaintEvent, QPainter, QFont, QFontMetrics, QColor, QBrush
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QStatusBar from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QStatusBar
from PySide6.QtCore import QTimer, QPoint, Qt from PySide6.QtCore import QTimer, QPoint, Qt, QRect, QLine
import sys import sys
from src.pluginregistry import PluginRegistry from src.pluginregistry import PluginRegistry
import gettext import gettext
@@ -100,7 +100,7 @@ class LineType(enum.IntEnum):
class Line: class Line:
def __init__(self, byte_offset: int, byte_end: int, text: str, type: LineType = LineType.Full): def __init__(self, byte_offset: int, byte_end: int, text: str, bytes: str, type: LineType = LineType.Full):
""" """
:type byte_offset: int the offset of the first byte of this line :type byte_offset: int the offset of the first byte of this line
:type byte_end: int the offset of the last byte of this line :type byte_end: int the offset of the last byte of this line
@@ -110,6 +110,7 @@ class Line:
self._byte_offset = byte_offset self._byte_offset = byte_offset
self._byte_end = byte_end self._byte_end = byte_end
self._text = text self._text = text
self._bytes = bytes
self._type = type self._type = type
def byte_offset(self) -> int: def byte_offset(self) -> int:
@@ -121,6 +122,9 @@ class Line:
def text(self) -> str: def text(self) -> str:
return self._text return self._text
def bytes(self) -> str:
return self._bytes
def type(self) -> LineType: def type(self) -> LineType:
return self._type return self._type
@@ -168,7 +172,7 @@ class FileModel:
decoded_line = line.decode(encoding, errors="replace") decoded_line = line.decode(encoding, errors="replace")
line_type = LineType.Begin if previous_line_type == LineType.End or previous_line_type == LineType.Full else LineType.Middle line_type = LineType.Begin if previous_line_type == LineType.End or previous_line_type == LineType.Full else LineType.Middle
return Line(start_of_line, end_of_line, decoded_line, line_type) return Line(start_of_line, end_of_line, decoded_line, line, line_type)
elif pos_of_newline >= 0: elif pos_of_newline >= 0:
start_of_line = read_offset start_of_line = read_offset
end_of_line = read_offset + pos_of_newline end_of_line = read_offset + pos_of_newline
@@ -176,7 +180,7 @@ class FileModel:
decoded_line = line.decode(encoding, errors="replace") decoded_line = line.decode(encoding, errors="replace")
line_type = LineType.Full if previous_line_type == LineType.End or previous_line_type == LineType.Full else LineType.End line_type = LineType.Full if previous_line_type == LineType.End or previous_line_type == LineType.Full else LineType.End
return Line(start_of_line, end_of_line, decoded_line, line_type) return Line(start_of_line, end_of_line, decoded_line, line, line_type)
else: else:
# line does not end in this buffer # line does not end in this buffer
@@ -202,10 +206,32 @@ class FileModel:
return lines return lines
class Selection:
def __init__(self, byte_start: int, byte_end: int, text_before_selection: str, selected_text: str):
self.byte_start = byte_start
self.byte_end = byte_end
self.text_before_selection = text_before_selection
self.selected_text = selected_text
def __repr__(self):
return f"{self.byte_start}:{self.byte_end} ({self.text_before_selection}:{self.selected_text})"
def min_byte(self) -> int:
return self.byte_start if self.byte_start < self.byte_end else self.byte_end
def max_byte(self) -> int:
return self.byte_end if self.byte_start < self.byte_end else self.byte_start
class BiggerText(QWidget): class BiggerText(QWidget):
def __init__(self, ): def __init__(self, ):
super(BiggerText, self).__init__() super(BiggerText, self).__init__()
self.selection = Selection(0, 0, "", "")
self._encoding = "utf8"
self.file_model: FileModel = FileModel("testdata/testset.txt")
# font ="Andale Mono" # font ="Andale Mono"
# font = "JetBrains Mono" # font = "JetBrains Mono"
# font = "Monospace" # not found # font = "Monospace" # not found
@@ -220,42 +246,124 @@ class BiggerText(QWidget):
def mousePressEvent(self, e: QtGui.QMouseEvent) -> None: def mousePressEvent(self, e: QtGui.QMouseEvent) -> None:
if e.buttons() == Qt.MouseButton.LeftButton and e.modifiers() == Qt.KeyboardModifier.NoModifier: if e.buttons() == Qt.MouseButton.LeftButton and e.modifiers() == Qt.KeyboardModifier.NoModifier:
offset = self.to_byte_offset(e.pos()) (byte_offset, char_in_line, selected_text) = self.to_byte_offset(e.position())
self.selection.byte_start = byte_offset
self.selection.byte_end = byte_offset + 1
self.selection.selected_text = selected_text
self.mouse_pressed = True
return return
def to_byte_offset(self, pos: QPoint): def mouseReleaseEvent(self, event):
line = self.y_pos_to_line(pos.y()) self.mouse_pressed = False
def y_pos_to_line(self, y: int) -> int: def mouseMoveEvent(self, event):
if self.mouse_pressed:
(byte_offset, char_in_line, text_before_selection) = self.to_byte_offset(event.position())
self.selection.byte_end = byte_offset + 1
self.selection.text_before_selection = text_before_selection
print(f"selection: {self.selection}")
self.update()
def to_byte_offset(self, pos: QPoint) -> (int, int, str):
line_number = self.y_pos_to_line_number_on_screen(pos.y())
w = self.font_metric.horizontalAdvanceChar('')
line = self.lines_to_render[line_number]
text: str = line.text()
text = text.replace("\n", "").replace("\r", "")
elidedText = self.font_metric.elidedText(text + "………", Qt.TextElideMode.ElideRight, pos.x() + w,
Qt.TextFlag.TextWrapAnywhere)
elidedText = elidedText[0:-1] if elidedText.endswith('') else elidedText # remove the trailing '…'
byte = line.byte_offset() + len(elidedText.encode("utf8"))
print(
f"line: {line_number} elidetText: '{elidedText}' byte: {byte} char_in_line: {len(elidedText)}")
return byte, len(elidedText), elidedText
def _text_left_of_pos(x: int, text: str, font_metric: QFontMetrics):
w = font_metric.horizontalAdvanceChar('')
elidedText = font_metric.elidedText(text, Qt.TextElideMode.ElideRight, x + w,
Qt.TextFlag.TextWrapAnywhere)
elidedText = elidedText[0:-1] if elidedText.endswith('') else elidedText # remove the trailing '…'
bounding_box_elided = font_metric.boundingRect(elidedText)
if len(elidedText) + 1 < len(text): # there is a next character
elidet_text_plus_one_char = text[0:len(elidedText) + 1]
print(f"elidet_text_plus_one_char: {elidet_text_plus_one_char}")
bounding_box_elided_plus_one = font_metric.boundingRect(elidet_text_plus_one_char)
diff = bounding_box_elided_plus_one.width() - bounding_box_elided.width()
if bounding_box_elided.width() + diff / 2 >= x:
return elidet_text_plus_one_char
else:
return elidedText
return elidedText
def y_pos_to_line_number_on_screen(self, y: int) -> int:
return int(y / self.char_height) return int(y / self.char_height)
def paintEvent(self, event: QPaintEvent) -> None: def paintEvent(self, event: QPaintEvent) -> None:
start_ns = time.process_time_ns() start_ns = time.process_time_ns()
painter = QPainter(self) painter = QPainter(self)
font = painter.font() font = painter.font()
font.setPointSize(20) font.setPointSize(25)
painter.setFont(font) painter.setFont(font)
font_metric: QFontMetrics = painter.fontMetrics() # ---
self.char_height = font_metric.height()
lines_to_render = [ painter.drawLine(QLine(273, 0, 273, self.height()))
"im0 ひらがな 王 フーバー 🔴🟢 7²", # ---
"iiiiiiiiii",
"", self.font_metric: QFontMetrics = painter.fontMetrics()
"12345678", self.char_height = self.font_metric.height()
"nonspacing marks:", lines_to_read = self.height() / self.char_height + 1
"next line consists of a%CC%88",
"äääääääääääääääääääääääääääääää|", self.lines_to_render: [Line] = self.file_model.read(0, lines_to_read, 200, self._encoding)
"アンドレアス",
"アンドレアス"
]
painter.setPen(QColor(0, 0, 0)) painter.setPen(QColor(0, 0, 0))
line_on_screen = 1 line_on_screen = 1
for line in lines_to_render:
painter.drawText(QPoint(0, line_on_screen * char_height), line) for line in self.lines_to_render:
x_start = -1
x_end = -1
# selection starts before line
if self.selection.min_byte() < line.byte_offset():
x_start = 0
# selection starts in line
if line.byte_offset() <= self.selection.min_byte() <= line.byte_end():
left_offset_in_bytes = self.selection.min_byte() - line.byte_offset()
bytes = line.bytes()[0:left_offset_in_bytes]
x_start = self.font_metric.boundingRect(bytes.decode(self._encoding, errors="replace")).width()
# selection ends after line
if self.selection.max_byte() > line.byte_end():
x_end = self.width()
# selection ends in line
if line.byte_offset() <= self.selection.max_byte() <= line.byte_end():
left_offset_in_bytes = self.selection.max_byte() - line.byte_offset()
bytes = line.bytes()[0:left_offset_in_bytes]
x_end = self.font_metric.boundingRect(bytes.decode(self._encoding, errors="replace")).width() - x_start
if x_start >= 0 and x_end >= 0:
print(f"highlighting in line {line_on_screen} -- x_start: {x_start} -> x_end: {x_end}")
prev_brush = painter.brush()
prev_pen = painter.pen()
painter.setBrush(QBrush(QColor(0, 255, 255)))
painter.setPen(QColor(0, 0, 0, 0))
painter.drawRect(
QRect(x_start, int(line_on_screen * self.char_height + int(self.char_height * 0.1)), x_end,
-self.char_height))
painter.setBrush(prev_brush)
painter.setPen(prev_pen)
painter.drawText(QPoint(0, line_on_screen * self.char_height), line.text())
line_on_screen = line_on_screen + 1 line_on_screen = line_on_screen + 1
painter.end() painter.end()