diff --git a/paint.py b/paint.py index 4d98024..061ec2d 100755 --- a/paint.py +++ b/paint.py @@ -476,6 +476,25 @@ class Selection: document.copy_region(source=self.contained_image, source_region=source_region, target_region=target_region, mask=self.mask) +def offset_to_text_index(textbox: Selection, offset: Offset) -> int: + """Converts an offset in the textbox to an index in the text.""" + assert textbox.textbox_mode, "offset_to_text_index called on non-textbox selection" + return offset.y * textbox.region.width + offset.x + +def text_index_to_offset(textbox: Selection, index: int) -> Offset: + """Converts an index in the text to an offset in the textbox.""" + assert textbox.textbox_mode, "text_index_to_offset called on non-textbox selection" + return Offset(index % textbox.region.width, index // textbox.region.width) + +def selected_text_range(textbox: Selection) -> Generator[Offset, None, None]: + """Yields all offsets within the text selection.""" + assert textbox.textbox_mode, "selected_text_range called on non-textbox selection" + start = offset_to_text_index(textbox, textbox.text_selection_start) + end = offset_to_text_index(textbox, textbox.text_selection_end) + for i in range(min(start, end), max(start, end) + 1): + yield text_index_to_offset(textbox, i) + + debug_region_updates = False ansi_escape_pattern = re.compile(r"(\N{ESC}\[[\d;]*[a-zA-Z])") @@ -2760,26 +2779,11 @@ class PaintApp(App[None]): textbox = self.image.selection assert textbox.contained_image is not None, "Textbox mode should always have contained_image, to edit as text." - def offset_to_text_index(offset: Offset) -> int: - """Converts an offset in the textbox to an index in the text.""" - return offset.y * textbox.region.width + offset.x - - def text_index_to_offset(index: int) -> Offset: - """Converts an index in the text to an offset in the textbox.""" - return Offset(index % textbox.region.width, index // textbox.region.width) - - def selected_text_range() -> Generator[Offset, None, None]: - """Yields all offsets within the text selection.""" - start = offset_to_text_index(textbox.text_selection_start) - end = offset_to_text_index(textbox.text_selection_end) - for i in range(min(start, end), max(start, end) + 1): - yield text_index_to_offset(i) - def delete_selected_text() -> None: """Deletes the selected text, if any.""" assert textbox.contained_image is not None, "Textbox mode should always have contained_image, to edit as text." # Come on, Pyright. # Delete the selected text. - for offset in selected_text_range(): + for offset in selected_text_range(textbox): textbox.contained_image.ch[offset.y][offset.x] = " " textbox.textbox_edited = True # Move the cursor to the start of the selection.