seems to be working quite great
This commit is contained in:
@@ -205,29 +205,48 @@ class FileModel:
|
||||
|
||||
return lines
|
||||
|
||||
def get_selection(self, byte_start: int, byte_end: int):
|
||||
with FileWithTimeout.open(self.file, 5, 'rb') as f:
|
||||
start = min(byte_start, byte_end)
|
||||
end = max(byte_start, byte_end)
|
||||
f.seek(start)
|
||||
b = f.read(end - start)
|
||||
# print(f"read {end - start } bytes -> {b}")
|
||||
return b.decode("utf-8", errors="replace")
|
||||
|
||||
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
|
||||
|
||||
class SelectionPos:
|
||||
def __init__(self, index: int, is_in_left_half: bool, num_bytes_of_char: int):
|
||||
self.index = index
|
||||
self.is_in_left_half = is_in_left_half
|
||||
self.num_bytes_of_char = num_bytes_of_char
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.byte_start}:{self.byte_end} ({self.text_before_selection}:{self.selected_text})"
|
||||
return f"{self.index}{'🞀' if self.is_in_left_half else '🞂'}({self.num_bytes_of_char})"
|
||||
|
||||
def pos(self):
|
||||
return self.index + (0 if self.is_in_left_half else self.num_bytes_of_char)
|
||||
|
||||
class Selection:
|
||||
def __init__(self, start: SelectionPos = SelectionPos(0, False, 0), end: SelectionPos = SelectionPos(0, False, 0)):
|
||||
self.start = start
|
||||
self.end = end
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.start}:{self.end}"
|
||||
def min_byte(self) -> int:
|
||||
return self.byte_start if self.byte_start < self.byte_end else self.byte_end
|
||||
return min(self.start.pos(), self.end.pos())
|
||||
|
||||
def max_byte(self) -> int:
|
||||
return self.byte_end if self.byte_start < self.byte_end else self.byte_start
|
||||
return max(self.start.pos(), self.end.pos())
|
||||
|
||||
class BiggerText(QWidget):
|
||||
|
||||
def __init__(self, ):
|
||||
super(BiggerText, self).__init__()
|
||||
|
||||
self.selection = Selection(0, 0, "", "")
|
||||
self.selection = Selection()
|
||||
self.mouse_pressed = False
|
||||
|
||||
self._encoding = "utf8"
|
||||
self.file_model: FileModel = FileModel("testdata/testset.txt")
|
||||
@@ -246,25 +265,57 @@ class BiggerText(QWidget):
|
||||
|
||||
def mousePressEvent(self, e: QtGui.QMouseEvent) -> None:
|
||||
if e.buttons() == Qt.MouseButton.LeftButton and e.modifiers() == Qt.KeyboardModifier.NoModifier:
|
||||
(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.selection.start = self.to_byte_offset(e.position())
|
||||
self.selection.end = self.selection.start
|
||||
self.mouse_pressed = True
|
||||
return
|
||||
self.update()
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
self.mouse_pressed = False
|
||||
|
||||
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.selection.end = self.to_byte_offset(event.position())
|
||||
#print(f"selection: {self.selection} -> {self.file_model.get_selection(self.selection.min_byte(), self.selection.max_byte())}")
|
||||
self.update()
|
||||
|
||||
def to_byte_offset(self, pos: QPoint) -> (int, int, str):
|
||||
def to_byte_offset(self, pos: QPoint) -> SelectionPos:
|
||||
|
||||
line_number = self.y_pos_to_line_number_on_screen(pos.y())
|
||||
|
||||
line = self.lines_to_render[line_number]
|
||||
text: str = line.text()
|
||||
text = text.replace("\n", "").replace("\r", "")
|
||||
|
||||
elided_text = self.elided_text(text, pos.x())
|
||||
byte_offset = line.byte_offset() + len(elided_text.encode("utf8"))
|
||||
|
||||
left_x_offset = self.font_metric.horizontalAdvance(elided_text)
|
||||
|
||||
next_char = ""
|
||||
pos_is_in_left_half = False
|
||||
bytes_of_char = 0
|
||||
if len(text) > len(elided_text): # has another character
|
||||
next_char = text[len(elided_text)]
|
||||
char_with = self.font_metric.horizontalAdvance(next_char)
|
||||
pos_is_in_left_half = pos.x() < (left_x_offset + char_with / 2)
|
||||
bytes_of_char = len(next_char.encode("utf8"))
|
||||
else:
|
||||
# the position is after the last character / behind the end of the line
|
||||
pass
|
||||
|
||||
print(
|
||||
f"to_byte_offset({pos.x()}, {pos.y()}) -> {left_x_offset} -- elided_text '{elided_text}' next_char '{next_char}' -> byte_offset {byte_offset} pos_is_in_left_half: {pos_is_in_left_half}")
|
||||
return SelectionPos(byte_offset, pos_is_in_left_half, bytes_of_char)
|
||||
|
||||
def elided_text(self, text: str, width: int):
|
||||
w = width + self.font_metric.horizontalAdvance("…")
|
||||
elided_text = self.font_metric.elidedText(text + "…", Qt.TextElideMode.ElideRight, w,
|
||||
Qt.TextFlag.TextWrapAnywhere)
|
||||
elided_text = elided_text[0:-1] if elided_text.endswith('…') else elided_text # remove the trailing '…'
|
||||
return elided_text
|
||||
|
||||
def to_byte_offset_old(self, pos: QPoint) -> (int, int, str):
|
||||
line_number = self.y_pos_to_line_number_on_screen(pos.y())
|
||||
|
||||
w = self.font_metric.horizontalAdvanceChar('…')
|
||||
@@ -286,15 +337,15 @@ class BiggerText(QWidget):
|
||||
Qt.TextFlag.TextWrapAnywhere)
|
||||
elidedText = elidedText[0:-1] if elidedText.endswith('…') else elidedText # remove the trailing '…'
|
||||
|
||||
bounding_box_elided = font_metric.boundingRect(elidedText)
|
||||
bounding_box_elided = font_metric.horizontalAdvance(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()
|
||||
# print(f"elidet_text_plus_one_char: {elidet_text_plus_one_char}")
|
||||
bounding_box_elided_plus_one = font_metric.horizontalAdvance(elidet_text_plus_one_char)
|
||||
diff = bounding_box_elided_plus_one - bounding_box_elided.width()
|
||||
|
||||
if bounding_box_elided.width() + diff / 2 >= x:
|
||||
if bounding_box_elided + diff / 2 >= x:
|
||||
return elidet_text_plus_one_char
|
||||
else:
|
||||
return elidedText
|
||||
@@ -313,7 +364,7 @@ class BiggerText(QWidget):
|
||||
|
||||
# ---
|
||||
|
||||
painter.drawLine(QLine(273, 0, 273, self.height()))
|
||||
#painter.drawLine(QLine(273, 0, 273, self.height()))
|
||||
# ---
|
||||
|
||||
# ----
|
||||
@@ -325,8 +376,32 @@ class BiggerText(QWidget):
|
||||
self.lines_to_render: [Line] = self.file_model.read(0, lines_to_read, 200, self._encoding)
|
||||
|
||||
painter.setPen(QColor(0, 0, 0))
|
||||
line_on_screen = 0
|
||||
|
||||
if False:
|
||||
line_on_screen = 0
|
||||
for line in self.lines_to_render:
|
||||
text = line.text()
|
||||
text = text.replace("\n", "").replace("\r", "")
|
||||
|
||||
start = 0
|
||||
end = 1
|
||||
|
||||
if start < len(text) and end <= len(text):
|
||||
x_start = self.font_metric.horizontalAdvance(text[0:start])
|
||||
# x_width = self.font_metric.horizontalAdvance(text[start:end])
|
||||
x_width = self.font_metric.boundingRect(text[start:end]).width()
|
||||
elidet_text = self.font_metric.elidedText(text, Qt.TextElideMode.ElideNone, 50,
|
||||
Qt.TextFlag.TextWrapAnywhere)
|
||||
# x_width = self.font_metric.boundingRect(elidet_text).width()
|
||||
print(f"-> {text[start:end]} width: {x_width} elidet_text: {elidet_text}")
|
||||
|
||||
y = int(line_on_screen * self.char_height)
|
||||
painter.setBrush(QBrush(QColor(233, 133, 233)))
|
||||
painter.drawRect(QRect(x_start, y, x_width, self.char_height))
|
||||
line_on_screen = line_on_screen + 1
|
||||
|
||||
if False:
|
||||
line_on_screen = 0
|
||||
for line in self.lines_to_render:
|
||||
text = line.text()
|
||||
text = text.replace("\n", "").replace("\r", "")
|
||||
@@ -345,6 +420,17 @@ class BiggerText(QWidget):
|
||||
painter.drawRect(QRect(0, y, r.x() + r.width(), self.char_height))
|
||||
line_on_screen = line_on_screen + 1
|
||||
|
||||
if False:
|
||||
line_on_screen = 0
|
||||
for line in self.lines_to_render:
|
||||
text = line.text()
|
||||
text = text.replace("\n", "").replace("\r", "")
|
||||
x = self.font_metric.horizontalAdvance(text)
|
||||
y = int(line_on_screen * self.char_height)
|
||||
painter.setBrush(QBrush(QColor(233, 233, 233)))
|
||||
painter.drawRect(QRect(0, y, x, self.char_height))
|
||||
line_on_screen = line_on_screen + 1
|
||||
|
||||
line_on_screen = 1
|
||||
for line in self.lines_to_render:
|
||||
x_start = -1
|
||||
@@ -358,7 +444,10 @@ class BiggerText(QWidget):
|
||||
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()
|
||||
chars = bytes.decode(self._encoding, errors="replace")
|
||||
x_start = self.font_metric.horizontalAdvance(chars)
|
||||
|
||||
#print(f"width({chars}) -> bounding_rect={self.font_metric.boundingRect(chars).width()}px or horizontalAdvance={self.font_metric.horizontalAdvance(chars)}")
|
||||
|
||||
# selection ends after line
|
||||
if self.selection.max_byte() > line.byte_end():
|
||||
@@ -368,10 +457,10 @@ class BiggerText(QWidget):
|
||||
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
|
||||
x_end = self.font_metric.horizontalAdvance(bytes.decode(self._encoding, errors="replace")) - 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}")
|
||||
#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)))
|
||||
|
||||
Reference in New Issue
Block a user