shinestacker 0.5.0__py3-none-any.whl → 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of shinestacker might be problematic. Click here for more details.
- shinestacker/_version.py +1 -1
- shinestacker/algorithms/align.py +4 -12
- shinestacker/algorithms/balance.py +11 -9
- shinestacker/algorithms/depth_map.py +0 -30
- shinestacker/algorithms/utils.py +10 -0
- shinestacker/algorithms/vignetting.py +116 -70
- shinestacker/app/about_dialog.py +37 -16
- shinestacker/app/gui_utils.py +1 -1
- shinestacker/app/help_menu.py +1 -1
- shinestacker/app/main.py +2 -2
- shinestacker/app/project.py +2 -2
- shinestacker/config/constants.py +4 -1
- shinestacker/config/gui_constants.py +3 -4
- shinestacker/gui/action_config.py +5 -561
- shinestacker/gui/action_config_dialog.py +567 -0
- shinestacker/gui/base_form_dialog.py +18 -0
- shinestacker/gui/colors.py +5 -6
- shinestacker/gui/gui_logging.py +0 -1
- shinestacker/gui/gui_run.py +54 -106
- shinestacker/gui/ico/shinestacker.icns +0 -0
- shinestacker/gui/ico/shinestacker.ico +0 -0
- shinestacker/gui/ico/shinestacker.png +0 -0
- shinestacker/gui/ico/shinestacker.svg +60 -0
- shinestacker/gui/main_window.py +275 -371
- shinestacker/gui/menu_manager.py +236 -0
- shinestacker/gui/new_project.py +75 -20
- shinestacker/gui/{actions_window.py → project_controller.py} +166 -79
- shinestacker/gui/project_converter.py +6 -6
- shinestacker/gui/project_editor.py +248 -165
- shinestacker/gui/project_model.py +2 -7
- shinestacker/gui/tab_widget.py +81 -0
- shinestacker/gui/time_progress_bar.py +95 -0
- shinestacker/retouch/base_filter.py +173 -40
- shinestacker/retouch/brush_preview.py +0 -10
- shinestacker/retouch/brush_tool.py +2 -5
- shinestacker/retouch/denoise_filter.py +5 -44
- shinestacker/retouch/exif_data.py +10 -13
- shinestacker/retouch/file_loader.py +1 -1
- shinestacker/retouch/filter_manager.py +1 -4
- shinestacker/retouch/image_editor_ui.py +318 -40
- shinestacker/retouch/image_viewer.py +34 -11
- shinestacker/retouch/io_gui_handler.py +34 -30
- shinestacker/retouch/layer_collection.py +2 -0
- shinestacker/retouch/shortcuts_help.py +12 -0
- shinestacker/retouch/unsharp_mask_filter.py +10 -10
- shinestacker/retouch/vignetting_filter.py +69 -0
- shinestacker/retouch/white_balance_filter.py +46 -14
- {shinestacker-0.5.0.dist-info → shinestacker-1.0.1.dist-info}/METADATA +8 -2
- shinestacker-1.0.1.dist-info/RECORD +91 -0
- shinestacker/app/app_config.py +0 -22
- shinestacker/retouch/image_editor.py +0 -197
- shinestacker/retouch/image_filters.py +0 -69
- shinestacker-0.5.0.dist-info/RECORD +0 -87
- {shinestacker-0.5.0.dist-info → shinestacker-1.0.1.dist-info}/WHEEL +0 -0
- {shinestacker-0.5.0.dist-info → shinestacker-1.0.1.dist-info}/entry_points.txt +0 -0
- {shinestacker-0.5.0.dist-info → shinestacker-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {shinestacker-0.5.0.dist-info → shinestacker-1.0.1.dist-info}/top_level.txt +0 -0
shinestacker/gui/main_window.py
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
# pylint: disable=C0114, C0115, C0116, E0611, R0902, R0915, R0904, R0914
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116, E0611, R0902, R0915, R0904, R0914
|
|
2
|
+
# pylint: disable=R0912, E1101, W0201, E1121, R0913, R0917
|
|
2
3
|
import os
|
|
3
4
|
import subprocess
|
|
4
|
-
from PySide6.
|
|
5
|
-
|
|
6
|
-
from PySide6.
|
|
7
|
-
|
|
5
|
+
from PySide6.QtCore import Qt
|
|
6
|
+
from PySide6.QtGui import QGuiApplication, QAction, QIcon
|
|
7
|
+
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QMessageBox,
|
|
8
|
+
QSplitter, QToolBar, QMenu, QMainWindow)
|
|
8
9
|
from .. config.constants import constants
|
|
9
|
-
from .. core.core_utils import running_under_windows, running_under_macos
|
|
10
|
+
from .. core.core_utils import running_under_windows, running_under_macos
|
|
10
11
|
from .colors import ColorPalette
|
|
11
12
|
from .project_model import Project
|
|
12
|
-
from .actions_window import ActionsWindow
|
|
13
13
|
from .gui_logging import LogManager
|
|
14
14
|
from .gui_run import RunWindow, RunWorker
|
|
15
15
|
from .project_converter import ProjectConverter
|
|
16
16
|
from .project_model import get_action_working_path, get_action_input_path, get_action_output_path
|
|
17
|
+
from .menu_manager import MenuManager
|
|
18
|
+
from .project_controller import ProjectController
|
|
19
|
+
from .tab_widget import TabWidgetWithPlaceholder
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
class JobLogWorker(RunWorker):
|
|
@@ -45,105 +48,50 @@ LIST_STYLE_SHEET = f"""
|
|
|
45
48
|
"""
|
|
46
49
|
|
|
47
50
|
|
|
48
|
-
class
|
|
49
|
-
# Segnali aggiuntivi per mantenere la compatibilità
|
|
50
|
-
currentChanged = Signal(int)
|
|
51
|
-
tabCloseRequested = Signal(int)
|
|
52
|
-
|
|
53
|
-
def __init__(self, parent=None):
|
|
54
|
-
super().__init__(parent)
|
|
55
|
-
self.layout = QVBoxLayout(self)
|
|
56
|
-
self.layout.setContentsMargins(0, 0, 0, 0)
|
|
57
|
-
self.stacked_widget = QStackedWidget()
|
|
58
|
-
self.layout.addWidget(self.stacked_widget)
|
|
59
|
-
self.tab_widget = QTabWidget()
|
|
60
|
-
self.stacked_widget.addWidget(self.tab_widget)
|
|
61
|
-
self.placeholder = QLabel()
|
|
62
|
-
self.placeholder.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
63
|
-
rel_path = 'ico/focus_stack_bkg.png'
|
|
64
|
-
icon_path = f'{get_app_base_path()}/{rel_path}'
|
|
65
|
-
if not os.path.exists(icon_path):
|
|
66
|
-
icon_path = f'{get_app_base_path()}/../{rel_path}'
|
|
67
|
-
if os.path.exists(icon_path):
|
|
68
|
-
pixmap = QPixmap(icon_path)
|
|
69
|
-
# Ridimensiona mantenendo le proporzioni (es. max 400x400)
|
|
70
|
-
pixmap = pixmap.scaled(250, 250, Qt.AspectRatioMode.KeepAspectRatio,
|
|
71
|
-
Qt.TransformationMode.SmoothTransformation)
|
|
72
|
-
self.placeholder.setPixmap(pixmap)
|
|
73
|
-
else:
|
|
74
|
-
self.placeholder.setText("Run logs will appear here.")
|
|
75
|
-
self.stacked_widget.addWidget(self.placeholder)
|
|
76
|
-
self.tab_widget.currentChanged.connect(self._on_current_changed)
|
|
77
|
-
self.tab_widget.tabCloseRequested.connect(self._on_tab_close_requested)
|
|
78
|
-
self.update_placeholder_visibility()
|
|
79
|
-
|
|
80
|
-
def _on_current_changed(self, index):
|
|
81
|
-
self.currentChanged.emit(index)
|
|
82
|
-
self.update_placeholder_visibility()
|
|
83
|
-
|
|
84
|
-
def _on_tab_close_requested(self, index):
|
|
85
|
-
self.tabCloseRequested.emit(index)
|
|
86
|
-
self.update_placeholder_visibility()
|
|
87
|
-
|
|
88
|
-
def update_placeholder_visibility(self):
|
|
89
|
-
if self.tab_widget.count() == 0:
|
|
90
|
-
self.stacked_widget.setCurrentIndex(1)
|
|
91
|
-
else:
|
|
92
|
-
self.stacked_widget.setCurrentIndex(0)
|
|
93
|
-
|
|
94
|
-
# pylint: disable=C0103
|
|
95
|
-
def addTab(self, widget, label):
|
|
96
|
-
result = self.tab_widget.addTab(widget, label)
|
|
97
|
-
self.update_placeholder_visibility()
|
|
98
|
-
return result
|
|
99
|
-
|
|
100
|
-
def removeTab(self, index):
|
|
101
|
-
result = self.tab_widget.removeTab(index)
|
|
102
|
-
self.update_placeholder_visibility()
|
|
103
|
-
return result
|
|
104
|
-
|
|
105
|
-
def count(self):
|
|
106
|
-
return self.tab_widget.count()
|
|
107
|
-
|
|
108
|
-
def setCurrentIndex(self, index):
|
|
109
|
-
return self.tab_widget.setCurrentIndex(index)
|
|
110
|
-
|
|
111
|
-
def currentIndex(self):
|
|
112
|
-
return self.tab_widget.currentIndex()
|
|
113
|
-
|
|
114
|
-
def currentWidget(self):
|
|
115
|
-
return self.tab_widget.currentWidget()
|
|
116
|
-
|
|
117
|
-
def widget(self, index):
|
|
118
|
-
return self.tab_widget.widget(index)
|
|
119
|
-
|
|
120
|
-
def indexOf(self, widget):
|
|
121
|
-
return self.tab_widget.indexOf(widget)
|
|
122
|
-
# pylint: enable=C0103
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
class MainWindow(ActionsWindow, LogManager):
|
|
51
|
+
class MainWindow(QMainWindow, LogManager):
|
|
126
52
|
def __init__(self):
|
|
127
|
-
|
|
53
|
+
QMainWindow.__init__(self)
|
|
128
54
|
LogManager.__init__(self)
|
|
55
|
+
self.project_controller = ProjectController(self)
|
|
56
|
+
self.project_editor = self.project_controller.project_editor
|
|
57
|
+
actions = {
|
|
58
|
+
"&New...": self.project_controller.new_project,
|
|
59
|
+
"&Open...": self.project_controller.open_project,
|
|
60
|
+
"&Close": self.project_controller.close_project,
|
|
61
|
+
"&Save": self.project_controller.save_project,
|
|
62
|
+
"Save &As...": self.project_controller.save_project_as,
|
|
63
|
+
"&Undo": self.project_editor.undo,
|
|
64
|
+
"&Cut": self.project_editor.cut_element,
|
|
65
|
+
"Cop&y": self.project_editor.copy_element,
|
|
66
|
+
"&Paste": self.project_editor.paste_element,
|
|
67
|
+
"Duplicate": self.project_editor.clone_element,
|
|
68
|
+
"Delete": self.delete_element,
|
|
69
|
+
"Move &Up": self.project_editor.move_element_up,
|
|
70
|
+
"Move &Down": self.project_editor.move_element_down,
|
|
71
|
+
"E&nable": self.project_editor.enable,
|
|
72
|
+
"Di&sable": self.project_editor.disable,
|
|
73
|
+
"Enable All": self.project_editor.enable_all,
|
|
74
|
+
"Disable All": self.project_editor.disable_all,
|
|
75
|
+
"Expert Options": self.toggle_expert_options,
|
|
76
|
+
"Add Job": self.project_editor.add_job,
|
|
77
|
+
"Run Job": self.run_job,
|
|
78
|
+
"Run All Jobs": self.run_all_jobs,
|
|
79
|
+
}
|
|
80
|
+
self.menu_manager = MenuManager(self.menuBar(), actions, self.project_editor, self)
|
|
81
|
+
self.script_dir = os.path.dirname(__file__)
|
|
129
82
|
self._windows = []
|
|
130
83
|
self._workers = []
|
|
131
84
|
self.retouch_callback = None
|
|
132
|
-
self.
|
|
133
|
-
self.
|
|
134
|
-
|
|
135
|
-
self.
|
|
136
|
-
self.add_edit_menu(menubar)
|
|
137
|
-
self.add_view_menu(menubar)
|
|
138
|
-
self.add_job_menu(menubar)
|
|
139
|
-
self.add_actions_menu(menubar)
|
|
140
|
-
self.add_help_menu(menubar)
|
|
85
|
+
self.expert_options = False
|
|
86
|
+
self.job_list().setStyleSheet(LIST_STYLE_SHEET)
|
|
87
|
+
self.action_list().setStyleSheet(LIST_STYLE_SHEET)
|
|
88
|
+
self.menu_manager.add_menus()
|
|
141
89
|
toolbar = QToolBar(self)
|
|
142
90
|
self.addToolBar(Qt.TopToolBarArea, toolbar)
|
|
143
|
-
self.fill_toolbar(toolbar)
|
|
91
|
+
self.menu_manager.fill_toolbar(toolbar)
|
|
144
92
|
self.resize(1200, 800)
|
|
145
|
-
|
|
146
|
-
|
|
93
|
+
self.move(QGuiApplication.primaryScreen().geometry().center() -
|
|
94
|
+
self.rect().center())
|
|
147
95
|
self.set_project(Project())
|
|
148
96
|
self.central_widget = QWidget()
|
|
149
97
|
self.setCentralWidget(self.central_widget)
|
|
@@ -158,248 +106,181 @@ class MainWindow(ActionsWindow, LogManager):
|
|
|
158
106
|
self.tab_widget = TabWidgetWithPlaceholder()
|
|
159
107
|
self.tab_widget.resize(1000, 500)
|
|
160
108
|
h_splitter.addWidget(self.tab_widget)
|
|
161
|
-
self.job_list.currentRowChanged.connect(self.on_job_selected)
|
|
162
|
-
self.job_list.itemDoubleClicked.connect(self.on_job_edit)
|
|
163
|
-
self.action_list.itemDoubleClicked.connect(self.on_action_edit)
|
|
109
|
+
self.job_list().currentRowChanged.connect(self.project_editor.on_job_selected)
|
|
110
|
+
self.job_list().itemDoubleClicked.connect(self.on_job_edit)
|
|
111
|
+
self.action_list().itemDoubleClicked.connect(self.on_action_edit)
|
|
164
112
|
vbox_left = QVBoxLayout()
|
|
165
113
|
vbox_left.setSpacing(4)
|
|
166
114
|
vbox_left.addWidget(QLabel("Job"))
|
|
167
|
-
vbox_left.addWidget(self.job_list)
|
|
115
|
+
vbox_left.addWidget(self.job_list())
|
|
168
116
|
vbox_right = QVBoxLayout()
|
|
169
117
|
vbox_right.setSpacing(4)
|
|
170
118
|
vbox_right.addWidget(QLabel("Action"))
|
|
171
|
-
vbox_right.addWidget(self.action_list)
|
|
172
|
-
self.job_list.itemSelectionChanged.connect(self.update_delete_action_state)
|
|
173
|
-
self.action_list.itemSelectionChanged.connect(self.update_delete_action_state)
|
|
119
|
+
vbox_right.addWidget(self.action_list())
|
|
120
|
+
self.job_list().itemSelectionChanged.connect(self.update_delete_action_state)
|
|
121
|
+
self.action_list().itemSelectionChanged.connect(self.update_delete_action_state)
|
|
174
122
|
h_layout.addLayout(vbox_left)
|
|
175
123
|
h_layout.addLayout(vbox_right)
|
|
176
124
|
layout.addWidget(h_splitter)
|
|
177
125
|
self.central_widget.setLayout(layout)
|
|
126
|
+
self.update_title()
|
|
127
|
+
|
|
128
|
+
def handle_modified(modified):
|
|
129
|
+
self.save_actions_set_enabled(modified)
|
|
130
|
+
self.update_title()
|
|
131
|
+
|
|
132
|
+
self.project_editor.modified_signal.connect(handle_modified)
|
|
133
|
+
self.project_editor.select_signal.connect(self.update_delete_action_state)
|
|
134
|
+
self.project_editor.refresh_ui_signal.connect(self.refresh_ui)
|
|
135
|
+
self.project_editor.enable_delete_action_signal.connect(
|
|
136
|
+
self.menu_manager.delete_element_action.setEnabled)
|
|
137
|
+
self.project_controller.update_title_requested.connect(self.update_title)
|
|
138
|
+
self.project_controller.refresh_ui_requested.connect(self.refresh_ui)
|
|
139
|
+
self.project_controller.activate_window_requested.connect(self.activateWindow)
|
|
140
|
+
self.project_controller.enable_save_actions_requested.connect(
|
|
141
|
+
self.menu_manager.save_actions_set_enabled)
|
|
142
|
+
|
|
143
|
+
def modified(self):
|
|
144
|
+
return self.project_editor.modified()
|
|
145
|
+
|
|
146
|
+
def mark_as_modified(self, modified=True):
|
|
147
|
+
self.project_editor.mark_as_modified(modified)
|
|
148
|
+
|
|
149
|
+
def set_project(self, project):
|
|
150
|
+
self.project_editor.set_project(project)
|
|
151
|
+
|
|
152
|
+
def project(self):
|
|
153
|
+
return self.project_editor.project()
|
|
154
|
+
|
|
155
|
+
def project_jobs(self):
|
|
156
|
+
return self.project_editor.project_jobs()
|
|
157
|
+
|
|
158
|
+
def project_job(self, i):
|
|
159
|
+
return self.project_editor.project_job(i)
|
|
160
|
+
|
|
161
|
+
def add_job_to_project(self, job):
|
|
162
|
+
self.project_editor.add_job_to_project(job)
|
|
163
|
+
|
|
164
|
+
def num_project_jobs(self):
|
|
165
|
+
return self.project_editor.num_project_jobs()
|
|
166
|
+
|
|
167
|
+
def current_file_path(self):
|
|
168
|
+
return self.project_editor.current_file_path()
|
|
169
|
+
|
|
170
|
+
def current_file_directory(self):
|
|
171
|
+
return self.project_editor.current_file_directory()
|
|
172
|
+
|
|
173
|
+
def current_file_name(self):
|
|
174
|
+
return self.project_editor.current_file_name()
|
|
175
|
+
|
|
176
|
+
def set_current_file_path(self, path):
|
|
177
|
+
self.project_editor.set_current_file_path(path)
|
|
178
|
+
|
|
179
|
+
def job_list(self):
|
|
180
|
+
return self.project_editor.job_list()
|
|
181
|
+
|
|
182
|
+
def action_list(self):
|
|
183
|
+
return self.project_editor.action_list()
|
|
184
|
+
|
|
185
|
+
def current_job_index(self):
|
|
186
|
+
return self.project_editor.current_job_index()
|
|
187
|
+
|
|
188
|
+
def current_action_index(self):
|
|
189
|
+
return self.project_editor.current_action_index()
|
|
190
|
+
|
|
191
|
+
def set_current_job(self, index):
|
|
192
|
+
return self.project_editor.set_current_job(index)
|
|
193
|
+
|
|
194
|
+
def set_current_action(self, index):
|
|
195
|
+
return self.project_editor.set_current_action(index)
|
|
196
|
+
|
|
197
|
+
def job_list_count(self):
|
|
198
|
+
return self.project_editor.job_list_count()
|
|
199
|
+
|
|
200
|
+
def action_list_count(self):
|
|
201
|
+
return self.project_editor.action_list_count()
|
|
202
|
+
|
|
203
|
+
def job_list_item(self, index):
|
|
204
|
+
return self.project_editor.job_list_item(index)
|
|
205
|
+
|
|
206
|
+
def action_list_item(self, index):
|
|
207
|
+
return self.project_editor.action_list_item(index)
|
|
208
|
+
|
|
209
|
+
def job_list_has_focus(self):
|
|
210
|
+
return self.project_editor.job_list_has_focus()
|
|
211
|
+
|
|
212
|
+
def action_list_has_focus(self):
|
|
213
|
+
return self.project_editor.action_list_has_focus()
|
|
214
|
+
|
|
215
|
+
def clear_job_list(self):
|
|
216
|
+
self.project_editor.clear_job_list()
|
|
217
|
+
|
|
218
|
+
def clear_action_list(self):
|
|
219
|
+
self.project_editor.clear_action_list()
|
|
220
|
+
|
|
221
|
+
def num_selected_jobs(self):
|
|
222
|
+
return self.project_editor.num_selected_jobs()
|
|
223
|
+
|
|
224
|
+
def num_selected_actions(self):
|
|
225
|
+
return self.project_editor.num_selected_actions()
|
|
226
|
+
|
|
227
|
+
def get_current_action_at(self, job, action_index):
|
|
228
|
+
return self.project_editor.get_current_action_at(job, action_index)
|
|
229
|
+
|
|
230
|
+
def action_config_dialog(self, action):
|
|
231
|
+
return self.project_editor.action_config_dialog(action)
|
|
232
|
+
|
|
233
|
+
def action_text(self, action, is_sub_action=False, indent=True, long_name=False, html=False):
|
|
234
|
+
return self.project_editor.action_text(action, is_sub_action, indent, long_name, html)
|
|
235
|
+
|
|
236
|
+
def job_text(self, job, long_name=False, html=False):
|
|
237
|
+
return self.project_editor.job_text(job, long_name, html)
|
|
238
|
+
|
|
239
|
+
def on_job_selected(self, index):
|
|
240
|
+
return self.project_editor.on_job_selected(index)
|
|
241
|
+
|
|
242
|
+
def get_action_at(self, action_row):
|
|
243
|
+
return self.project_editor.get_action_at(action_row)
|
|
244
|
+
|
|
245
|
+
def on_job_edit(self, item):
|
|
246
|
+
self.project_controller.on_job_edit(item)
|
|
247
|
+
|
|
248
|
+
def on_action_edit(self, item):
|
|
249
|
+
self.project_controller.on_action_edit(item)
|
|
250
|
+
|
|
251
|
+
def edit_current_action(self):
|
|
252
|
+
self.project_controller.edit_current_action()
|
|
253
|
+
|
|
254
|
+
def edit_action(self, action):
|
|
255
|
+
self.project_controller.edit_action(action)
|
|
178
256
|
|
|
179
257
|
def set_retouch_callback(self, callback):
|
|
180
258
|
self.retouch_callback = callback
|
|
181
259
|
|
|
182
|
-
def add_file_menu(self, menubar):
|
|
183
|
-
menu = menubar.addMenu("&File")
|
|
184
|
-
new_action = QAction("&New...", self)
|
|
185
|
-
new_action.setShortcut("Ctrl+N")
|
|
186
|
-
new_action.triggered.connect(self.new_project)
|
|
187
|
-
menu.addAction(new_action)
|
|
188
|
-
open_action = QAction("&Open...", self)
|
|
189
|
-
open_action.setShortcut("Ctrl+O")
|
|
190
|
-
open_action.triggered.connect(self.open_project)
|
|
191
|
-
menu.addAction(open_action)
|
|
192
|
-
self.save_action = QAction("&Save", self)
|
|
193
|
-
self.save_action.setShortcut("Ctrl+S")
|
|
194
|
-
self.save_action.triggered.connect(self.save_project)
|
|
195
|
-
menu.addAction(self.save_action)
|
|
196
|
-
self.save_as_action = QAction("Save &As...", self)
|
|
197
|
-
self.save_as_action.setShortcut("Ctrl+Shift+S")
|
|
198
|
-
self.save_as_action.triggered.connect(self.save_project_as)
|
|
199
|
-
menu.addAction(self.save_as_action)
|
|
200
|
-
self.save_actions_set_enabled(False)
|
|
201
|
-
close_action = QAction("&Close", self)
|
|
202
|
-
close_action.setShortcut("Ctrl+W")
|
|
203
|
-
close_action.triggered.connect(self.close_project)
|
|
204
|
-
menu.addAction(close_action)
|
|
205
|
-
|
|
206
260
|
def save_actions_set_enabled(self, enabled):
|
|
207
|
-
self.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
cut_action = QAction("&Cut", self)
|
|
218
|
-
cut_action.setShortcut("Ctrl+X")
|
|
219
|
-
cut_action.triggered.connect(self.cut_element)
|
|
220
|
-
menu.addAction(cut_action)
|
|
221
|
-
copy_action = QAction("Cop&y", self)
|
|
222
|
-
copy_action.setShortcut("Ctrl+C")
|
|
223
|
-
copy_action.triggered.connect(self.copy_element)
|
|
224
|
-
menu.addAction(copy_action)
|
|
225
|
-
paste_action = QAction("&Paste", self)
|
|
226
|
-
paste_action.setShortcut("Ctrl+V")
|
|
227
|
-
paste_action.triggered.connect(self.paste_element)
|
|
228
|
-
menu.addAction(paste_action)
|
|
229
|
-
clone_action = QAction("Duplicate", self)
|
|
230
|
-
clone_action.setShortcut("Ctrl+D")
|
|
231
|
-
clone_action.triggered.connect(self.clone_element)
|
|
232
|
-
menu.addAction(clone_action)
|
|
233
|
-
self.delete_element_action = QAction("Delete", self)
|
|
234
|
-
self.delete_element_action.setShortcut("Del") # Qt.Key_Backspace
|
|
235
|
-
self.delete_element_action.setIcon(self.get_icon("close-round-line-icon"))
|
|
236
|
-
self.delete_element_action.setToolTip("delete")
|
|
237
|
-
self.delete_element_action.triggered.connect(self.delete_element)
|
|
238
|
-
self.delete_element_action.setEnabled(False)
|
|
239
|
-
menu.addAction(self.delete_element_action)
|
|
240
|
-
menu.addSeparator()
|
|
241
|
-
up_action = QAction("Move &Up", self)
|
|
242
|
-
up_action.setShortcut("Ctrl+Up")
|
|
243
|
-
up_action.triggered.connect(self.move_element_up)
|
|
244
|
-
menu.addAction(up_action)
|
|
245
|
-
down_action = QAction("Move &Down", self)
|
|
246
|
-
down_action.setShortcut("Ctrl+Down")
|
|
247
|
-
down_action.triggered.connect(self.move_element_down)
|
|
248
|
-
menu.addAction(down_action)
|
|
249
|
-
menu.addSeparator()
|
|
250
|
-
self.enable_action = QAction("E&nable", self)
|
|
251
|
-
self.enable_action.setShortcut("Ctrl+E")
|
|
252
|
-
self.enable_action.triggered.connect(self.enable)
|
|
253
|
-
menu.addAction(self.enable_action)
|
|
254
|
-
self.disable_action = QAction("Di&sable", self)
|
|
255
|
-
self.disable_action.setShortcut("Ctrl+B")
|
|
256
|
-
self.disable_action.triggered.connect(self.disable)
|
|
257
|
-
menu.addAction(self.disable_action)
|
|
258
|
-
enable_all_action = QAction("Enable All", self)
|
|
259
|
-
enable_all_action.setShortcut("Ctrl+Shift+E")
|
|
260
|
-
enable_all_action.triggered.connect(self.enable_all)
|
|
261
|
-
menu.addAction(enable_all_action)
|
|
262
|
-
disable_all_action = QAction("Disable All", self)
|
|
263
|
-
disable_all_action.setShortcut("Ctrl+Shift+B")
|
|
264
|
-
disable_all_action.triggered.connect(self.disable_all)
|
|
265
|
-
menu.addAction(disable_all_action)
|
|
266
|
-
|
|
267
|
-
def add_view_menu(self, menubar):
|
|
268
|
-
menu = menubar.addMenu("&View")
|
|
269
|
-
self.expert_options_action = QAction("Expert Options", self)
|
|
270
|
-
self.expert_options_action.setShortcut("Ctrl+Shift+X")
|
|
271
|
-
self.expert_options_action.triggered.connect(self.toggle_expert_options)
|
|
272
|
-
self.expert_options_action.setCheckable(True)
|
|
273
|
-
self.expert_options_action.setChecked(self.expert_options)
|
|
274
|
-
menu.addAction(self.expert_options_action)
|
|
275
|
-
|
|
276
|
-
def add_job_menu(self, menubar):
|
|
277
|
-
menu = menubar.addMenu("&Jobs")
|
|
278
|
-
self.add_job_action = QAction("Add Job", self)
|
|
279
|
-
self.add_job_action.setShortcut("Ctrl+P")
|
|
280
|
-
self.add_job_action.setIcon(self.get_icon("plus-round-line-icon"))
|
|
281
|
-
self.add_job_action.setToolTip("Add job")
|
|
282
|
-
self.add_job_action.triggered.connect(self.add_job)
|
|
283
|
-
menu.addAction(self.add_job_action)
|
|
284
|
-
menu.addSeparator()
|
|
285
|
-
self.run_job_action = QAction("Run Job", self)
|
|
286
|
-
self.run_job_action.setShortcut("Ctrl+J")
|
|
287
|
-
self.run_job_action.setIcon(self.get_icon("play-button-round-icon"))
|
|
288
|
-
self.run_job_action.setToolTip("Run job")
|
|
289
|
-
self.run_job_action.setEnabled(False)
|
|
290
|
-
self.run_job_action.triggered.connect(self.run_job)
|
|
291
|
-
menu.addAction(self.run_job_action)
|
|
292
|
-
self.run_all_jobs_action = QAction("Run All Jobs", self)
|
|
293
|
-
self.run_all_jobs_action.setShortcut("Ctrl+Shift+J")
|
|
294
|
-
self.run_all_jobs_action.setIcon(self.get_icon("forward-button-icon"))
|
|
295
|
-
self.run_all_jobs_action.setToolTip("Run all jobs")
|
|
296
|
-
self.run_all_jobs_action.setEnabled(False)
|
|
297
|
-
self.run_all_jobs_action.triggered.connect(self.run_all_jobs)
|
|
298
|
-
menu.addAction(self.run_all_jobs_action)
|
|
299
|
-
|
|
300
|
-
def add_action_combined_actions(self):
|
|
301
|
-
self.add_action(constants.ACTION_COMBO)
|
|
302
|
-
|
|
303
|
-
def add_action_noise_detection(self):
|
|
304
|
-
self.add_action(constants.ACTION_NOISEDETECTION)
|
|
305
|
-
|
|
306
|
-
def add_action_focus_stack(self):
|
|
307
|
-
self.add_action(constants.ACTION_FOCUSSTACK)
|
|
308
|
-
|
|
309
|
-
def add_action_focus_stack_bunch(self):
|
|
310
|
-
self.add_action(constants.ACTION_FOCUSSTACKBUNCH)
|
|
311
|
-
|
|
312
|
-
def add_action_multilayer(self):
|
|
313
|
-
self.add_action(constants.ACTION_MULTILAYER)
|
|
314
|
-
|
|
315
|
-
def add_sub_action_make_noise(self):
|
|
316
|
-
self.add_sub_action(constants.ACTION_MASKNOISE)
|
|
317
|
-
|
|
318
|
-
def add_sub_action_vignetting(self):
|
|
319
|
-
self.add_sub_action(constants.ACTION_VIGNETTING)
|
|
320
|
-
|
|
321
|
-
def add_sub_action_align_frames(self):
|
|
322
|
-
self.add_sub_action(constants.ACTION_ALIGNFRAMES)
|
|
323
|
-
|
|
324
|
-
def add_sub_action_balance_frames(self):
|
|
325
|
-
self.add_sub_action(constants.ACTION_BALANCEFRAMES)
|
|
326
|
-
|
|
327
|
-
def add_actions_menu(self, menubar):
|
|
328
|
-
menu = menubar.addMenu("&Actions")
|
|
329
|
-
add_action_menu = QMenu("Add Action", self)
|
|
330
|
-
for action in constants.ACTION_TYPES:
|
|
331
|
-
entry_action = QAction(action, self)
|
|
332
|
-
entry_action.triggered.connect({
|
|
333
|
-
constants.ACTION_COMBO: self.add_action_combined_actions,
|
|
334
|
-
constants.ACTION_NOISEDETECTION: self.add_action_noise_detection,
|
|
335
|
-
constants.ACTION_FOCUSSTACK: self.add_action_focus_stack,
|
|
336
|
-
constants.ACTION_FOCUSSTACKBUNCH: self.add_action_focus_stack_bunch,
|
|
337
|
-
constants.ACTION_MULTILAYER: self.add_action_multilayer
|
|
338
|
-
}[action])
|
|
339
|
-
add_action_menu.addAction(entry_action)
|
|
340
|
-
menu.addMenu(add_action_menu)
|
|
341
|
-
add_sub_action_menu = QMenu("Add Sub Action", self)
|
|
342
|
-
self.sub_action_menu_entries = []
|
|
343
|
-
for action in constants.SUB_ACTION_TYPES:
|
|
344
|
-
entry_action = QAction(action, self)
|
|
345
|
-
entry_action.triggered.connect({
|
|
346
|
-
constants.ACTION_MASKNOISE: self.add_sub_action_make_noise,
|
|
347
|
-
constants.ACTION_VIGNETTING: self.add_sub_action_vignetting,
|
|
348
|
-
constants.ACTION_ALIGNFRAMES: self.add_sub_action_align_frames,
|
|
349
|
-
constants.ACTION_BALANCEFRAMES: self.add_sub_action_balance_frames
|
|
350
|
-
}[action])
|
|
351
|
-
entry_action.setEnabled(False)
|
|
352
|
-
self.sub_action_menu_entries.append(entry_action)
|
|
353
|
-
add_sub_action_menu.addAction(entry_action)
|
|
354
|
-
menu.addMenu(add_sub_action_menu)
|
|
355
|
-
|
|
356
|
-
def add_help_menu(self, menubar):
|
|
357
|
-
menu = menubar.addMenu("&Help")
|
|
358
|
-
menu.setObjectName("Help")
|
|
359
|
-
|
|
360
|
-
def fill_toolbar(self, toolbar):
|
|
361
|
-
toolbar.addAction(self.add_job_action)
|
|
362
|
-
toolbar.addSeparator()
|
|
363
|
-
self.action_selector = QComboBox()
|
|
364
|
-
self.action_selector.addItems(constants.ACTION_TYPES)
|
|
365
|
-
self.action_selector.setEnabled(False)
|
|
366
|
-
toolbar.addWidget(self.action_selector)
|
|
367
|
-
self.add_action_entry_action = QAction("Add Action", self)
|
|
368
|
-
self.add_action_entry_action.setIcon(
|
|
369
|
-
QIcon(os.path.join(self.script_dir, "img/plus-round-line-icon.png")))
|
|
370
|
-
self.add_action_entry_action.setToolTip("Add action")
|
|
371
|
-
self.add_action_entry_action.triggered.connect(self.add_action)
|
|
372
|
-
self.add_action_entry_action.setEnabled(False)
|
|
373
|
-
toolbar.addAction(self.add_action_entry_action)
|
|
374
|
-
self.sub_action_selector = QComboBox()
|
|
375
|
-
self.sub_action_selector.addItems(constants.SUB_ACTION_TYPES)
|
|
376
|
-
self.sub_action_selector.setEnabled(False)
|
|
377
|
-
toolbar.addWidget(self.sub_action_selector)
|
|
378
|
-
self.add_sub_action_entry_action = QAction("Add Sub Action", self)
|
|
379
|
-
self.add_sub_action_entry_action.setIcon(
|
|
380
|
-
QIcon(os.path.join(self.script_dir, "img/plus-round-line-icon.png")))
|
|
381
|
-
self.add_sub_action_entry_action.setToolTip("Add sub action")
|
|
382
|
-
self.add_sub_action_entry_action.triggered.connect(self.add_sub_action)
|
|
383
|
-
self.add_sub_action_entry_action.setEnabled(False)
|
|
384
|
-
toolbar.addAction(self.add_sub_action_entry_action)
|
|
385
|
-
toolbar.addSeparator()
|
|
386
|
-
toolbar.addAction(self.delete_element_action)
|
|
387
|
-
toolbar.addSeparator()
|
|
388
|
-
toolbar.addAction(self.run_job_action)
|
|
389
|
-
toolbar.addAction(self.run_all_jobs_action)
|
|
261
|
+
self.menu_manager.save_actions_set_enabled(enabled)
|
|
262
|
+
|
|
263
|
+
def update_title(self):
|
|
264
|
+
title = constants.APP_TITLE
|
|
265
|
+
file_name = self.current_file_name()
|
|
266
|
+
if file_name:
|
|
267
|
+
title += f" - {file_name}"
|
|
268
|
+
if self.modified():
|
|
269
|
+
title += " *"
|
|
270
|
+
self.window().setWindowTitle(title)
|
|
390
271
|
|
|
391
272
|
# pylint: disable=C0103
|
|
392
273
|
def contextMenuEvent(self, event):
|
|
393
|
-
item = self.job_list.itemAt(self.job_list.viewport().mapFrom(self, event.pos()))
|
|
274
|
+
item = self.job_list().itemAt(self.job_list().viewport().mapFrom(self, event.pos()))
|
|
394
275
|
current_action = None
|
|
395
276
|
if item:
|
|
396
|
-
index = self.job_list.row(item)
|
|
277
|
+
index = self.job_list().row(item)
|
|
397
278
|
current_action = self.get_job_at(index)
|
|
398
|
-
self.
|
|
399
|
-
item = self.action_list.itemAt(self.action_list.viewport().mapFrom(self, event.pos()))
|
|
279
|
+
self.set_current_job(index)
|
|
280
|
+
item = self.action_list().itemAt(self.action_list().viewport().mapFrom(self, event.pos()))
|
|
400
281
|
if item:
|
|
401
|
-
index = self.action_list.row(item)
|
|
402
|
-
self.
|
|
282
|
+
index = self.action_list().row(item)
|
|
283
|
+
self.set_current_action(index)
|
|
403
284
|
_job_row, _action_row, pos = self.get_action_at(index)
|
|
404
285
|
current_action = pos.action if not pos.is_sub_action else pos.sub_action
|
|
405
286
|
if current_action:
|
|
@@ -417,7 +298,7 @@ class MainWindow(ActionsWindow, LogManager):
|
|
|
417
298
|
os.path.exists(self.current_action_working_path):
|
|
418
299
|
action_name = "Browse Working Path" + (f" > {name}" if name != '' else '')
|
|
419
300
|
self.browse_working_path_action = QAction(action_name)
|
|
420
|
-
self.browse_working_path_action.triggered.connect(self.
|
|
301
|
+
self.browse_working_path_action.triggered.connect(self.browse_working_path)
|
|
421
302
|
menu.addAction(self.browse_working_path_action)
|
|
422
303
|
ip, name = get_action_input_path(current_action)
|
|
423
304
|
if ip != '':
|
|
@@ -431,16 +312,24 @@ class MainWindow(ActionsWindow, LogManager):
|
|
|
431
312
|
break
|
|
432
313
|
if p_exists:
|
|
433
314
|
action_name = "Browse Input Path" + (f" > {name}" if name != '' else '')
|
|
315
|
+
n_files = [f"{len(next(os.walk(p))[2])}"
|
|
316
|
+
for p in
|
|
317
|
+
self.current_action_input_path.split(constants.PATH_SEPARATOR)]
|
|
318
|
+
s = "" if len(n_files) == 1 and n_files[0] == 1 else "s"
|
|
319
|
+
action_name += " (" + ", ".join(n_files) + f" file{s})"
|
|
434
320
|
self.browse_input_path_action = QAction(action_name)
|
|
435
|
-
self.browse_input_path_action.triggered.connect(self.
|
|
321
|
+
self.browse_input_path_action.triggered.connect(self.browse_input_path)
|
|
436
322
|
menu.addAction(self.browse_input_path_action)
|
|
437
323
|
op, name = get_action_output_path(current_action)
|
|
438
324
|
if op != '':
|
|
439
325
|
self.current_action_output_path = f"{self.current_action_working_path}/{op}"
|
|
440
326
|
if os.path.exists(self.current_action_output_path):
|
|
441
327
|
action_name = "Browse Output Path" + (f" > {name}" if name != '' else '')
|
|
328
|
+
n_files = len(next(os.walk(op))[2])
|
|
329
|
+
s = "" if n_files == 1 else "s"
|
|
330
|
+
action_name += f" ({n_files} file{s})"
|
|
442
331
|
self.browse_output_path_action = QAction(action_name)
|
|
443
|
-
self.browse_output_path_action.triggered.connect(self.
|
|
332
|
+
self.browse_output_path_action.triggered.connect(self.browse_output_path)
|
|
444
333
|
menu.addAction(self.browse_output_path_action)
|
|
445
334
|
menu.addSeparator()
|
|
446
335
|
menu.addAction(self.run_job_action)
|
|
@@ -488,58 +377,57 @@ class MainWindow(ActionsWindow, LogManager):
|
|
|
488
377
|
if os.path.exists(p):
|
|
489
378
|
if running_under_windows():
|
|
490
379
|
os.startfile(os.path.normpath(p))
|
|
491
|
-
elif running_under_macos():
|
|
492
|
-
subprocess.run(['open', p], check=True)
|
|
493
380
|
else:
|
|
494
|
-
|
|
381
|
+
cmd = 'open' if running_under_macos() else 'xdg-open'
|
|
382
|
+
subprocess.run([cmd, p], check=True)
|
|
495
383
|
|
|
496
|
-
def
|
|
384
|
+
def browse_working_path(self):
|
|
497
385
|
self.browse_path(self.current_action_working_path)
|
|
498
386
|
|
|
499
|
-
def
|
|
387
|
+
def browse_input_path(self):
|
|
500
388
|
self.browse_path(self.current_action_input_path)
|
|
501
389
|
|
|
502
|
-
def
|
|
390
|
+
def browse_output_path(self):
|
|
503
391
|
self.browse_path(self.current_action_output_path)
|
|
504
392
|
|
|
505
393
|
def refresh_ui(self, job_row=-1, action_row=-1):
|
|
506
|
-
self.
|
|
507
|
-
for job in self.
|
|
508
|
-
self.add_list_item(self.job_list, job, False)
|
|
509
|
-
if self.
|
|
510
|
-
self.
|
|
394
|
+
self.clear_job_list()
|
|
395
|
+
for job in self.project_jobs():
|
|
396
|
+
self.project_editor.add_list_item(self.job_list(), job, False)
|
|
397
|
+
if self.project_jobs():
|
|
398
|
+
self.set_current_job(0)
|
|
511
399
|
if job_row >= 0:
|
|
512
|
-
self.
|
|
400
|
+
self.set_current_job(job_row)
|
|
513
401
|
if action_row >= 0:
|
|
514
|
-
self.
|
|
515
|
-
if self.
|
|
516
|
-
self.add_action_entry_action.setEnabled(False)
|
|
517
|
-
self.action_selector.setEnabled(False)
|
|
402
|
+
self.set_current_action(action_row)
|
|
403
|
+
if self.job_list_count() == 0:
|
|
404
|
+
self.menu_manager.add_action_entry_action.setEnabled(False)
|
|
405
|
+
self.menu_manager.action_selector.setEnabled(False)
|
|
518
406
|
self.run_job_action.setEnabled(False)
|
|
519
407
|
self.run_all_jobs_action.setEnabled(False)
|
|
520
408
|
else:
|
|
521
|
-
self.add_action_entry_action.setEnabled(True)
|
|
522
|
-
self.action_selector.setEnabled(True)
|
|
523
|
-
self.delete_element_action.setEnabled(True)
|
|
524
|
-
self.run_job_action.setEnabled(True)
|
|
525
|
-
self.run_all_jobs_action.setEnabled(True)
|
|
409
|
+
self.menu_manager.add_action_entry_action.setEnabled(True)
|
|
410
|
+
self.menu_manager.action_selector.setEnabled(True)
|
|
411
|
+
self.menu_manager.delete_element_action.setEnabled(True)
|
|
412
|
+
self.menu_manager.run_job_action.setEnabled(True)
|
|
413
|
+
self.menu_manager.run_all_jobs_action.setEnabled(True)
|
|
526
414
|
|
|
527
415
|
def quit(self):
|
|
528
|
-
if self.
|
|
416
|
+
if self.project_controller.check_unsaved_changes():
|
|
529
417
|
for worker in self._workers:
|
|
530
418
|
worker.stop()
|
|
531
419
|
self.close()
|
|
532
420
|
|
|
533
421
|
def toggle_expert_options(self):
|
|
534
|
-
self.expert_options = self.expert_options_action.isChecked()
|
|
422
|
+
self.expert_options = self.menu_manager.expert_options_action.isChecked()
|
|
535
423
|
|
|
536
424
|
def set_expert_options(self):
|
|
537
425
|
self.expert_options_action.setChecked(True)
|
|
538
426
|
self.expert_options = True
|
|
539
427
|
|
|
540
428
|
def before_thread_begins(self):
|
|
541
|
-
self.run_job_action.setEnabled(False)
|
|
542
|
-
self.run_all_jobs_action.setEnabled(False)
|
|
429
|
+
self.menu_manager.run_job_action.setEnabled(False)
|
|
430
|
+
self.menu_manager.run_all_jobs_action.setEnabled(False)
|
|
543
431
|
|
|
544
432
|
def get_tab_and_position(self, id_str):
|
|
545
433
|
for i in range(self.tab_widget.count()):
|
|
@@ -557,8 +445,8 @@ class MainWindow(ActionsWindow, LogManager):
|
|
|
557
445
|
return i
|
|
558
446
|
|
|
559
447
|
def do_handle_end_message(self, status, id_str, message):
|
|
560
|
-
self.run_job_action.setEnabled(True)
|
|
561
|
-
self.run_all_jobs_action.setEnabled(True)
|
|
448
|
+
self.menu_manager.run_job_action.setEnabled(True)
|
|
449
|
+
self.menu_manager.run_all_jobs_action.setEnabled(True)
|
|
562
450
|
tab = self.get_tab_at_position(id_str)
|
|
563
451
|
tab.close_button.setEnabled(True)
|
|
564
452
|
tab.stop_button.setEnabled(False)
|
|
@@ -569,8 +457,7 @@ class MainWindow(ActionsWindow, LogManager):
|
|
|
569
457
|
new_window = RunWindow(labels,
|
|
570
458
|
lambda id_str: self.stop_worker(self.get_tab_position(id_str)),
|
|
571
459
|
lambda id_str: self.close_window(self.get_tab_position(id_str)),
|
|
572
|
-
retouch_paths,
|
|
573
|
-
self)
|
|
460
|
+
retouch_paths, self)
|
|
574
461
|
self.tab_widget.addTab(new_window, title)
|
|
575
462
|
self.tab_widget.setCurrentIndex(self.tab_widget.count() - 1)
|
|
576
463
|
if title is not None:
|
|
@@ -589,7 +476,7 @@ class MainWindow(ActionsWindow, LogManager):
|
|
|
589
476
|
worker = self._workers[tab_position]
|
|
590
477
|
worker.stop()
|
|
591
478
|
|
|
592
|
-
def
|
|
479
|
+
def connect_worker_signals(self, worker, window):
|
|
593
480
|
worker.before_action_signal.connect(window.handle_before_action)
|
|
594
481
|
worker.after_action_signal.connect(window.handle_after_action)
|
|
595
482
|
worker.step_counts_signal.connect(window.handle_step_counts)
|
|
@@ -598,23 +485,18 @@ class MainWindow(ActionsWindow, LogManager):
|
|
|
598
485
|
worker.after_step_signal.connect(window.handle_after_step)
|
|
599
486
|
worker.save_plot_signal.connect(window.handle_save_plot)
|
|
600
487
|
worker.open_app_signal.connect(window.handle_open_app)
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
self.sub_action_selector.setEnabled(enabled)
|
|
605
|
-
for a in self.sub_action_menu_entries:
|
|
606
|
-
a.setEnabled(enabled)
|
|
488
|
+
worker.run_completed_signal.connect(window.handle_run_completed)
|
|
489
|
+
worker.run_stopped_signal.connect(window.handle_run_stopped)
|
|
490
|
+
worker.run_failed_signal.connect(window.handle_run_failed)
|
|
607
491
|
|
|
608
492
|
def run_job(self):
|
|
609
|
-
current_index = self.
|
|
493
|
+
current_index = self.current_job_index()
|
|
610
494
|
if current_index < 0:
|
|
611
|
-
if
|
|
612
|
-
|
|
613
|
-
else:
|
|
614
|
-
QMessageBox.warning(self, "No Job Added", "Please add a job first.")
|
|
495
|
+
msg = "No Job Selected" if self.num_project_jobs() > 0 else "No Job Added"
|
|
496
|
+
QMessageBox.warning(self, msg, "Please select a job first.")
|
|
615
497
|
return
|
|
616
498
|
if current_index >= 0:
|
|
617
|
-
job = self.
|
|
499
|
+
job = self.project_job(current_index)
|
|
618
500
|
if job.enabled():
|
|
619
501
|
job_name = job.params["name"]
|
|
620
502
|
labels = [[(self.action_text(a), a.enabled()) for a in job.sub_actions]]
|
|
@@ -623,29 +505,51 @@ class MainWindow(ActionsWindow, LogManager):
|
|
|
623
505
|
new_window, id_str = self.create_new_window(f"{job_name} [⚙️ Job]",
|
|
624
506
|
labels, retouch_paths)
|
|
625
507
|
worker = JobLogWorker(job, id_str)
|
|
626
|
-
self.
|
|
508
|
+
self.connect_worker_signals(worker, new_window)
|
|
627
509
|
self.start_thread(worker)
|
|
628
510
|
self._workers.append(worker)
|
|
629
511
|
else:
|
|
630
|
-
QMessageBox.warning(
|
|
631
|
-
|
|
632
|
-
"Job " + job.params["name"] + " is disabled.")
|
|
512
|
+
QMessageBox.warning(self, "Can't run Job",
|
|
513
|
+
"Job " + job.params["name"] + " is disabled.")
|
|
633
514
|
return
|
|
634
515
|
|
|
635
516
|
def run_all_jobs(self):
|
|
636
517
|
labels = [[(self.action_text(a), a.enabled() and
|
|
637
|
-
job.enabled()) for a in job.sub_actions] for job in self.
|
|
518
|
+
job.enabled()) for a in job.sub_actions] for job in self.project_jobs()]
|
|
638
519
|
project_name = ".".join(self.current_file_name().split(".")[:-1])
|
|
639
520
|
if project_name == '':
|
|
640
521
|
project_name = '[new]'
|
|
641
522
|
retouch_paths = []
|
|
642
|
-
for job in self.
|
|
523
|
+
for job in self.project_jobs():
|
|
643
524
|
r = self.get_retouch_path(job)
|
|
644
525
|
if len(r) > 0:
|
|
645
526
|
retouch_paths.append((job.params["name"], r))
|
|
646
527
|
new_window, id_str = self.create_new_window(f"{project_name} [Project 📚]",
|
|
647
528
|
labels, retouch_paths)
|
|
648
|
-
worker = ProjectLogWorker(self.project, id_str)
|
|
649
|
-
self.
|
|
529
|
+
worker = ProjectLogWorker(self.project(), id_str)
|
|
530
|
+
self.connect_worker_signals(worker, new_window)
|
|
650
531
|
self.start_thread(worker)
|
|
651
532
|
self._workers.append(worker)
|
|
533
|
+
|
|
534
|
+
def delete_element(self):
|
|
535
|
+
self.project_editor.delete_element()
|
|
536
|
+
if self.job_list_count() > 0:
|
|
537
|
+
self.menu_manager.delete_element_action.setEnabled(True)
|
|
538
|
+
|
|
539
|
+
def update_delete_action_state(self):
|
|
540
|
+
has_job_selected = self.num_selected_jobs() > 0
|
|
541
|
+
has_action_selected = self.num_selected_actions() > 0
|
|
542
|
+
self.menu_manager.delete_element_action.setEnabled(
|
|
543
|
+
has_job_selected or has_action_selected)
|
|
544
|
+
if has_action_selected and has_job_selected:
|
|
545
|
+
job_index = min(self.current_job_index(), self.num_project_jobs() - 1)
|
|
546
|
+
action_index = self.current_action_index()
|
|
547
|
+
if job_index >= 0:
|
|
548
|
+
job = self.project_job(job_index)
|
|
549
|
+
current_action, is_sub_action = \
|
|
550
|
+
self.get_current_action_at(job, action_index)
|
|
551
|
+
enable_sub_actions = current_action is not None and \
|
|
552
|
+
not is_sub_action and current_action.type_name == constants.ACTION_COMBO
|
|
553
|
+
self.menu_manager.set_enabled_sub_actions_gui(enable_sub_actions)
|
|
554
|
+
else:
|
|
555
|
+
self.menu_manager.set_enabled_sub_actions_gui(False)
|