mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 05:24:22 +08:00
Update Scene.embed to play nicely with gui interactions
This commit is contained in:
@ -14,7 +14,6 @@ import numpy as np
|
|||||||
from manimlib.animation.animation import prepare_animation
|
from manimlib.animation.animation import prepare_animation
|
||||||
from manimlib.animation.transform import MoveToTarget
|
from manimlib.animation.transform import MoveToTarget
|
||||||
from manimlib.camera.camera import Camera
|
from manimlib.camera.camera import Camera
|
||||||
from manimlib.config import get_custom_config
|
|
||||||
from manimlib.constants import DEFAULT_WAIT_TIME
|
from manimlib.constants import DEFAULT_WAIT_TIME
|
||||||
from manimlib.constants import ARROW_SYMBOLS
|
from manimlib.constants import ARROW_SYMBOLS
|
||||||
from manimlib.constants import SHIFT_MODIFIER, CTRL_MODIFIER, COMMAND_MODIFIER
|
from manimlib.constants import SHIFT_MODIFIER, CTRL_MODIFIER, COMMAND_MODIFIER
|
||||||
@ -143,32 +142,40 @@ class Scene(object):
|
|||||||
|
|
||||||
def embed(self, close_scene_on_exit: bool = True) -> None:
|
def embed(self, close_scene_on_exit: bool = True) -> None:
|
||||||
if not self.preview:
|
if not self.preview:
|
||||||
# If the scene is just being
|
# If the scene is just being written, ignore embed calls
|
||||||
# written, ignore embed calls
|
|
||||||
return
|
return
|
||||||
self.stop_skipping()
|
self.stop_skipping()
|
||||||
self.linger_after_completion = False
|
self.linger_after_completion = False
|
||||||
self.update_frame()
|
self.update_frame()
|
||||||
|
|
||||||
# Save scene state at the point of embedding
|
|
||||||
self.save_state()
|
self.save_state()
|
||||||
|
|
||||||
from IPython.terminal.embed import InteractiveShellEmbed
|
# Configure and launch embedded terminal
|
||||||
shell = InteractiveShellEmbed()
|
from IPython.terminal import embed, pt_inputhooks
|
||||||
# Have the frame update after each command
|
shell = embed.InteractiveShellEmbed.instance()
|
||||||
shell.events.register('post_run_cell', lambda *a, **kw: self.refresh_static_mobjects())
|
|
||||||
shell.events.register('post_run_cell', lambda *a, **kw: self.update_frame())
|
# Use the locals namespace of the caller
|
||||||
# Use the locals of the caller as the local namespace
|
|
||||||
# once embedded, and add a few custom shortcuts
|
|
||||||
local_ns = inspect.currentframe().f_back.f_locals
|
local_ns = inspect.currentframe().f_back.f_locals
|
||||||
local_ns["touch"] = self.interact
|
# Add a few custom shortcuts
|
||||||
local_ns["i2g"] = self.ids_to_group
|
for term in ("play", "wait", "add", "remove", "clear", "save_state", "restore", "i2g", "i2m"):
|
||||||
for term in ("play", "wait", "add", "remove", "clear", "save_state", "restore"):
|
|
||||||
local_ns[term] = getattr(self, term)
|
local_ns[term] = getattr(self, term)
|
||||||
log.info("Tips: Now the embed iPython terminal is open. But you can't interact with"
|
|
||||||
" the window directly. To do so, you need to type `touch()` or `self.interact()`")
|
# Enables gui interactions during the embed
|
||||||
exec(get_custom_config()["universal_import_line"])
|
def inputhook(context):
|
||||||
|
while not context.input_is_ready():
|
||||||
|
self.update_frame()
|
||||||
|
|
||||||
|
pt_inputhooks.register("manim", inputhook)
|
||||||
|
shell.enable_gui("manim")
|
||||||
|
|
||||||
|
# Have the frame update after each command
|
||||||
|
def post_cell_func(*args, **kwargs):
|
||||||
|
self.refresh_static_mobjects()
|
||||||
|
|
||||||
|
shell.events.register("post_run_cell", post_cell_func)
|
||||||
|
|
||||||
|
# Launch shell, with stack_depth=2 indicating we should use caller globals/locals
|
||||||
shell(local_ns=local_ns, stack_depth=2)
|
shell(local_ns=local_ns, stack_depth=2)
|
||||||
|
|
||||||
# End scene when exiting an embed
|
# End scene when exiting an embed
|
||||||
if close_scene_on_exit:
|
if close_scene_on_exit:
|
||||||
raise EndSceneEarlyException()
|
raise EndSceneEarlyException()
|
||||||
@ -331,6 +338,12 @@ class Scene(object):
|
|||||||
map(self.id_to_mobject, id_values)
|
map(self.id_to_mobject, id_values)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
def i2g(self, *id_values):
|
||||||
|
return self.ids_to_group(*id_values)
|
||||||
|
|
||||||
|
def i2m(self, id_value):
|
||||||
|
return self.id_to_mobject(id_value)
|
||||||
|
|
||||||
# Related to skipping
|
# Related to skipping
|
||||||
def update_skipping_status(self) -> None:
|
def update_skipping_status(self) -> None:
|
||||||
if self.start_at_animation_number is not None:
|
if self.start_at_animation_number is not None:
|
||||||
|
Reference in New Issue
Block a user