3b1b-manim/manimlib/window.py

150 lines
5.4 KiB
Python
Raw Normal View History

from __future__ import annotations
import numpy as np
2022-04-12 19:19:59 +08:00
2020-02-11 19:51:19 -08:00
import moderngl_window as mglw
from moderngl_window.context.pyglet.window import Window as PygletWindow
2020-02-13 10:50:38 -08:00
from moderngl_window.timers.clock import Timer
2021-01-19 11:35:25 -08:00
from screeninfo import get_monitors
2020-02-11 19:51:19 -08:00
from manimlib.constants import FRAME_SHAPE
2021-01-19 11:35:25 -08:00
from manimlib.utils.customization import get_customization
2020-02-11 19:51:19 -08:00
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from manimlib.scene.scene import Scene
2020-02-11 19:51:19 -08:00
class Window(PygletWindow):
2022-12-26 09:40:11 -07:00
fullscreen: bool = False
resizable: bool = True
gl_version: tuple[int, int] = (3, 3)
vsync: bool = True
cursor: bool = True
2020-02-11 19:51:19 -08:00
def __init__(
self,
scene: Scene,
size: tuple[int, int] = (1280, 720),
samples = 0
):
super().__init__(size=size, samples=samples)
2023-01-23 17:10:18 -08:00
self.default_size = size
self.default_position = self.find_initial_position(size)
2021-02-11 12:20:17 -08:00
self.scene = scene
self.pressed_keys = set()
self.title = str(scene)
self.size = size
mglw.activate_context(window=self)
self.timer = Timer()
self.config = mglw.WindowConfig(ctx=self.ctx, wnd=self, timer=self.timer)
self.timer.start()
2023-01-23 17:10:18 -08:00
self.to_default_position()
def to_default_position(self):
self.size = self.default_size
self.position = self.default_position
self.swap_buffers()
2021-01-06 12:47:13 -08:00
def find_initial_position(self, size: tuple[int, int]) -> tuple[int, int]:
2021-01-19 11:35:25 -08:00
custom_position = get_customization()["window_position"]
monitors = get_monitors()
mon_index = get_customization()["window_monitor"]
monitor = monitors[min(mon_index, len(monitors) - 1)]
2021-02-12 13:34:33 -08:00
window_width, window_height = size
2021-01-19 11:35:25 -08:00
# Position might be specified with a string of the form
# x,y for integers x and y
if "," in custom_position:
return tuple(map(int, custom_position.split(",")))
# Alternatively, it might be specified with a string like
2021-08-07 22:25:26 +07:00
# UR, OO, DL, etc. specifying what corner it should go to
2021-01-19 11:35:25 -08:00
char_to_n = {"L": 0, "U": 0, "O": 1, "R": 2, "D": 2}
width_diff = monitor.width - window_width
height_diff = monitor.height - window_height
return (
monitor.x + char_to_n[custom_position[1]] * width_diff // 2,
-monitor.y + char_to_n[custom_position[0]] * height_diff // 2,
2021-01-19 11:35:25 -08:00
)
2020-02-11 19:51:19 -08:00
# Delegate event handling to scene
def pixel_coords_to_space_coords(
self,
px: int,
py: int,
relative: bool = False
) -> np.ndarray:
if not hasattr(self.scene, "frame"):
return np.zeros(3)
pixel_shape = np.array(self.size)
2023-01-30 15:24:10 -08:00
fixed_frame_shape = np.array(FRAME_SHAPE)
frame = self.scene.frame
coords = np.zeros(3)
2023-01-30 15:24:10 -08:00
coords[:2] = (fixed_frame_shape / pixel_shape) * np.array([px, py])
if not relative:
2023-01-30 15:24:10 -08:00
coords[:2] -= 0.5 * fixed_frame_shape
return frame.from_fixed_frame_point(coords, relative)
2020-02-11 19:51:19 -08:00
def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> None:
2020-02-11 19:51:19 -08:00
super().on_mouse_motion(x, y, dx, dy)
point = self.pixel_coords_to_space_coords(x, y)
d_point = self.pixel_coords_to_space_coords(dx, dy, relative=True)
self.scene.on_mouse_motion(point, d_point)
def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int) -> None:
2020-02-11 19:51:19 -08:00
super().on_mouse_drag(x, y, dx, dy, buttons, modifiers)
point = self.pixel_coords_to_space_coords(x, y)
d_point = self.pixel_coords_to_space_coords(dx, dy, relative=True)
2020-02-14 10:52:39 -08:00
self.scene.on_mouse_drag(point, d_point, buttons, modifiers)
2020-02-11 19:51:19 -08:00
def on_mouse_press(self, x: int, y: int, button: int, mods: int) -> None:
2020-02-11 19:51:19 -08:00
super().on_mouse_press(x, y, button, mods)
point = self.pixel_coords_to_space_coords(x, y)
self.scene.on_mouse_press(point, button, mods)
def on_mouse_release(self, x: int, y: int, button: int, mods: int) -> None:
2020-02-11 19:51:19 -08:00
super().on_mouse_release(x, y, button, mods)
point = self.pixel_coords_to_space_coords(x, y)
self.scene.on_mouse_release(point, button, mods)
def on_mouse_scroll(self, x: int, y: int, x_offset: float, y_offset: float) -> None:
2020-02-11 19:51:19 -08:00
super().on_mouse_scroll(x, y, x_offset, y_offset)
point = self.pixel_coords_to_space_coords(x, y)
offset = self.pixel_coords_to_space_coords(x_offset, y_offset, relative=True)
self.scene.on_mouse_scroll(point, offset, x_offset, y_offset)
2020-02-11 19:51:19 -08:00
def on_key_press(self, symbol: int, modifiers: int) -> None:
2021-01-06 12:47:13 -08:00
self.pressed_keys.add(symbol) # Modifiers?
2020-02-11 19:51:19 -08:00
super().on_key_press(symbol, modifiers)
self.scene.on_key_press(symbol, modifiers)
def on_key_release(self, symbol: int, modifiers: int) -> None:
2021-01-06 12:47:13 -08:00
self.pressed_keys.difference_update({symbol}) # Modifiers?
super().on_key_release(symbol, modifiers)
self.scene.on_key_release(symbol, modifiers)
def on_resize(self, width: int, height: int) -> None:
2020-02-11 19:51:19 -08:00
super().on_resize(width, height)
self.scene.on_resize(width, height)
def on_show(self) -> None:
2020-02-11 19:51:19 -08:00
super().on_show()
self.scene.on_show()
def on_hide(self) -> None:
2020-02-11 19:51:19 -08:00
super().on_hide()
self.scene.on_hide()
def on_close(self) -> None:
2020-02-11 19:51:19 -08:00
super().on_close()
self.scene.on_close()
2021-01-06 12:47:13 -08:00
def is_key_pressed(self, symbol: int) -> bool:
2021-01-06 12:47:13 -08:00
return (symbol in self.pressed_keys)