feat(cli/lib): use scene background color as default (#160)

* Use scene background color as default

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Minor changes to feature: Read scene background

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Small fix for feature "Read bg color"

* chore(ci): add typing ignore

* fix(ci): typo

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Jérome Eertmans <jeertmans@icloud.com>
This commit is contained in:
Fairlight8
2023-03-22 13:59:04 +01:00
committed by GitHub
parent 2ba9b734a3
commit 88d598709a
4 changed files with 40 additions and 8 deletions

View File

@ -8,6 +8,7 @@ from pathlib import Path
from typing import Dict, List, Optional, Set, Tuple, Union from typing import Dict, List, Optional, Set, Tuple, Union
from pydantic import BaseModel, FilePath, PositiveInt, root_validator, validator from pydantic import BaseModel, FilePath, PositiveInt, root_validator, validator
from pydantic.color import Color
from PySide6.QtCore import Qt from PySide6.QtCore import Qt
from .defaults import FFMPEG_BIN from .defaults import FFMPEG_BIN
@ -150,6 +151,7 @@ class PresentationConfig(BaseModel): # type: ignore
slides: List[SlideConfig] slides: List[SlideConfig]
files: List[FilePath] files: List[FilePath]
resolution: Tuple[PositiveInt, PositiveInt] = (1920, 1080) resolution: Tuple[PositiveInt, PositiveInt] = (1920, 1080)
background_color: Color = "black"
@root_validator @root_validator
def animation_indices_match_files( def animation_indices_match_files(

View File

@ -321,9 +321,9 @@ class RevealJS(Converter):
# Read more about this: # Read more about this:
# https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide#autoplay_and_autoplay_blocking # https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide#autoplay_and_autoplay_blocking
if slide_config.is_loop(): if slide_config.is_loop():
yield f'<section data-background-size={self.background_size.value} data-background-video="{file}" data-background-video-muted data-background-video-loop></section>' yield f'<section data-background-size={self.background_size.value} data-background-color="{presentation_config.background_color}" data-background-video="{file}" data-background-video-muted data-background-video-loop></section>'
else: else:
yield f'<section data-background-size={self.background_size.value} data-background-video="{file}" data-background-video-muted></section>' yield f'<section data-background-size={self.background_size.value} data-background-color="{presentation_config.background_color}" data-background-video="{file}" data-background-video-muted></section>'
def load_template(self) -> str: def load_template(self) -> str:
"""Returns the RevealJS HTML template as a string.""" """Returns the RevealJS HTML template as a string."""

View File

@ -11,6 +11,7 @@ import cv2
import numpy as np import numpy as np
from click import Context, Parameter from click import Context, Parameter
from pydantic import ValidationError from pydantic import ValidationError
from pydantic.color import Color
from PySide6.QtCore import Qt, QThread, Signal, Slot from PySide6.QtCore import Qt, QThread, Signal, Slot
from PySide6.QtGui import QCloseEvent, QIcon, QImage, QKeyEvent, QPixmap, QResizeEvent from PySide6.QtGui import QCloseEvent, QIcon, QImage, QKeyEvent, QPixmap, QResizeEvent
from PySide6.QtWidgets import QApplication, QGridLayout, QLabel, QWidget from PySide6.QtWidgets import QApplication, QGridLayout, QLabel, QWidget
@ -105,6 +106,11 @@ class Presentation:
"""Returns the resolution.""" """Returns the resolution."""
return self.config.resolution return self.config.resolution
@property
def background_color(self) -> Color:
"""Returns the background color."""
return self.config.background_color
@property @property
def current_slide_index(self) -> int: def current_slide_index(self) -> int:
return self.__current_slide_index return self.__current_slide_index
@ -411,6 +417,11 @@ class Display(QThread): # type: ignore
"""Returns the resolution of the current presentation.""" """Returns the resolution of the current presentation."""
return self.current_presentation.resolution return self.current_presentation.resolution
@property
def current_background_color(self) -> Color:
"""Returns the background color of the current presentation."""
return self.current_presentation.background_color
def run(self) -> None: def run(self) -> None:
"""Runs a series of presentations until end or exit.""" """Runs a series of presentations until end or exit."""
while self.run_flag: while self.run_flag:
@ -649,7 +660,9 @@ class App(QWidget): # type: ignore
self.label.setScaledContents(True) self.label.setScaledContents(True)
self.label.setAlignment(Qt.AlignCenter) self.label.setAlignment(Qt.AlignCenter)
self.label.resize(self.display_width, self.display_height) self.label.resize(self.display_width, self.display_height)
self.label.setStyleSheet(f"background-color: {background_color}") self.label.setStyleSheet(
f"background-color: {self.thread.current_background_color}"
)
self.pixmap = QPixmap(self.width(), self.height()) self.pixmap = QPixmap(self.width(), self.height())
self.label.setPixmap(self.pixmap) self.label.setPixmap(self.pixmap)
@ -729,6 +742,9 @@ class App(QWidget): # type: ignore
self.display_width, self.display_height = self.thread.current_resolution self.display_width, self.display_height = self.thread.current_resolution
if not self.isFullScreen(): if not self.isFullScreen():
self.resize(self.display_width, self.display_height) self.resize(self.display_width, self.display_height)
self.label.setStyleSheet(
f"background-color: {self.thread.current_background_color}"
)
@click.command() @click.command()
@ -924,8 +940,8 @@ def start_at_callback(
"background_color", "background_color",
metavar="COLOR", metavar="COLOR",
type=str, type=str,
default="black", default=None,
help='Set the background color for borders when using "keep" resize mode. Can be any valid CSS color, e.g., "green", "#FF6500" or "rgba(255, 255, 0, .5)".', help='Set the background color for borders when using "keep" resize mode. Can be any valid CSS color, e.g., "green", "#FF6500" or "rgba(255, 255, 0, .5)". If not set, it defaults to the background color configured in the Manim scene.',
show_default=True, show_default=True,
) )
@click.option( @click.option(
@ -980,7 +996,7 @@ def present(
hide_mouse: bool, hide_mouse: bool,
aspect_ratio: str, aspect_ratio: str,
resize_mode: str, resize_mode: str,
background_color: str, background_color: Optional[str],
start_at: Tuple[Optional[int], Optional[int], Optional[int]], start_at: Tuple[Optional[int], Optional[int], Optional[int]],
start_at_scene_number: Optional[int], start_at_scene_number: Optional[int],
start_at_slide_number: Optional[int], start_at_slide_number: Optional[int],
@ -1005,6 +1021,10 @@ def present(
for presentation_config in presentation_configs: for presentation_config in presentation_configs:
presentation_config.resolution = resolution presentation_config.resolution = resolution
if background_color is not None:
for presentation_config in presentation_configs:
presentation_config.background_color = background_color
presentations = [ presentations = [
Presentation(presentation_config) Presentation(presentation_config)
for presentation_config in presentation_configs for presentation_config in presentation_configs
@ -1048,7 +1068,6 @@ def present(
hide_mouse=hide_mouse, hide_mouse=hide_mouse,
aspect_ratio=ASPECT_RATIO_MODES[aspect_ratio], aspect_ratio=ASPECT_RATIO_MODES[aspect_ratio],
resize_mode=RESIZE_MODES[resize_mode], resize_mode=RESIZE_MODES[resize_mode],
background_color=background_color,
start_at_scene_number=start_at_scene_number, start_at_scene_number=start_at_scene_number,
start_at_slide_number=start_at_slide_number, start_at_slide_number=start_at_slide_number,
start_at_animation_number=start_at_animation_number, start_at_animation_number=start_at_animation_number,

View File

@ -54,6 +54,14 @@ class Slide(Scene): # type:ignore
self.__loop_start_animation: Optional[int] = None self.__loop_start_animation: Optional[int] = None
self.__pause_start_animation = 0 self.__pause_start_animation = 0
@property
def __background_color(self) -> str:
"""Returns the scene's background color."""
if MANIMGL:
return self.camera_config["background_color"].hex # type: ignore
else:
return config["background_color"].hex # type: ignore
@property @property
def __resolution(self) -> Tuple[int, int]: def __resolution(self) -> Tuple[int, int]:
"""Returns the scene's resolution used during rendering.""" """Returns the scene's resolution used during rendering."""
@ -321,7 +329,10 @@ class Slide(Scene): # type:ignore
with open(slide_path, "w") as f: with open(slide_path, "w") as f:
f.write( f.write(
PresentationConfig( PresentationConfig(
slides=self.__slides, files=files, resolution=self.__resolution slides=self.__slides,
files=files,
resolution=self.__resolution,
background_color=self.__background_color,
).json(indent=2) ).json(indent=2)
) )