Skip to content

Commit 49e5483

Browse files
authored
mrg: pull request #376 from Mission-DMX/media-asset-config-ui
Add dialog to open assets
2 parents e12879c + c317ec5 commit 49e5483

4 files changed

Lines changed: 109 additions & 6 deletions

File tree

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""Contains the asset management dialog."""
2+
3+
from __future__ import annotations
4+
5+
import os
6+
7+
from PySide6.QtGui import QAction, QIcon
8+
from PySide6.QtWidgets import QDialog, QDialogButtonBox, QFileDialog, QMessageBox, QToolBar, QVBoxLayout, QWidget
9+
10+
from controller.utils.process_notifications import ProcessNotifier, get_process_notifier
11+
from model.media_assets.image import LocalImage
12+
from model.media_assets.media_type import MediaType
13+
from view.utility_widgets.asset_selection_widget import AssetSelectionWidget
14+
15+
_SUPPORTED_FILE_ENDINGS: dict[MediaType, list[str]] = {
16+
MediaType.TEXT: [".txt"],
17+
MediaType.IMAGE: [".jpg", ".jpeg", ".png", ".bmp", ".gif", ".pbm", ".pgm", ".ppm", ".xbm", ".xpm"],
18+
MediaType.VIDEO: [".mp4"],
19+
MediaType.AUDIO: [".wav", ".mp3", ".flac"],
20+
MediaType.MODEL_3D: [".stl", ".obj"]
21+
}
22+
23+
24+
class AssetManagementDialog(QDialog):
25+
"""Provide a GUI method to manage assets."""
26+
27+
def __init__(self, parent: QWidget | None = None, show_file_path: str | None = None) -> None:
28+
"""Initialize the asset management dialog."""
29+
super().__init__(parent)
30+
layout = QVBoxLayout()
31+
32+
self._action_button_group = QToolBar()
33+
34+
self._load_asset_file = QAction()
35+
self._load_asset_file.setIcon(QIcon.fromTheme("document-open"))
36+
self._load_asset_file.setText("Load asset from file")
37+
self._load_asset_file.triggered.connect(self._open_file)
38+
self._action_button_group.addAction(self._load_asset_file)
39+
40+
layout.addWidget(self._action_button_group)
41+
42+
self._asset_display = AssetSelectionWidget(self)
43+
layout.addWidget(self._asset_display)
44+
45+
self._close_button_group = QDialogButtonBox(QDialogButtonBox.StandardButton.Close)
46+
self._close_button_group.button(QDialogButtonBox.StandardButton.Close).clicked.connect(self.close)
47+
layout.addWidget(self._close_button_group)
48+
49+
self.setLayout(layout)
50+
self.setModal(True)
51+
self._dialog: QFileDialog | None = None
52+
self._show_file_path = show_file_path if show_file_path is not None else ""
53+
self.setMinimumWidth(800)
54+
55+
def _open_file(self) -> None:
56+
self._dialog = QFileDialog(self, "Open file")
57+
self._dialog.setModal(True)
58+
self._dialog.setNameFilters(
59+
[f"{k.get_long_description()} ({" ".join(f"*{va}" for va in v)})"
60+
for k, v in _SUPPORTED_FILE_ENDINGS.items()]
61+
)
62+
self._dialog.setDefaultSuffix(".jpg")
63+
self._dialog.setFileMode(QFileDialog.FileMode.ExistingFiles)
64+
self._dialog.setDirectory(os.path.expanduser("~") if self._show_file_path is None else self._show_file_path)
65+
self._dialog.filesSelected.connect(self._process_loading_files)
66+
self._dialog.open()
67+
68+
def _process_loading_files(self, list_of_files: list[str]) -> None:
69+
self._dialog.close()
70+
if len(list_of_files) == 0:
71+
return
72+
accumulated_errors = ""
73+
pn = get_process_notifier("Asset Loading", len(list_of_files))
74+
for file_path in list_of_files:
75+
pn.current_step_description = f"Loading Asset from {file_path}"
76+
extension = os.path.splitext(file_path)[1]
77+
try:
78+
if extension in _SUPPORTED_FILE_ENDINGS[MediaType.IMAGE]:
79+
LocalImage(file_path, show_file_path=self._show_file_path)
80+
else:
81+
accumulated_errors += f"Unable to load asset from {file_path}: extension {extension} unknown.\n"
82+
except Exception as e:
83+
accumulated_errors += f"Unable to load asset from {file_path}: {e}\n"
84+
pn.current_step_number += 1
85+
self._asset_display.reload_model()
86+
pn.close()
87+
if len(accumulated_errors) > 0:
88+
msg_box = QMessageBox(QMessageBox.Icon.Critical, "Loading Assets Failed",
89+
"Errors occurred during asset loading:", parent=self,
90+
detailedText=accumulated_errors)
91+
msg_box.show()
92+
self._dialog = msg_box

src/view/main_window.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from utility import resource_path
2222
from view.action_setup_view.combined_action_setup_widget import CombinedActionSetupWidget
2323
from view.console_mode.console_universe_selector import UniverseSelector
24+
from view.dialogs.asset_mgmt_dialog import AssetManagementDialog
2425
from view.dialogs.colum_dialog import ColumnDialog
2526
from view.logging_view.logging_widget import LoggingWidget
2627
from view.main_widget import MainWidget
@@ -199,6 +200,8 @@ def _setup_menubar(self) -> None:
199200
"Tools": [
200201
# ("Scene Wizard", self._open_scene_setup_wizard, None),
201202
("Patch Plan Export", self._open_patch_plan_export_dialog, None),
203+
("Asset Management", self._open_asset_mgmt_dialog, None),
204+
("---", None, None),
202205
("&Toggle Terminal", self._toggle_terminal, "T"),
203206
],
204207
"Help": [
@@ -395,3 +398,7 @@ def _toggle_terminal(self) -> None:
395398
else:
396399
self._terminal_widget.show()
397400
self._terminal_widget.focusWidget()
401+
402+
def _open_asset_mgmt_dialog(self) -> None:
403+
self._settings_dialog = AssetManagementDialog(self, self._board_configuration.file_path)
404+
self._settings_dialog.show()

src/view/show_mode/show_ui_widgets/macro_buttons_ui_widget.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ def __init__(self, ui_widget: MacroButtonUIWidget, button_list: QListWidget, upd
5757
self._text_tb = QLineEdit(self)
5858
layout.addRow("Display Text: ", self._text_tb)
5959

60-
# TODO add Icon selection from show media storage
6160
self._icon_selection = AssetSelectionWidget(self, allowed_types=[MediaType.IMAGE], multiselection_allowed=False)
6261
layout.addRow("Select Icon", self._icon_selection)
6362
# TODO add clear icon button

src/view/utility_widgets/asset_selection_widget.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def __init__(self) -> None:
3030
self._name_filter: str = ""
3131
self._filtered_asset_list: list[MediaAsset] = []
3232

33-
def apply_filter(self, name: str, types: set[MediaType]) -> None:
33+
def apply_filter(self, name: str, types: set[MediaType], force_update: bool = False) -> None:
3434
"""Apply the filter parameters to the asset selection.
3535
3636
Warning: this operation may be quite expensive. It is therefore better to wait for a filter to be entered
@@ -39,11 +39,12 @@ def apply_filter(self, name: str, types: set[MediaType]) -> None:
3939
Args:
4040
name: If set to anything than an empty string, all assets needs to contain this in their name.
4141
types: The types of assets to show.
42+
force_update: If set to true, updating the model is forced.
4243
4344
"""
44-
if types == self._selected_media_types and name == self._name_filter:
45+
if (types == self._selected_media_types and name == self._name_filter) and not force_update:
4546
return
46-
if len(name) < len(self._name_filter):
47+
if len(name) < len(self._name_filter) or force_update:
4748
self._filtered_asset_list.clear()
4849
self._selected_media_types.clear()
4950
types_to_add = types - self._selected_media_types
@@ -199,16 +200,20 @@ def __init__(self, parent: QWidget | None = None, allowed_types: list[MediaType]
199200
self.setLayout(layout)
200201
self._update_filter()
201202

202-
def _update_filter(self) -> None:
203+
def _update_filter(self, force: bool = False) -> None:
203204
selected_types: set[MediaType] = set()
204205
for asset_type, action in self._type_checkboxes:
205206
if action.isChecked():
206207
selected_types.add(asset_type)
207208
self._asset_view.setEnabled(False)
208-
self._model.apply_filter(self._search_bar.text(), selected_types)
209+
self._model.apply_filter(self._search_bar.text(), selected_types, force_update=force)
209210
self._asset_view.setEnabled(True)
210211
self.update()
211212

213+
def reload_model(self) -> None:
214+
"""Forcefully update the model."""
215+
self._update_filter(force=True)
216+
212217
@property
213218
def selected_asset(self) -> list[MediaAsset]:
214219
"""Get or set the selected assets."""

0 commit comments

Comments
 (0)