mirror of
https://github.com/1j01/textual-paint.git
synced 2025-01-05 21:56:30 +03:00
Confirm discarding information during Save/Open/New, not just Save As
This commit is contained in:
parent
29e9e7a384
commit
faa41d07b2
@ -171,7 +171,6 @@ To preview ANSI art files in file managers like Nautilus, Thunar, Nemo, or Caja,
|
|||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|
||||||
- When saving as a TXT file, color information is discarded without warning. It is considered saved, so the backup will be discarded, even though the saved file doesn't match the visible document.
|
|
||||||
- Undo/Redo doesn't work inside the Text tool's textbox. Ctrl+Z will delete the textbox. (Also note that the Text tool works differently from MS Paint; it will overwrite characters and the cursor can move freely, which makes it better for ASCII art and worse for prose.)
|
- Undo/Redo doesn't work inside the Text tool's textbox. Ctrl+Z will delete the textbox. (Also note that the Text tool works differently from MS Paint; it will overwrite characters and the cursor can move freely, which makes it better for ASCII art and worse for prose.)
|
||||||
- The selection box border appears inside instead of outside (and lacks dashes). For the text box, I hid the border because it was too visually confusing, but it should also have an outer border.
|
- The selection box border appears inside instead of outside (and lacks dashes). For the text box, I hid the border because it was too visually confusing, but it should also have an outer border.
|
||||||
- Pick Color can't be cancelled (with Esc or by pressing both mouse buttons), since it samples the color continuously.
|
- Pick Color can't be cancelled (with Esc or by pressing both mouse buttons), since it samples the color continuously.
|
||||||
|
@ -2550,6 +2550,20 @@ class PaintApp(App[None]):
|
|||||||
self.message_box(dialog_title, _("An unexpected error occurred while writing %1.", file_path), "ok", error=e)
|
self.message_box(dialog_title, _("An unexpected error occurred while writing %1.", file_path), "ok", error=e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def reload_after_save(self, content: bytes, file_path: str) -> None:
|
||||||
|
"""Reload the document from saved content, to show information loss from the file format.
|
||||||
|
|
||||||
|
Unlike `open_from_file_path`, this method:
|
||||||
|
- doesn't short circuit when the file path matches the current file path, crucially
|
||||||
|
- skips backup management
|
||||||
|
- skips the file system, which is more efficient
|
||||||
|
- fails to handle errors... FIXME
|
||||||
|
"""
|
||||||
|
self.resize_document(self.image.width, self.image.height) # (hackily) make this undoable
|
||||||
|
new_image = AnsiArtDocument.decode_based_on_file_extension(content, file_path)
|
||||||
|
self.canvas.image = self.image = new_image
|
||||||
|
self.canvas.refresh(layout=True)
|
||||||
|
|
||||||
async def save(self) -> bool:
|
async def save(self) -> bool:
|
||||||
"""Save the image to a file.
|
"""Save the image to a file.
|
||||||
|
|
||||||
@ -2558,13 +2572,20 @@ class PaintApp(App[None]):
|
|||||||
self.stop_action_in_progress()
|
self.stop_action_in_progress()
|
||||||
dialog_title = _("Save")
|
dialog_title = _("Save")
|
||||||
if self.file_path:
|
if self.file_path:
|
||||||
|
format_id = AnsiArtDocument.format_from_extension(self.file_path)
|
||||||
|
information_loss = await self.confirm_information_loss_async(format_id or "ANSI")
|
||||||
try:
|
try:
|
||||||
content = self.image.encode_based_on_file_extension(self.file_path)
|
content = self.image.encode_to_format(format_id)
|
||||||
except FormatWriteNotSupported as e:
|
except FormatWriteNotSupported as e:
|
||||||
self.message_box(_("Save"), e.localized_message, "ok")
|
self.message_box(_("Save"), e.localized_message, "ok")
|
||||||
return False
|
return False
|
||||||
if self.write_file_path(self.file_path, content, dialog_title):
|
if self.write_file_path(self.file_path, content, dialog_title):
|
||||||
self.saved_undo_count = len(self.undos)
|
self.saved_undo_count = len(self.undos)
|
||||||
|
if information_loss:
|
||||||
|
# Note: this fails to preview the lost information in the case
|
||||||
|
# of saving the old file in prompt_save_changes,
|
||||||
|
# because the document will be unloaded.
|
||||||
|
self.reload_after_save(content, self.file_path)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@ -2610,10 +2631,7 @@ class PaintApp(App[None]):
|
|||||||
self.saved_undo_count = len(self.undos)
|
self.saved_undo_count = len(self.undos)
|
||||||
window.close()
|
window.close()
|
||||||
if reload_after_save:
|
if reload_after_save:
|
||||||
self.resize_document(self.image.width, self.image.height) # (hackily) make this undoable
|
self.reload_after_save(content, file_path)
|
||||||
new_image = AnsiArtDocument.decode_based_on_file_extension(content, file_path)
|
|
||||||
self.canvas.image = self.image = new_image
|
|
||||||
self.canvas.refresh(layout=True)
|
|
||||||
saved_future.set_result(None)
|
saved_future.set_result(None)
|
||||||
|
|
||||||
# TODO: should this look for a backup file and offer to recover it?
|
# TODO: should this look for a backup file and offer to recover it?
|
||||||
@ -2753,7 +2771,7 @@ class PaintApp(App[None]):
|
|||||||
self.message_box(_("Paint"), message, "yes/no", handle_button)
|
self.message_box(_("Paint"), message, "yes/no", handle_button)
|
||||||
|
|
||||||
def confirm_information_loss(self, format_id: str, callback: Callable[[bool], None]) -> None:
|
def confirm_information_loss(self, format_id: str, callback: Callable[[bool], None]) -> None:
|
||||||
"""Confirms discarding information when saving as a particular format."""
|
"""Confirms discarding information when saving as a particular format. Callback variant. Never calls back if unconfirmed."""
|
||||||
if format_id in ("ANSI", "SVG", "HTML", "RICH_CONSOLE_MARKUP"):
|
if format_id in ("ANSI", "SVG", "HTML", "RICH_CONSOLE_MARKUP"):
|
||||||
callback(False)
|
callback(False)
|
||||||
elif format_id == "PLAINTEXT":
|
elif format_id == "PLAINTEXT":
|
||||||
@ -2761,6 +2779,12 @@ class PaintApp(App[None]):
|
|||||||
else:
|
else:
|
||||||
self.confirm_lose_text_information(lambda: callback(True))
|
self.confirm_lose_text_information(lambda: callback(True))
|
||||||
|
|
||||||
|
async def confirm_information_loss_async(self, format_id: str) -> Coroutine[None, None, bool]:
|
||||||
|
"""Confirms discarding information when saving as a particular format. Awaitable variant, which uses the callback variant."""
|
||||||
|
future = asyncio.get_running_loop().create_future()
|
||||||
|
self.confirm_information_loss(format_id, lambda result: future.set_result(result))
|
||||||
|
return await future
|
||||||
|
|
||||||
def is_document_modified(self) -> bool:
|
def is_document_modified(self) -> bool:
|
||||||
"""Returns whether the document has been modified since the last save."""
|
"""Returns whether the document has been modified since the last save."""
|
||||||
return len(self.undos) != self.saved_undo_count
|
return len(self.undos) != self.saved_undo_count
|
||||||
|
Loading…
Reference in New Issue
Block a user