Files
Jérome Eertmans 802f6406ae refactor(lib): change how manim API is imported (#285)
* refactor(lib): change how manim API is imported

* chore(lib): delete old files

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

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

* wip: moving all commands

* adding animations

* fix tests

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

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

* fix mypy

* fixes

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

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

* trying to fix docs

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

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

* wip: docs

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

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

* make it work

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

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

* wip test

* tests are working

* improving docs

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

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

* fix index

* docs: nicer shift

* docs: nicer quickstart example

* fix tests

* change tests

* move coverage to test workflow

* fix(tests): remove resolve

* strict resolve

* change local path test

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

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

* documented changes

* cleanup docs

* cleanup files

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

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

* fix(ci): set type

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-17 16:06:19 +02:00

196 lines
5.6 KiB
Python

import sys
from functools import partial
from pathlib import Path
from typing import Any
import click
from PySide6.QtCore import Qt
from PySide6.QtGui import QIcon, QKeyEvent
from PySide6.QtWidgets import (
QApplication,
QDialog,
QDialogButtonBox,
QGridLayout,
QLabel,
QMessageBox,
QPushButton,
QVBoxLayout,
QWidget,
)
from .commons import config_options, verbosity_option
from .config import Config, Key
from .defaults import CONFIG_PATH
from .logger import logger
from .resources import * # noqa: F401, F403
WINDOW_NAME: str = "Configuration Wizard"
keymap = {}
for key in Qt.Key:
keymap[key.value] = key.name.partition("_")[2]
class KeyInput(QDialog): # type: ignore
def __init__(self) -> None:
super().__init__()
self.key = None
self.layout = QVBoxLayout()
self.setWindowTitle("Keyboard Input")
self.label = QLabel("Press any key to register it")
self.layout.addWidget(self.label)
self.setLayout(self.layout)
def keyPressEvent(self, event: QKeyEvent) -> None:
self.key = event.key()
self.deleteLater()
event.accept()
class Wizard(QWidget): # type: ignore
def __init__(self, config: Config):
super().__init__()
self.setWindowTitle(WINDOW_NAME)
self.config = config
self.icon = QIcon(":/icon.png")
self.setWindowIcon(self.icon)
QBtn = QDialogButtonBox.Save | QDialogButtonBox.Cancel
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.saveConfig)
self.buttonBox.rejected.connect(self.closeWithoutSaving)
self.buttons = []
self.layout = QGridLayout()
for i, (key, value) in enumerate(self.config.keys.dict().items()):
# Create label for key name information
label = QLabel()
key_info = value["name"] or key
label.setText(key_info.title())
self.layout.addWidget(label, i, 0)
# Create button that will pop-up a dialog and ask to input a new key
value = value["ids"].pop()
button = QPushButton(keymap[value])
button.setToolTip(
f"Click to modify the key associated to action {key_info}"
)
self.buttons.append(button)
button.clicked.connect(
partial(self.openDialog, i, getattr(self.config.keys, key))
)
self.layout.addWidget(button, i, 1)
self.layout.addWidget(self.buttonBox, len(self.buttons), 1)
self.setLayout(self.layout)
def closeWithoutSaving(self) -> None:
logger.debug("Closing configuration wizard without saving")
self.deleteLater()
sys.exit(0)
def closeEvent(self, event: Any) -> None:
self.closeWithoutSaving()
event.accept()
def saveConfig(self) -> None:
try:
Config.model_validate(self.config.dict())
except ValueError:
msg = QMessageBox()
msg.setIcon(QMessageBox.Critical)
msg.setText("Error")
msg.setInformativeText(
"Two or more actions share a common key: make sure actions have distinct key codes."
)
msg.setWindowTitle("Error: duplicated keys")
msg.exec_()
return
self.deleteLater()
def openDialog(self, button_number: int, key: Key) -> None:
button = self.buttons[button_number]
dialog = KeyInput()
dialog.exec_()
if dialog.key is not None:
key_name = keymap[dialog.key]
key.set_ids(dialog.key)
button.setText(key_name)
@click.command()
@config_options
@click.help_option("-h", "--help")
@verbosity_option
def wizard(config_path: Path, force: bool, merge: bool) -> None:
"""Launch configuration wizard."""
return _init(config_path, force, merge, skip_interactive=False)
@click.command()
@config_options
@click.help_option("-h", "--help")
@verbosity_option
def init(
config_path: Path, force: bool, merge: bool, skip_interactive: bool = False
) -> None:
"""Initialize a new default configuration file."""
return _init(config_path, force, merge, skip_interactive=True)
def _init(
config_path: Path, force: bool, merge: bool, skip_interactive: bool = False
) -> None:
"""Actual initialization code for configuration file, with optional interactive
mode."""
if config_path.exists():
click.secho(f"The `{CONFIG_PATH}` configuration file exists")
if not force and not merge:
choice = click.prompt(
"Do you want to continue and (o)verwrite / (m)erge it, or (q)uit?",
type=click.Choice(["o", "m", "q"], case_sensitive=False),
)
force = choice == "o"
merge = choice == "m"
if not force and not merge:
logger.debug("Exiting without doing anything")
sys.exit(0)
config = Config()
if force:
logger.debug(f"Overwriting `{config_path}` if exists")
elif merge:
logger.debug("Merging new config into `{config_path}`")
if not skip_interactive:
if config_path.exists():
config = Config.from_file(config_path)
app = QApplication(sys.argv)
app.setApplicationName("Manim Slides Wizard")
window = Wizard(config)
window.show()
app.exec()
config = window.config
if merge:
config = Config.from_file(config_path).merge_with(config)
config.to_file(config_path)
click.secho(f"Configuration file successfully saved to `{config_path}`")