Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
144 commits
Select commit Hold shift + click to select a range
d6086dd
Add windows compatibility
joellkp Jun 25, 2025
c392246
Add windows compatibility
joellkp Jun 25, 2025
5d96d89
Add windows compatibility
joellkp Jun 25, 2025
2d03986
Add visualizer and yaml editor base
joellkp Jul 5, 2025
39ade81
add: resources submodule
Doralitze Jul 8, 2025
ce50922
chg: model path
Doralitze Jul 19, 2025
9f2044e
mrg: branch 'main' into visualizer
Doralitze Aug 2, 2025
ffbe6dc
Rebase
joellkp Jul 5, 2025
dd4eb92
add: resources submodule
Doralitze Jul 8, 2025
c10dd89
chg: model path
Doralitze Jul 19, 2025
0cf8fce
Add visualizer and yaml editor base
joellkp Oct 16, 2025
b8ceb3d
Add visualizer and yaml editor base
joellkp Oct 16, 2025
18ac80d
a
joellkp Oct 16, 2025
89e4ff7
test class
joellkp Oct 23, 2025
966fe69
Add visualizer and yaml editor base
joellkp Jul 5, 2025
a18c3b3
chg: model path
Doralitze Jul 19, 2025
fbcf593
a
joellkp Oct 16, 2025
4f24d7f
test class
joellkp Oct 23, 2025
bfd4e8a
Merge remote-tracking branch 'origin/visualizer2' into visualizer2
joellkp Oct 24, 2025
a5f7ebb
add: option to remove assets
Doralitze Jan 10, 2026
63f36dd
add: option to edit icons of macro buttons
Doralitze Jan 10, 2026
66caaf5
add: dialog to ask for exit
Doralitze Jan 10, 2026
f1c056e
fix: duplicate declaration of closing event in main
Doralitze Jan 12, 2026
25f4180
fix: main window close callback to be private
Doralitze Jan 15, 2026
4162cf6
Merge branch 'refs/heads/main' into visualizer2
joellkp Jan 20, 2026
5afc4c6
add: dmx default value support to scene model
Doralitze Apr 15, 2026
e474638
mrg: branch '169-color-to-color-wheel-adapter-v-filter' into scene-de…
Doralitze Apr 15, 2026
c17dd43
mrg: branch 'media-asset-config-ui' into scene-default-dmx-values
Doralitze Apr 15, 2026
bf70dc5
mrg: branch 'dimmer-brightness-mixin-vfilter' into scene-default-dmx-…
Doralitze Apr 15, 2026
4270515
fix: ruff issues
Doralitze Apr 15, 2026
91ff1d5
add: skeleton
Doralitze Apr 15, 2026
81e7154
add: tab loading and closing mechanics
Doralitze Apr 15, 2026
1722447
add: crude editing UI
Doralitze Apr 15, 2026
fadad97
fix: inverted update bug
Doralitze Apr 15, 2026
4ce9b85
fix: docs in showmanager.py
Doralitze Apr 15, 2026
650b463
fix: typo
Doralitze Apr 15, 2026
4521faf
add: entry removal option
Doralitze Apr 16, 2026
d63816c
add: default mapping from console
Doralitze Apr 16, 2026
eb70c82
init
joellkp Apr 19, 2026
da301da
add: reasonable error message for missing fixture definitions
Doralitze Apr 20, 2026
19affa7
fix: saving of show files
Doralitze Apr 21, 2026
a1463fb
fix: context menu for single value add
Doralitze Apr 21, 2026
ad03e57
chg: dmx update in 45hz
joellkp May 3, 2026
34fa4c9
add: documentation updates
Doralitze May 4, 2026
e9fcd6e
fix: typo
Doralitze May 4, 2026
b3b80ad
add: switch filter nodes
Doralitze May 5, 2026
5399dc7
fix: possible entering of invalid numbers
Doralitze May 5, 2026
62e0091
add: chaser filter type to type enum
Doralitze May 6, 2026
127d0d7
add: chaser filter node
Doralitze May 6, 2026
626a042
add: initial chaser filter model
Doralitze May 6, 2026
cd9a51d
add: layers table for further usage in GUI
Doralitze May 6, 2026
f639164
add: chaser_layer_help resource link
Doralitze May 7, 2026
5c02a19
add: layout prototype
Doralitze May 7, 2026
7f36eb4
add: missing chaser model serialization
Doralitze May 7, 2026
a2678b6
upd: resources submodule version
Doralitze May 8, 2026
84c96cc
add: event selection button
Doralitze May 9, 2026
d9de2e0
add: parameter container widgets
Doralitze May 9, 2026
a2161b2
Merge branch 'main' into scene-default-dmx-values
CorsCodini May 10, 2026
34be0b4
mrg: branch 'main' into 268-mux-filter-missing
Doralitze May 11, 2026
06b475d
fix: import order after merge
Doralitze May 11, 2026
7dd3700
fix: missing module doc string in routing nodes
Doralitze May 11, 2026
b43f257
Merge branch 'main' into media-asset-config-ui
Doralitze May 11, 2026
a5405bb
del: redundant lambda
Doralitze May 11, 2026
6521fbf
mrg: branch 'main' into scene-default-dmx-values
Doralitze May 11, 2026
6158a02
fix: docs in model/universe.py
Doralitze May 11, 2026
8317927
mrg: branch 'main' into 389-add-chaser-editor
Doralitze May 11, 2026
a70cdb9
Merge branch 'main' into visualizer1
Doralitze May 11, 2026
98a3626
fix: ruff issues in chaser model
Doralitze May 11, 2026
99b25c0
add: recently used files log
Doralitze May 11, 2026
75d9c1b
fix: docs
Doralitze May 11, 2026
bcdaffa
add: custom list rendering
Doralitze May 11, 2026
43ce461
fix: import order
Doralitze May 11, 2026
a1eb018
add: persistence check box to cue editor
Doralitze May 12, 2026
5652db9
chg: gif loading to be opportunistic
Doralitze May 13, 2026
6f8d6a3
add: functionality to parameter mgmt
Doralitze May 13, 2026
02699b0
chg: display preview query only if parameters configured
Doralitze May 13, 2026
e92377c
add: layer list to ChaserConfigWidget
Doralitze May 13, 2026
38ca5f5
fix: crash on outdated fixture loading (missing mode)
Doralitze May 14, 2026
106f6cf
upd: docs of fixture.mode
Doralitze May 14, 2026
c2997a4
fix: ruff issues
Doralitze May 14, 2026
babc001
del: redundant variable
Doralitze May 14, 2026
f103fe4
fix: event renaming
Doralitze May 14, 2026
0d43d8e
add: Percent Number Parameter Widget
Doralitze May 14, 2026
c45fd5d
chg: refactored classes to be in separate file
Doralitze May 15, 2026
61e81c5
chg: both number parameter widgets to share common base class
Doralitze May 15, 2026
ed28050
add: towards color parameter widget
Doralitze May 15, 2026
fc38fcf
add: preset selection logic
Doralitze May 15, 2026
33a74f3
mrg: branch 'main' into 389-add-chaser-editor
Doralitze May 15, 2026
582d552
add: color parameter widget change logic
Doralitze May 15, 2026
dbc413b
add: dialog stub
Doralitze May 15, 2026
6d27587
add: delete actions for layers and config
Doralitze May 15, 2026
7885b4a
fix: various issues
Doralitze May 15, 2026
95c5743
fix: layout
Doralitze May 15, 2026
8c9f611
fix: parameter settings widgets
Doralitze May 16, 2026
018d4eb
fix: gifs not rendering
Doralitze May 16, 2026
6b6e257
add: test button
Doralitze May 16, 2026
f948198
add: preset names
Doralitze May 16, 2026
8a13c85
add: extract command
Doralitze May 16, 2026
9132370
add: chaser update insert command dialog
Doralitze May 16, 2026
3c7ed2c
fix: variant data editing
Doralitze May 16, 2026
54b05f0
add: chaser preset UI widget
Doralitze May 17, 2026
147beb5
add: preset list ui widget final
Doralitze May 18, 2026
bb8f77e
fix: broken apply
Doralitze May 18, 2026
1f5fee2
fix: lambda layout
Doralitze May 19, 2026
139b306
fix: layer removal
Doralitze May 19, 2026
3275862
fix: missing mask mod parameters
Doralitze May 19, 2026
62fe501
add: live config uiwidget prototype
Doralitze May 19, 2026
362757b
chg: layer param list separator to line
Doralitze May 19, 2026
e997c13
add: layer up / down buttons
Doralitze May 19, 2026
b6a209f
add: show export feature
Doralitze May 21, 2026
1c0c7c2
fix: docs
Doralitze May 21, 2026
b66d4f2
add: Fruchterman-Reingold prototype
Doralitze May 21, 2026
9ec3852
chg: sort action to be part of show browser
Doralitze May 21, 2026
865cf51
add: ELK method
Doralitze May 21, 2026
ba7d12d
fix: crash on button list inst
Doralitze May 21, 2026
f00c938
fix: instantiation of wrong widget
Doralitze May 21, 2026
b4d88cf
fix: widget rendering
Doralitze May 21, 2026
adfbee4
add: down state for select buttons
Doralitze May 22, 2026
f222e9f
add: enabling / disabling of response for number consts
Doralitze May 22, 2026
5a3f579
mrg: branch 'media-asset-config-ui' into coal26-megabranch
Doralitze May 22, 2026
930e687
mrg: branch 'scene-default-dmx-values' into coal26-megabranch
Doralitze May 22, 2026
9a1e0c0
mrg: branch '268-mux-filter-missing' into coal26-megabranch
Doralitze May 22, 2026
1fcace4
mrg: branch '389-add-chaser-editor' into coal26-megabranch
Doralitze May 22, 2026
2465da0
mrg: branch 'save-recently-opened-files' into coal26-megabranch
Doralitze May 22, 2026
0f48eb3
mrg: branch 'cue-editor-persitence-setting' into coal26-megabranch
Doralitze May 22, 2026
d37984c
mrg: branch 'fix-event-rename-feature' into coal26-megabranch
Doralitze May 22, 2026
a3fc945
mrg: branch 'export-standalone-show' into coal26-megabranch
Doralitze May 22, 2026
06bb700
fix: import order after merge
Doralitze May 22, 2026
87b7d8d
mrg: branch 'filterpage-graph-sorting' into coal26-megabranch
Doralitze May 22, 2026
f3224ef
fix: import order after merge
Doralitze May 22, 2026
0212831
mrg: branch '393-add-responding-constant-filter-nodes' into coal26-me…
Doralitze May 22, 2026
f20ff6a
mrg: branch 'visualizer1' into coal26-megabranch
Doralitze May 22, 2026
069e64f
add: kf from image skeleton
Doralitze May 22, 2026
9e21d2a
add: radio buttons
Doralitze May 22, 2026
7743869
add: generate_keyframes_from_image prototype
Doralitze May 23, 2026
a5dab8c
add: accept and reject buttons
Doralitze May 23, 2026
7f28065
add: towards reasonable error messages
Doralitze May 24, 2026
b4a704c
fix: asset selection and kf from image
Doralitze May 24, 2026
7daeae9
fix: save default values button not working with newer Qt version
Doralitze May 25, 2026
0195b1d
fix: fixture to filter not instantiating rgbw adapters
Doralitze May 25, 2026
e5c11a2
add: mod filter to div command
Doralitze May 25, 2026
4003b44
fix: crash on CLI exception in remote terminal
Doralitze May 25, 2026
a543cd8
fix: image underflow if specified column break
Doralitze May 26, 2026
e91dd8b
fix: pixel mapping break
Doralitze May 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/build_docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: CI Pipeline

on:
push:
branches: [ main ]


jobs:
read-commit:
runs-on: [self-hosted]
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
submodules: true

- name: Build Documentation
run: doxygen Doxyfile

- name: Deploy class documentation
run: cd docs-build/html && sudo /home/deploy/deploy.bash . docs/editor-class-doc
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ __pycache__/

# Distribution / packaging
.Python
docs-build/
build/
develop-eggs/
dist/
Expand Down
2,863 changes: 2,863 additions & 0 deletions Doxyfile

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Project-Editor.spec
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
added_files = [
( 'src/resources/' , 'resources'),
( 'src/resources/autotrack_models', 'resources/autotrack_models' ),
( 'src/resources/3dmodels', 'resources/3dmodels' ),
( 'src/resources/data', 'resources/data' ),
( 'src/resources/fonts', 'resources/fonts' ),
( 'src/resources/icons', 'resources/icons' ),
( 'src/resources/chaser_layer_help', 'resources/chaser_layer_help' ),
( 'src/configs','configs')
]

Expand Down
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ authors = [
{ name = "CorsCodini", email = "cors.codini@web.de" },
{ name = "Niklas Naumann", email = "niklas.naumann@student.uni-luebeck.de" },
{ name = "Doralitze", email = "doralitze@chaotikum.org" },
{ name = "Ludwig Rahlff"},
{ name = "Joell Keanu"},
]

requires-python = "==3.13.*"
Expand All @@ -18,7 +20,7 @@ dependencies = [
"xmlschema>=3.4.5",
"requests>=2.32.3",
"numpy>=2.2.4",
"ruamel-yaml>=0.18.10",
"ruamel-yaml>=0.18.14",
"html2text>=2024.2.26",
"markdown>=3.7",
"typing-extensions>=4.13.1",
Expand All @@ -31,10 +33,12 @@ dependencies = [
"pyjoystick>=1.2.4",
"pyopengl>=3.1.9",
"onnxruntime-openvino>=1.21.0",
"PySDL2>=0.9.17",
"pydantic>=2.11.7",
"defusedxml>=0.7.1",
"tzlocal>=5.3.1",
"jinja2>=3.1.6",
"pyelk>=0.3",
]

[dependency-groups]
Expand Down
2 changes: 2 additions & 0 deletions src/controller/cli/cli_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from controller.cli.bankset_command import BankSetCommand
from controller.cli.connect_command import ConnectCommand
from controller.cli.event_command import EventCommand
from controller.cli.extract_command import ExtractCommand
from controller.cli.fish_con_command import FishConnCommand
from controller.cli.help_command import HelpCommand
from controller.cli.list_command import ListCommand
Expand Down Expand Up @@ -106,6 +107,7 @@ def __init__(self, show: BoardConfiguration, network_manager: NetworkManager, ex
ConnectCommand(self),
FishConnCommand(self),
UIPageCommand(self),
ExtractCommand(self),
]
self._selected_bank: BankSet | None = None
self._selected_scene: Scene | None = None
Expand Down
4 changes: 4 additions & 0 deletions src/controller/cli/connect_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def _mul(value: str, arg: str) -> str:
def _div(value: str, arg: str) -> str:
return str(int(int(value) / int(arg)))

def _mod(value: str, arg: str) -> str:
return str(int(int(value) % int(arg)))

class ConnectCommand(Command):
"""Command to connect filters."""

Expand All @@ -41,6 +44,7 @@ def __init__(self, context: CLIContext) -> None:
self._jinja_env.filters["sub"] = _sub
self._jinja_env.filters["mul"] = _mul
self._jinja_env.filters["div"] = _div
self._jinja_env.filters["mod"] = _mod

@override
def configure_parser(self, parser: ArgumentParser) -> None:
Expand Down
67 changes: 67 additions & 0 deletions src/controller/cli/extract_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Contains extract command."""

from __future__ import annotations

from typing import TYPE_CHECKING, override

from controller.cli.command import Command

if TYPE_CHECKING:
from argparse import ArgumentParser, Namespace

from controller.cli.cli_context import CLIContext


class ExtractCommand(Command):
"""Command to extract element from list."""

def __init__(self, context: CLIContext) -> None:
"""Initialize the command."""
super().__init__(context, "extract")
self._help_text = "Extract element from list"

@override
def configure_parser(self, parser: ArgumentParser) -> None:
parser.add_argument("destination", type=str, help="Destination variable.")
parser.add_argument("element", type=int, help="Index of element to extract.")
subparsers = parser.add_subparsers(dest="target", help="Extraction target.")
for target in ["filter-param", "filter-config"]:
filter_param_parser = subparsers.add_parser(
target,
help=f"Extract {target} from filter.",
exit_on_error=False
)
filter_param_parser.add_argument("--scene", type=int, default=-1,
help="Scene of the filter. Default: Current selected scene.")
filter_param_parser.add_argument("fid", type=str, help="Filter ID.")
filter_param_parser.add_argument("parameter", type=str, help="The parameter to extract.")
filter_param_parser.add_argument("delimiter", type=str, help="The delimiter to use.")

@override
def execute(self, args: Namespace) -> bool:
match args.target:
case "filter-param" | "filter-config":
scene = args.scene
if scene == -1:
scene = self.context.selected_scene
if scene is None:
self.context.print("Error: No scene specified.")
return False
if isinstance(scene, int):
scene = self.context.show.get_scene_by_id(scene)
if scene is None:
self.context.print("Error: No scene with specified ID exists.")
return False
filter_inst = scene.get_filter_by_id(args.fid)
if filter_inst is None:
self.context.print(f"Error: No filter with ID '{args.fid}' not found.")
return False
selected_dict = filter_inst.initial_parameters if args.target == "filter-param"\
else filter_inst.filter_configurations
splitted_param = selected_dict.get(args.parameter, "").split(args.delimiter)
element = splitted_param[args.element] if abs(args.element) < len(splitted_param) else ""
if len(args.destination) < 0:
self.context.print("Error: Invalid destination variable.")
return False
self.context.update_variables({args.destination: element})
return True
9 changes: 8 additions & 1 deletion src/controller/cli/help_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ def execute(self, args: Namespace) -> bool:
self.context.print("\tscene -- Select the scene to perform actions on")
self.context.print("\tcolumn -- Select the control desk column to perform actions on")
self.context.print("\tbank_set -- Select the control desk bank set to perform actions on")
case "extract":
self.context.print("Use this command to extract data from concatenated lists and store it in the "
"specified destination variable.")
self.context.print("Usage: extract <destination> <element> <target> <...>")
self.context.print("The following targets exist:")
self.context.print("\tfilter-param [--scene <scene>] <filter-id> <parameter> <delimiter>")
self.context.print("\tfilter-config [--scene <scene>] <filter-id> <parameter> <delimiter>")
case "list":
self.context.print("This command displays the content of system collections.")
self.context.print("The following containers can be queried:")
Expand Down Expand Up @@ -99,6 +106,6 @@ def execute(self, args: Namespace) -> bool:
self.context.print(f"ERROR: The requested help topic '{args.topic}' is unknown.")
self.context.print("The following topics are known:")
self.context.print("\tevent\tselect\tlist\tpatch\tbank_set\tshowctl\tdelay\tmacro")
self.context.print("\tprint\tasset\tset\tif\tconnect\tfish\tuipage")
self.context.print("\tprint\tasset\tset\tif\tconnect\tfish\tuipage\textract")
return False
return True
2 changes: 1 addition & 1 deletion src/controller/cli/remote_control_port.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
except OSError:
pass
except UnicodeDecodeError as e:
self._client.send("Unable to decode command. Exiting.")
self._client.send("Unable to decode command. Exiting.".encode())

Check failure on line 149 in src/controller/cli/remote_control_port.py

View workflow job for this annotation

GitHub Actions / test_on_main_pr

ruff (UP012)

src/controller/cli/remote_control_port.py:149:31: UP012 Unnecessary call to `encode` as UTF-8 help: Rewrite as bytes literal
self._client.close()
logger.exception("Failed to decode CLI command. %s", e)
finally:
Expand Down
37 changes: 29 additions & 8 deletions src/controller/file/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

import xmlschema
from defusedxml.ElementTree import parse
from PySide6.QtWidgets import QMessageBox

import proto.Console_pb2
import proto.UniverseControl_pb2
from controller.file.deserialization.migrations import replace_old_filter_configurations
from controller.file.deserialization.post_load_operations import link_patched_fixtures
from controller.file.recently_used import register_opened_file
from controller.utils.process_notifications import get_process_notifier
from model import BoardConfiguration, Filter, Scene, UIPage, Universe
from model.color_hsi import ColorHSI
Expand All @@ -21,7 +23,7 @@
from model.media_assets.asset_loading_factory import load_asset
from model.media_assets.factory_hint import AssetFactoryObjectHint
from model.media_assets.registry import clear as clear_media_registry
from model.ofl.fixture import load_fixture, make_used_fixture
from model.ofl.fixture import FixtureDefNotFoundError, load_fixture, make_used_fixture
from model.scene import FilterPage
from model.virtual_filters.vfilter_factory import construct_virtual_filter_instance
from utility import resource_path
Expand Down Expand Up @@ -175,6 +177,7 @@ def read_document(file_name: str, board_configuration: BoardConfiguration) -> bo
logger.exception("Unable to update show UI window count: %s", e)
update_window_count(0, board_configuration)
board_configuration.broadcaster.show_file_loaded.emit()
register_opened_file(file_name)
pn.close()
return True

Expand Down Expand Up @@ -265,6 +268,14 @@ def _parse_filter_page(element: ET.Element, parent_scene: Scene, instantiated_pa
return True


def _parse_dmx_default_value(scene: Scene, child: ET.Element) -> None:
scene.insert_dmx_default_value(
int(child.attrib["universe"]),
int(child.attrib["channel"]),
int(child.attrib["value"])
)


def _parse_scene(
scene_element: ET.Element, board_configuration: BoardConfiguration, loaded_banksets: dict[str, BankSet]
) -> None:
Expand Down Expand Up @@ -301,6 +312,8 @@ def _parse_scene(
filter_pages.append(child)
case "uipage":
ui_page_elements.append(child)
case "dmxdefaultvalue":
_parse_dmx_default_value(scene, child)
case _:
logger.warning("Scene %s contains unknown element: %s", human_readable_name, child.tag)

Expand Down Expand Up @@ -652,13 +665,21 @@ def _parse_patching(board_configuration: BoardConfiguration, location_element: E
fixtures_path = "/var/cache/missionDMX/fixtures" # TODO config file

for child in location_element:
make_used_fixture(
board_configuration,
load_fixture(os.path.join(fixtures_path, child.attrib["fixture_file"])),
int(child.attrib["mode"]),
universe_id,
int(child.attrib["start"]),
)
try:
make_used_fixture(
board_configuration,
load_fixture(os.path.join(fixtures_path, child.attrib["fixture_file"])),
int(child.attrib["mode"]),
universe_id,
int(child.attrib["start"]),
)
except FixtureDefNotFoundError as e:
# Calling Dialog exec is not an issue here as we're in the process of loading the show file anyway
mb = QMessageBox(QMessageBox.Icon.Critical, "Failed to load fixture", str(e) +
"\n\nDo not continue until this error is fixed as the show is now corrupted.\nMaybe try "
"updating the fixture database.")
mb.exec_()
continue

# TODO load fixture name from file

Expand Down
47 changes: 47 additions & 0 deletions src/controller/file/recently_used.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Provides functions to query and update recently used files."""

from __future__ import annotations

import os

_STORAGE_PATH = os.path.join(os.path.expanduser("~"), ".local", "share", "missionDMX")
_STORAGE_FILE = os.path.join(_STORAGE_PATH, "recently_used.list")

if not os.path.exists(_STORAGE_PATH):
os.makedirs(_STORAGE_PATH, mode=0o770, exist_ok=True)

if not os.path.exists(_STORAGE_FILE):
with open(_STORAGE_FILE, "w") as f:
f.write("")
del f

def get_recently_used_files() -> list[str]:
"""Method returns the list of recently used files.

Returns:
A list of the recently used files in descending order.

"""
real_entries = []
with open(_STORAGE_FILE, "r") as f:
entries = f.readlines()
for entry in entries:
if entry.strip() == "":
continue
real_entries.append(entry.replace("\n", ""))
return real_entries

def register_opened_file(path: str) -> None:
"""Registers a file as being opened.

Args:
path: The path to the file which was opened.

"""
path = os.path.expanduser(path.strip())
existing_entries = get_recently_used_files()
new_entries = [path]
new_entries.extend(f"\n{entry}" for i, entry in enumerate(existing_entries) if
entry.strip() != "" and entry != path and i < 10)
with open(_STORAGE_FILE, "w") as output_file:
output_file.writelines(new_entries)
7 changes: 7 additions & 0 deletions src/controller/file/serializing/scene_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ def generate_scene_xml_description(

for ui_page in scene.ui_pages:
_add_ui_page_to_element(scene_element, ui_page)
scene.sort_dmx_default_values()
for default_value in scene.dmx_default_values:
ET.SubElement(scene_element, "dmxdefaultvalue", attrib={
"universe": str(default_value.universe_id),
"channel": str(default_value.channel),
"value": str(default_value.value),
})


def _create_scene_element(scene: Scene, parent: ET.Element) -> ET.Element:
Expand Down
12 changes: 11 additions & 1 deletion src/controller/file/showfile_dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from PySide6.QtWidgets import QFileDialog, QWidget

from controller.file.read import read_document
from controller.file.write import write_document
from controller.file.write import export_document, write_document
from model import BoardConfiguration


Expand Down Expand Up @@ -78,3 +78,13 @@ def show_load_showfile_dialog(parent: QWidget, show_data: BoardConfiguration) ->

"""
_select_file(parent, _load_show_file, False, show_data)

def open_show_export_dialog(parent: QWidget, show_data: BoardConfiguration) -> None:
"""Opens a dialog to export the provided show by fish in standalone mode."""
file_dialog = QFileDialog(parent, "Export Show")
file_dialog.setNameFilter("Fish Standalone Show (*.fs)")
file_dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptSave)
file_dialog.setDefaultSuffix(".fs")
file_dialog.setDirectory(os.path.expanduser("~"))
file_dialog.fileSelected.connect(lambda file_name: export_document(file_name, show_data))
file_dialog.show()
Loading
Loading