mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
[IO API] Create Python entry points for creating and editing IO notes (#2598)
* Create python API for adding and editing IO notes Also: Refactor IO-related methods, tweaking their naming and moving them to a continuous section * Ensure editor is loaded before setupMaskEditor call --------- Co-authored-by: Glutanimate <glutanimate@users.noreply.github.com>
This commit is contained in:
parent
239e964c42
commit
594267149d
2 changed files with 102 additions and 42 deletions
|
@ -51,6 +51,7 @@ class AddCards(QMainWindow):
|
|||
add_close_shortcut(self)
|
||||
self._load_new_note()
|
||||
self.setupButtons()
|
||||
self.col.add_image_occlusion_notetype()
|
||||
self.history: list[NoteId] = []
|
||||
self._last_added_note: Optional[Note] = None
|
||||
gui_hooks.operation_did_execute.append(self.on_operation_did_execute)
|
||||
|
|
143
qt/aqt/editor.py
143
qt/aqt/editor.py
|
@ -31,7 +31,8 @@ from anki.collection import Config, SearchNode
|
|||
from anki.consts import MODEL_CLOZE
|
||||
from anki.hooks import runFilter
|
||||
from anki.httpclient import HttpClient
|
||||
from anki.notes import Note, NoteFieldsCheckResult
|
||||
from anki.models import NotetypeId, StockNotetype
|
||||
from anki.notes import Note, NoteFieldsCheckResult, NoteId
|
||||
from anki.utils import checksum, is_lin, is_win, namedtmp
|
||||
from aqt import AnkiQt, colors, gui_hooks
|
||||
from aqt.operations import QueryOp
|
||||
|
@ -561,18 +562,14 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
|
|||
self.editorMode != EditorMode.ADD_CARDS
|
||||
and self.current_notetype_is_image_occlusion()
|
||||
):
|
||||
mode = {"kind": "edit", "noteId": self.note.id}
|
||||
options = {"mode": mode}
|
||||
js += " setupMaskEditor(%s);" % json.dumps(options)
|
||||
io_options = self._create_edit_io_options(note_id=self.note.id)
|
||||
js += " setupMaskEditor(%s);" % json.dumps(io_options)
|
||||
|
||||
js = gui_hooks.editor_will_load_note(js, self.note, self)
|
||||
self.web.evalWithCallback(
|
||||
f'require("anki/ui").loaded.then(() => {{ {js} }})', oncallback
|
||||
)
|
||||
|
||||
def current_notetype_is_image_occlusion(self) -> bool:
|
||||
return False
|
||||
|
||||
def _save_current_note(self) -> None:
|
||||
"Call after note is updated with data from webview."
|
||||
update_note(parent=self.widget, note=self.note).run_in_background(
|
||||
|
@ -982,6 +979,102 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
|
|||
def onCutOrCopy(self) -> None:
|
||||
self.web.user_cut_or_copied()
|
||||
|
||||
# Image occlusion
|
||||
######################################################################
|
||||
|
||||
def current_notetype_is_image_occlusion(self) -> bool:
|
||||
return bool(self.note) and (
|
||||
self.note.note_type().get("originalStockKind", None)
|
||||
== StockNotetype.OriginalStockKind.ORIGINAL_STOCK_KIND_IMAGE_OCCLUSION
|
||||
)
|
||||
|
||||
def select_image_and_occlude(self) -> None:
|
||||
"""Show a file selection screen, then get selected image path."""
|
||||
extension_filter = " ".join(
|
||||
f"*.{extension}" for extension in sorted(itertools.chain(pics))
|
||||
)
|
||||
filter = f"{tr.editing_media()} ({extension_filter})"
|
||||
|
||||
def accept(file: str) -> None:
|
||||
try:
|
||||
if self.editorMode == EditorMode.ADD_CARDS:
|
||||
self.setup_mask_editor_for_new_note(image_path=file, notetype_id=0)
|
||||
else:
|
||||
self.setup_mask_editor_for_existing_note(
|
||||
note_id=self.note.id, image_path=file
|
||||
)
|
||||
except Exception as e:
|
||||
showWarning(str(e))
|
||||
return
|
||||
|
||||
file = getFile(
|
||||
parent=self.widget,
|
||||
title=tr.editing_add_media(),
|
||||
cb=cast(Callable[[Any], None], accept),
|
||||
filter=filter,
|
||||
key="media",
|
||||
)
|
||||
|
||||
self.parentWindow.activateWindow()
|
||||
|
||||
def setup_mask_editor_for_new_note(
|
||||
self,
|
||||
image_path: str,
|
||||
notetype_id: NotetypeId | int = 0,
|
||||
):
|
||||
"""Set-up IO mask editor for adding new notes
|
||||
Presupposes that active editor notetype is an image occlusion notetype
|
||||
Args:
|
||||
image_path: Absolute path to image.
|
||||
notetype_id: ID of note type to use. Provided ID must belong to an
|
||||
image occlusion notetype. Set this to 0 to auto-select the first
|
||||
found image occlusion notetype in the user's collection.
|
||||
"""
|
||||
image_field_html = self._addMedia(image_path)
|
||||
io_options = self._create_add_io_options(
|
||||
image_path=image_path,
|
||||
image_field_html=image_field_html,
|
||||
notetype_id=notetype_id,
|
||||
)
|
||||
self._setup_mask_editor(io_options)
|
||||
|
||||
def setup_mask_editor_for_existing_note(
|
||||
self, note_id: NoteId, image_path: str | None = None
|
||||
):
|
||||
"""Set-up IO mask editor for editing existing notes
|
||||
Presupposes that active editor notetype is an image occlusion notetype
|
||||
Args:
|
||||
note_id: ID of note to edit.
|
||||
image_path: (Optional) Absolute path to image that should replace current
|
||||
image
|
||||
"""
|
||||
io_options = self._create_edit_io_options(note_id)
|
||||
if image_path:
|
||||
image_field_html = self._addMedia(image_path)
|
||||
self.web.eval(f"resetIOImage({json.dumps(image_path)})")
|
||||
self.web.eval(f"setImageField({json.dumps(image_field_html)})")
|
||||
self._setup_mask_editor(io_options)
|
||||
|
||||
def _setup_mask_editor(self, io_options: dict):
|
||||
self.web.eval(
|
||||
'require("anki/ui").loaded.then(() =>'
|
||||
f"setupMaskEditor({json.dumps(io_options)})"
|
||||
"); "
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _create_add_io_options(
|
||||
image_path: str, image_field_html: str, notetype_id: NotetypeId | int = 0
|
||||
) -> dict:
|
||||
return {
|
||||
"mode": {"kind": "add", "imagePath": image_path, "notetypeId": notetype_id},
|
||||
"html": image_field_html,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _create_edit_io_options(note_id: NoteId) -> dict:
|
||||
return {"mode": {"kind": "edit", "noteId": note_id}}
|
||||
|
||||
# Legacy editing routines
|
||||
######################################################################
|
||||
|
||||
|
@ -1188,40 +1281,6 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
|
|||
def setTagsCollapsed(self, collapsed: bool) -> None:
|
||||
aqt.mw.pm.set_tags_collapsed(self.editorMode, collapsed)
|
||||
|
||||
def onAddImageForOcclusion(self) -> None:
|
||||
"""Show a file selection screen, then get selected image path."""
|
||||
extension_filter = " ".join(
|
||||
f"*.{extension}" for extension in sorted(itertools.chain(pics))
|
||||
)
|
||||
filter = f"{tr.editing_media()} ({extension_filter})"
|
||||
|
||||
def accept(file: str) -> None:
|
||||
try:
|
||||
html = self._addMedia(file)
|
||||
if self.editorMode == EditorMode.ADD_CARDS:
|
||||
mode = {"kind": "add", "imagePath": file, "notetypeId": 0}
|
||||
options = {"html": html, "mode": mode}
|
||||
self.web.eval(f"setupMaskEditor({json.dumps(options)})")
|
||||
else:
|
||||
mode = {"kind": "edit", "noteId": self.note.id}
|
||||
options = {"html": html, "mode": mode}
|
||||
self.web.eval(f"resetIOImage({json.dumps(file)})")
|
||||
self.web.eval(f"setImageField({json.dumps(html)})")
|
||||
self.web.eval(f"setupMaskEditor({json.dumps(options)})")
|
||||
except Exception as e:
|
||||
showWarning(str(e))
|
||||
return
|
||||
|
||||
file = getFile(
|
||||
parent=self.widget,
|
||||
title=tr.editing_add_media(),
|
||||
cb=cast(Callable[[Any], None], accept),
|
||||
filter=filter,
|
||||
key="media",
|
||||
)
|
||||
|
||||
self.parentWindow.activateWindow()
|
||||
|
||||
# Links from HTML
|
||||
######################################################################
|
||||
|
||||
|
@ -1251,7 +1310,7 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too
|
|||
toggleMathjax=Editor.toggleMathjax,
|
||||
toggleShrinkImages=Editor.toggleShrinkImages,
|
||||
toggleCloseHTMLTags=Editor.toggleCloseHTMLTags,
|
||||
addImageForOcclusion=Editor.onAddImageForOcclusion,
|
||||
addImageForOcclusion=Editor.select_image_and_occlude,
|
||||
)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue