Move logic for window size and position into Window class

This commit is contained in:
Grant Sanderson 2024-12-10 11:07:54 -06:00
parent 178cca0ca5
commit d4c5c4736a
3 changed files with 54 additions and 56 deletions

View file

@ -5,7 +5,6 @@ import colour
import importlib import importlib
import inspect import inspect
import os import os
import screeninfo
import sys import sys
import yaml import yaml
@ -311,48 +310,15 @@ def get_resolution(args: Optional[Namespace] = None, global_config: Optional[dic
return int(width_str), int(height_str) return int(width_str), int(height_str)
def get_window_position(monitor: screeninfo.Monitor, position_string: str, size: tuple[int, int]):
# Find position (Perhaps factor this out)
# Position might be specified with a string of the form
# x,y for integers x and y
if "," in position_string:
return tuple(map(int, position_string.split(",")))
elif len(position_string) == 2:
# Alternatively, it might be specified with a string like
# UR, OO, DL, etc. specifying what corner it should go to
char_to_n = {"L": 0, "U": 0, "O": 1, "R": 2, "D": 2}
width_diff = monitor.width - size[0]
height_diff = monitor.height - size[1]
x_step = char_to_n[position_string[1]] * width_diff // 2
y_step = char_to_n[position_string[0]] * height_diff // 2
return (monitor.x + x_step, -monitor.y + y_step)
else:
raise Exception("Window position string must be either a tuple of integers, or a pair of from \"ULORD\"")
def get_window_config(args: Namespace, global_config: dict) -> dict: def get_window_config(args: Namespace, global_config: dict) -> dict:
# Default to making window half the screen size window_config = global_config["window"]
# but make it full screen if -f is passed in # Todo, this correction of configuration should maybe happen elsewhere
try: for key in "position", "size":
monitors = screeninfo.get_monitors() if window_config.get(key):
except screeninfo.ScreenInfoError: window_config[key] = eval(window_config[key])
# Default fallback if args.full_screen:
monitors = [screeninfo.Monitor(width=1920, height=1080)] window_config["full_screen"] = True
mon_index = global_config["window"]["monitor"] return window_config
monitor = monitors[min(mon_index, len(monitors) - 1)]
width, height = get_resolution(args, global_config)
aspect_ratio = width / height
window_width = monitor.width
if not (args.full_screen or global_config["window"]["full_screen"]):
window_width //= 2
window_height = int(window_width / aspect_ratio)
size = (window_width, window_height)
default_position = get_window_position(monitor, global_config["window"]["position"], size)
return dict(size=size, default_position=default_position)
def get_camera_config(args: Optional[Namespace] = None, global_config: Optional[dict] = None) -> dict: def get_camera_config(args: Optional[Namespace] = None, global_config: Optional[dict] = None) -> dict:

View file

@ -26,14 +26,16 @@ directories:
# but here a user can specify a different cache location # but here a user can specify a different cache location
cache: "" cache: ""
window: window:
# Set the position of window on screen, you can use directions, e.g. UL/DR/OL/OO/... # The position of window on screen. UR -> Upper Right, and likewise DL -> Down and Left,
# also, you can also specify the position(pixel) of the upper left corner of # UO would be upper middle, etc.
# the window on the monitor, e.g. "960,540" position_string: UR
position: UR # If using multiple monitors, which one should show the window
# If using multiple monitors, which one should show the window? monitor_index: 0
monitor: 0
# If not full screen, the default to give it half the screen width # If not full screen, the default to give it half the screen width
full_screen: False full_screen: False
# Other optional specifications that override the above
# position: (500, 500) # Specific position, in pixel coordiantes, for upper right corner
# size: (1920, 1080) # Specific size, in pixels
file_writer_config: file_writer_config:
# If break_into_partial_movies is set to True, then many small # If break_into_partial_movies is set to True, then many small
# files will be written corresponding to each Scene.play and # files will be written corresponding to each Scene.play and

View file

@ -6,8 +6,10 @@ import moderngl_window as mglw
from moderngl_window.context.pyglet.window import Window as PygletWindow from moderngl_window.context.pyglet.window import Window as PygletWindow
from moderngl_window.timers.clock import Timer from moderngl_window.timers.clock import Timer
from functools import wraps from functools import wraps
import screeninfo
from manimlib.config import get_global_config from manimlib.config import get_global_config
from manimlib.constants import ASPECT_RATIO
from manimlib.constants import FRAME_SHAPE from manimlib.constants import FRAME_SHAPE
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@ -29,20 +31,24 @@ class Window(PygletWindow):
def __init__( def __init__(
self, self,
scene: Optional[Scene] = None, scene: Optional[Scene] = None,
size: tuple[int, int] = (1280, 720), position_string: str = "UR",
default_position: tuple[int, int] = (0, 0), monitor_index: int = 1,
full_screen: bool = False,
size: Optional[tuple[int, int]] = None,
position: Optional[tuple[int, int]] = None,
samples: int = 0 samples: int = 0
): ):
super().__init__(size=size, samples=samples)
self.scene = scene self.scene = scene
self.default_size = size self.monitor = self.get_monitor(monitor_index)
self.default_position = default_position self.default_size = size or self.get_default_size(full_screen)
self.pressed_keys = set() self.default_position = position or self.position_from_string(position_string)
self.size = size
super().__init__(samples=samples)
self.to_default_position() self.to_default_position()
self.pressed_keys = set()
if self.scene: if self.scene:
self.init_for_scene(scene) self.init_for_scene(scene)
@ -66,6 +72,30 @@ class Window(PygletWindow):
mglw.activate_context(window=self, ctx=self.ctx) mglw.activate_context(window=self, ctx=self.ctx)
self.timer.start() self.timer.start()
def get_monitor(self, index):
try:
monitors = screeninfo.get_monitors()
return monitors[min(index, len(monitors) - 1)]
except screeninfo.ScreenInfoError:
# Default fallback
return screeninfo.Monitor(width=1920, height=1080)
def get_default_size(self, full_screen=False):
width = self.monitor.width // (1 if full_screen else 2)
height = int(width // ASPECT_RATIO)
return (width, height)
def position_from_string(self, position_string):
# Alternatively, it might be specified with a string like
# UR, OO, DL, etc. specifying what corner it should go to
char_to_n = {"L": 0, "U": 0, "O": 1, "R": 2, "D": 2}
size = self.default_size
width_diff = self.monitor.width - size[0]
height_diff = self.monitor.height - size[1]
x_step = char_to_n[position_string[1]] * width_diff // 2
y_step = char_to_n[position_string[0]] * height_diff // 2
return (self.monitor.x + x_step, -self.monitor.y + y_step)
def focus(self): def focus(self):
""" """
Puts focus on this window by hiding and showing it again. Puts focus on this window by hiding and showing it again.