feat(cli): smarter info window hiding logic (#482)

* Adds features from #327

This changes the ``--hide-info-window-`` command to accept three options: auto, always, and never. Auto will hide the info window if there is only one screen. This also fixes the --full-screen option by moving the info window to monitor 1 and the presentation to monitor 0 by default.

* chore(fmt): auto fixes from pre-commit.com hooks

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

* Let Qt decide the screens

* Fix full screen bug

* chore(fmt): auto fixes from pre-commit.com hooks

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

* fix(cli): improve logic

* fix

* Revert fixes and clean code

* Update changelog

---------

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:
PeculiarProgrammer
2024-12-11 03:16:50 -05:00
committed by GitHub
parent 3bd8c386b1
commit 05c1a16ca3
4 changed files with 68 additions and 21 deletions

View File

@ -10,6 +10,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
(unreleased)= (unreleased)=
## [Unreleased](https://github.com/jeertmans/manim-slides/compare/v5.1.10...HEAD) ## [Unreleased](https://github.com/jeertmans/manim-slides/compare/v5.1.10...HEAD)
(unreleased-changed)=
### Changed
- The info window is now only shown in presentations when there
are multiple monitors. However, the `--show-info-window` option
was added to `manim-slides present` to force the info window.
When there are multiple monitors, the info window will no longer
be on the same monitor as the main window, unless overridden.
[@PeculiarProgrammer](https://github.com/PeculiarProgrammer)
[#482](https://github.com/jeertmans/manim-slides/pull/482)
(v5.1.10)= (v5.1.10)=
## [v5.1.10](https://github.com/jeertmans/manim-slides/compare/v5.1.9...v5.1.10) ## [v5.1.10](https://github.com/jeertmans/manim-slides/compare/v5.1.9...v5.1.10)

View File

@ -1,7 +1,7 @@
import signal import signal
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Literal, Optional
import click import click
from click import Context, Parameter from click import Context, Parameter
@ -222,8 +222,14 @@ def start_at_callback(
) )
@click.option( @click.option(
"--hide-info-window", "--hide-info-window",
is_flag=True, flag_value="always",
help="Hide info window.", help="Hide info window. By default, hide the info window if there is only one screen.",
)
@click.option(
"--show-info-window",
"hide_info_window",
flag_value="never",
help="Force to show info window.",
) )
@click.option( @click.option(
"--info-window-screen", "--info-window-screen",
@ -231,11 +237,13 @@ def start_at_callback(
metavar="NUMBER", metavar="NUMBER",
type=int, type=int,
default=None, default=None,
help="Put info window on the given screen (a.k.a. display).", help="Put info window on the given screen (a.k.a. display). "
"If there is more than one screen, it will by default put the info window "
"on a different screen than the main player.",
) )
@click.help_option("-h", "--help") @click.help_option("-h", "--help")
@verbosity_option @verbosity_option
def present( def present( # noqa: C901
scenes: list[str], scenes: list[str],
config_path: Path, config_path: Path,
folder: Path, folder: Path,
@ -251,7 +259,7 @@ def present(
screen_number: Optional[int], screen_number: Optional[int],
playback_rate: float, playback_rate: float,
next_terminates_loop: bool, next_terminates_loop: bool,
hide_info_window: bool, hide_info_window: Optional[Literal["always", "never"]],
info_window_screen_number: Optional[int], info_window_screen_number: Optional[int],
) -> None: ) -> None:
""" """
@ -294,22 +302,36 @@ def present(
app = qapp() app = qapp()
app.setApplicationName("Manim Slides") app.setApplicationName("Manim Slides")
screens = app.screens()
def get_screen(number: int) -> Optional[QScreen]: def get_screen(number: int) -> Optional[QScreen]:
try: try:
return app.screens()[number] return screens[number]
except IndexError: except IndexError:
logger.error( logger.error(
f"Invalid screen number {number}, " f"Invalid screen number {number}, "
f"allowed values are from 0 to {len(app.screens())-1} (incl.)" f"allowed values are from 0 to {len(screens)-1} (incl.)"
) )
return None return None
should_hide_info_window = False
if hide_info_window is None:
should_hide_info_window = len(screens) == 1
elif hide_info_window == "always":
should_hide_info_window = True
if should_hide_info_window and info_window_screen_number is not None:
logger.warning(
f"Ignoring `--info-window-screen` because `--hide-info-window` is set to `{hide_info_window}`."
)
if screen_number is not None: if screen_number is not None:
screen = get_screen(screen_number) screen = get_screen(screen_number)
else: else:
screen = None screen = None
if info_window_screen_number is not None: if info_window_screen_number is not None and not should_hide_info_window:
info_window_screen = get_screen(info_window_screen_number) info_window_screen = get_screen(info_window_screen_number)
else: else:
info_window_screen = None info_window_screen = None
@ -333,11 +355,11 @@ def present(
screen=screen, screen=screen,
playback_rate=playback_rate, playback_rate=playback_rate,
next_terminates_loop=next_terminates_loop, next_terminates_loop=next_terminates_loop,
hide_info_window=hide_info_window, hide_info_window=should_hide_info_window,
info_window_screen=info_window_screen, info_window_screen=info_window_screen,
) )
player.show() player.show(screens)
signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGINT, signal.SIG_DFL)
sys.exit(app.exec()) sys.exit(app.exec())

View File

@ -28,7 +28,6 @@ class Info(QWidget): # type: ignore[misc]
def __init__( def __init__(
self, self,
*, *,
full_screen: bool,
aspect_ratio_mode: Qt.AspectRatioMode, aspect_ratio_mode: Qt.AspectRatioMode,
screen: Optional[QScreen], screen: Optional[QScreen],
) -> None: ) -> None:
@ -38,9 +37,6 @@ class Info(QWidget): # type: ignore[misc]
self.setScreen(screen) self.setScreen(screen)
self.move(screen.geometry().topLeft()) self.move(screen.geometry().topLeft())
if full_screen:
self.setWindowState(Qt.WindowFullScreen)
layout = QHBoxLayout() layout = QHBoxLayout()
# Current slide view # Current slide view
@ -243,7 +239,6 @@ class Player(QMainWindow): # type: ignore[misc]
self.slide_changed.connect(self.slide_changed_callback) self.slide_changed.connect(self.slide_changed_callback)
self.info = Info( self.info = Info(
full_screen=full_screen,
aspect_ratio_mode=aspect_ratio_mode, aspect_ratio_mode=aspect_ratio_mode,
screen=info_window_screen, screen=info_window_screen,
) )
@ -484,11 +479,28 @@ class Player(QMainWindow): # type: ignore[misc]
self.info.next_media_player.setSource(url) self.info.next_media_player.setSource(url)
self.info.next_media_player.play() self.info.next_media_player.play()
def show(self) -> None: def show(self, screens: list[QScreen]) -> None:
"""Screens is necessary to prevent the info window from being shown on the same screen as the main window (especially in full screen mode)."""
super().show() super().show()
if not self.hide_info_window: if not self.hide_info_window:
self.info.show() if len(screens) > 1 and self.isFullScreen():
self.ensure_different_screens(screens)
if self.isFullScreen():
self.info.showFullScreen()
else:
self.info.show()
if (
len(screens) > 1 and self.info.screen() == self.screen()
): # It is better when Qt assigns the location, but if it fails to, this is a fallback
self.ensure_different_screens(screens)
def ensure_different_screens(self, screens: list[QScreen]) -> None:
target_screen = screens[1] if self.screen() == screens[0] else screens[0]
self.info.setScreen(target_screen)
self.info.move(target_screen.geometry().topLeft())
@Slot() @Slot()
def close(self) -> None: def close(self) -> None:
@ -538,8 +550,10 @@ class Player(QMainWindow): # type: ignore[misc]
def full_screen(self) -> None: def full_screen(self) -> None:
if self.windowState() == Qt.WindowFullScreen: if self.windowState() == Qt.WindowFullScreen:
self.setWindowState(Qt.WindowNoState) self.setWindowState(Qt.WindowNoState)
self.info.setWindowState(Qt.WindowNoState)
else: else:
self.setWindowState(Qt.WindowFullScreen) self.setWindowState(Qt.WindowFullScreen)
self.info.setWindowState(Qt.WindowFullScreen)
@Slot() @Slot()
def hide_mouse(self) -> None: def hide_mouse(self) -> None:

6
uv.lock generated
View File

@ -1237,7 +1237,7 @@ wheels = [
[[package]] [[package]]
name = "manim-slides" name = "manim-slides"
version = "5.1.9" version = "5.1.10"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "av" }, { name = "av" },
@ -1433,6 +1433,8 @@ dependencies = [
] ]
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/31/c9/ef3fbd0ee64bc64f2fcc6699e7ebbeb81c86f60abf79a624bab5039a047f/manimgl-1.6.1-py310-none-any.whl", hash = "sha256:8f1cd581b1656bf8b091b88909c96f3579b1a273e55b2ae9d55519bd4f2fe84c", size = 235947 }, { url = "https://files.pythonhosted.org/packages/31/c9/ef3fbd0ee64bc64f2fcc6699e7ebbeb81c86f60abf79a624bab5039a047f/manimgl-1.6.1-py310-none-any.whl", hash = "sha256:8f1cd581b1656bf8b091b88909c96f3579b1a273e55b2ae9d55519bd4f2fe84c", size = 235947 },
{ url = "https://files.pythonhosted.org/packages/f2/5c/a29270cd293c85682d4e748cb939d8714bcdfe1ab95865317f8abfe9b522/manimgl-1.6.1-py37-none-any.whl", hash = "sha256:4d152b7191d922a78efb3b421a7db33b354ee54aecfe8806f86ec7b656b9c2d3", size = 235947 },
{ url = "https://files.pythonhosted.org/packages/00/2b/178c745905e99eef035698f1b794fcf631b2dd786dc123ecf180311b8017/manimgl-1.6.1-py38-none-any.whl", hash = "sha256:78f1a069ea97810c8bccd2e415e40b9c5d03ee7d485b0c5c16674ff786cd3a9b", size = 235944 },
{ url = "https://files.pythonhosted.org/packages/1c/2c/b427f44673d2206cd19bfa58d8a53a35940bae5f115c71e68315fc8403bf/manimgl-1.6.1-py39-none-any.whl", hash = "sha256:b53deef6bb015859c397b0c7fc918005169969468aee81307636457eeea0435c", size = 235946 }, { url = "https://files.pythonhosted.org/packages/1c/2c/b427f44673d2206cd19bfa58d8a53a35940bae5f115c71e68315fc8403bf/manimgl-1.6.1-py39-none-any.whl", hash = "sha256:b53deef6bb015859c397b0c7fc918005169969468aee81307636457eeea0435c", size = 235946 },
] ]
@ -2175,8 +2177,6 @@ version = "6.0.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/18/c7/8c6872f7372eb6a6b2e4708b88419fb46b857f7a2e1892966b851cc79fc9/psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", size = 508067 } sdist = { url = "https://files.pythonhosted.org/packages/18/c7/8c6872f7372eb6a6b2e4708b88419fb46b857f7a2e1892966b851cc79fc9/psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", size = 508067 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/c5/66/78c9c3020f573c58101dc43a44f6855d01bbbd747e24da2f0c4491200ea3/psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", size = 249766 },
{ url = "https://files.pythonhosted.org/packages/e1/3f/2403aa9558bea4d3854b0e5e567bc3dd8e9fbc1fc4453c0aa9aafeb75467/psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1", size = 253024 },
{ url = "https://files.pythonhosted.org/packages/0b/37/f8da2fbd29690b3557cca414c1949f92162981920699cd62095a984983bf/psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", size = 250961 }, { url = "https://files.pythonhosted.org/packages/0b/37/f8da2fbd29690b3557cca414c1949f92162981920699cd62095a984983bf/psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", size = 250961 },
{ url = "https://files.pythonhosted.org/packages/35/56/72f86175e81c656a01c4401cd3b1c923f891b31fbcebe98985894176d7c9/psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", size = 287478 }, { url = "https://files.pythonhosted.org/packages/35/56/72f86175e81c656a01c4401cd3b1c923f891b31fbcebe98985894176d7c9/psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", size = 287478 },
{ url = "https://files.pythonhosted.org/packages/19/74/f59e7e0d392bc1070e9a70e2f9190d652487ac115bb16e2eff6b22ad1d24/psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", size = 290455 }, { url = "https://files.pythonhosted.org/packages/19/74/f59e7e0d392bc1070e9a70e2f9190d652487ac115bb16e2eff6b22ad1d24/psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", size = 290455 },