shinestacker 0.4.0__py3-none-any.whl → 1.0.0__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 +101 -12
- 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 +10 -9
- 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 +276 -367
- shinestacker/gui/menu_manager.py +236 -0
- shinestacker/gui/new_project.py +75 -20
- 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 +25 -11
- shinestacker/retouch/denoise_filter.py +5 -44
- shinestacker/retouch/display_manager.py +57 -20
- 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 +365 -49
- shinestacker/retouch/image_viewer.py +34 -11
- shinestacker/retouch/io_gui_handler.py +96 -43
- shinestacker/retouch/io_manager.py +23 -7
- 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.4.0.dist-info → shinestacker-1.0.0.dist-info}/METADATA +14 -2
- shinestacker-1.0.0.dist-info/RECORD +90 -0
- shinestacker/app/app_config.py +0 -22
- shinestacker/gui/actions_window.py +0 -258
- shinestacker/retouch/image_editor.py +0 -201
- shinestacker/retouch/image_filters.py +0 -69
- shinestacker-0.4.0.dist-info/RECORD +0 -87
- {shinestacker-0.4.0.dist-info → shinestacker-1.0.0.dist-info}/WHEEL +0 -0
- {shinestacker-0.4.0.dist-info → shinestacker-1.0.0.dist-info}/entry_points.txt +0 -0
- {shinestacker-0.4.0.dist-info → shinestacker-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {shinestacker-0.4.0.dist-info → shinestacker-1.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,22 +1,19 @@
|
|
|
1
|
-
# pylint: disable=C0114, C0115, C0116, R0904, R1702, R0917, R0913, R0902, E0611, E1131
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116, R0904, R1702, R0917, R0913, R0902, E0611, E1131, E1121
|
|
2
2
|
import os
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from PySide6.QtWidgets import (
|
|
4
|
+
from PySide6.QtWidgets import (QListWidget, QMessageBox,
|
|
5
5
|
QDialog, QListWidgetItem, QLabel)
|
|
6
|
-
from PySide6.QtCore import Qt
|
|
6
|
+
from PySide6.QtCore import Qt, QObject, Signal
|
|
7
7
|
from .. config.constants import constants
|
|
8
8
|
from .colors import ColorPalette
|
|
9
|
-
from .
|
|
10
|
-
from .project_model import get_action_input_path, get_action_output_path
|
|
11
|
-
|
|
12
|
-
INDENT_SPACE = " ↪ "
|
|
13
|
-
CLONE_POSTFIX = " (clone)"
|
|
9
|
+
from .action_config_dialog import ActionConfigDialog
|
|
10
|
+
from .project_model import ActionConfig, get_action_input_path, get_action_output_path
|
|
14
11
|
|
|
15
12
|
|
|
16
13
|
@dataclass
|
|
17
14
|
class ActionPosition:
|
|
18
15
|
actions: list
|
|
19
|
-
sub_actions: list
|
|
16
|
+
sub_actions: list
|
|
20
17
|
action_index: int
|
|
21
18
|
sub_action_index: int = -1
|
|
22
19
|
|
|
@@ -77,20 +74,81 @@ def new_row_after_clone(job, action_row, is_sub_action, cloned):
|
|
|
77
74
|
for action in job.sub_actions[:job.sub_actions.index(cloned)])
|
|
78
75
|
|
|
79
76
|
|
|
80
|
-
class
|
|
77
|
+
class ProjectUndoManager:
|
|
81
78
|
def __init__(self):
|
|
82
|
-
|
|
79
|
+
self._undo_buffer = []
|
|
80
|
+
|
|
81
|
+
def add(self, item):
|
|
82
|
+
self._undo_buffer.append(item)
|
|
83
|
+
|
|
84
|
+
def pop(self):
|
|
85
|
+
return self._undo_buffer.pop()
|
|
86
|
+
|
|
87
|
+
def filled(self):
|
|
88
|
+
return len(self._undo_buffer) != 0
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class ProjectEditor(QObject):
|
|
92
|
+
INDENT_SPACE = " ↪ "
|
|
93
|
+
CLONE_POSTFIX = " (clone)"
|
|
94
|
+
|
|
95
|
+
modified_signal = Signal(int)
|
|
96
|
+
select_signal = Signal()
|
|
97
|
+
refresh_ui_signal = Signal(int, int)
|
|
98
|
+
enable_delete_action_signal = Signal(bool)
|
|
99
|
+
|
|
100
|
+
def __init__(self, parent=None):
|
|
101
|
+
super().__init__(parent)
|
|
102
|
+
self._undo_manager = ProjectUndoManager()
|
|
103
|
+
self._modified = False
|
|
104
|
+
self._project = None
|
|
83
105
|
self._copy_buffer = None
|
|
84
|
-
self.project_buffer = []
|
|
85
|
-
self.job_list = QListWidget()
|
|
86
|
-
self.action_list = QListWidget()
|
|
87
|
-
self.project = None
|
|
88
|
-
self.job_list_model = None
|
|
89
|
-
self.expert_options = False
|
|
90
|
-
self.script_dir = os.path.dirname(__file__)
|
|
91
|
-
self.dialog = None
|
|
92
106
|
self._current_file_path = ''
|
|
93
|
-
self.
|
|
107
|
+
self._job_list = QListWidget()
|
|
108
|
+
self._action_list = QListWidget()
|
|
109
|
+
self.dialog = None
|
|
110
|
+
|
|
111
|
+
def add_undo(self, item):
|
|
112
|
+
self._undo_manager.add(item)
|
|
113
|
+
|
|
114
|
+
def pop_undo(self):
|
|
115
|
+
return self._undo_manager.pop()
|
|
116
|
+
|
|
117
|
+
def filled_undo(self):
|
|
118
|
+
return self._undo_manager.filled()
|
|
119
|
+
|
|
120
|
+
def mark_as_modified(self, modified=True):
|
|
121
|
+
self._modified = modified
|
|
122
|
+
if modified:
|
|
123
|
+
self.add_undo(self._project.clone())
|
|
124
|
+
self.modified_signal.emit(modified)
|
|
125
|
+
|
|
126
|
+
def modified(self):
|
|
127
|
+
return self._modified
|
|
128
|
+
|
|
129
|
+
def set_project(self, project):
|
|
130
|
+
self._project = project
|
|
131
|
+
|
|
132
|
+
def project(self):
|
|
133
|
+
return self._project
|
|
134
|
+
|
|
135
|
+
def project_jobs(self):
|
|
136
|
+
return self._project.jobs
|
|
137
|
+
|
|
138
|
+
def add_job_to_project(self, job):
|
|
139
|
+
self._project.jobs.append(job)
|
|
140
|
+
|
|
141
|
+
def num_project_jobs(self):
|
|
142
|
+
return len(self.project().jobs)
|
|
143
|
+
|
|
144
|
+
def copy_buffer(self):
|
|
145
|
+
return self._copy_buffer
|
|
146
|
+
|
|
147
|
+
def set_copy_buffer(self, item):
|
|
148
|
+
self._copy_buffer = item
|
|
149
|
+
|
|
150
|
+
def has_copy_buffer(self):
|
|
151
|
+
return self._copy_buffer is not None
|
|
94
152
|
|
|
95
153
|
def current_file_path(self):
|
|
96
154
|
return self._current_file_path
|
|
@@ -111,8 +169,59 @@ class ProjectEditor(QMainWindow):
|
|
|
111
169
|
self._current_file_path = os.path.abspath(path)
|
|
112
170
|
os.chdir(self.current_file_directory())
|
|
113
171
|
|
|
114
|
-
def
|
|
115
|
-
self.
|
|
172
|
+
def project_job(self, index):
|
|
173
|
+
return self._project.jobs[index]
|
|
174
|
+
|
|
175
|
+
def job_list(self):
|
|
176
|
+
return self._job_list
|
|
177
|
+
|
|
178
|
+
def action_list(self):
|
|
179
|
+
return self._action_list
|
|
180
|
+
|
|
181
|
+
def current_job_index(self):
|
|
182
|
+
return self._job_list.currentRow()
|
|
183
|
+
|
|
184
|
+
def current_action_index(self):
|
|
185
|
+
return self._action_list.currentRow()
|
|
186
|
+
|
|
187
|
+
def set_current_job(self, index):
|
|
188
|
+
self._job_list.setCurrentRow(index)
|
|
189
|
+
|
|
190
|
+
def set_current_action(self, index):
|
|
191
|
+
self._action_list.setCurrentRow(index)
|
|
192
|
+
|
|
193
|
+
def job_list_count(self):
|
|
194
|
+
return self._job_list.count()
|
|
195
|
+
|
|
196
|
+
def action_list_count(self):
|
|
197
|
+
return self._action_list.count()
|
|
198
|
+
|
|
199
|
+
def job_list_item(self, index):
|
|
200
|
+
return self._job_list.item(index)
|
|
201
|
+
|
|
202
|
+
def action_list_item(self, index):
|
|
203
|
+
return self._action_list.item(index)
|
|
204
|
+
|
|
205
|
+
def job_list_has_focus(self):
|
|
206
|
+
return self._job_list.hasFocus()
|
|
207
|
+
|
|
208
|
+
def action_list_has_focus(self):
|
|
209
|
+
return self._action_list.hasFocus()
|
|
210
|
+
|
|
211
|
+
def take_job(self, index):
|
|
212
|
+
return self._job_list.takeItem(index)
|
|
213
|
+
|
|
214
|
+
def clear_job_list(self):
|
|
215
|
+
self._job_list.clear()
|
|
216
|
+
|
|
217
|
+
def clear_action_list(self):
|
|
218
|
+
self._action_list.clear()
|
|
219
|
+
|
|
220
|
+
def num_selected_jobs(self):
|
|
221
|
+
return len(self._job_list.selectedItems())
|
|
222
|
+
|
|
223
|
+
def num_selected_actions(self):
|
|
224
|
+
return len(self._action_list.selectedItems())
|
|
116
225
|
|
|
117
226
|
def job_text(self, job, long_name=False, html=False):
|
|
118
227
|
txt = f"{job.params.get('name', '(job)')}"
|
|
@@ -135,7 +244,7 @@ class ProjectEditor(QMainWindow):
|
|
|
135
244
|
}
|
|
136
245
|
ico = icon_map.get(action.type_name, '')
|
|
137
246
|
if is_sub_action and indent:
|
|
138
|
-
txt = INDENT_SPACE
|
|
247
|
+
txt = self.INDENT_SPACE
|
|
139
248
|
if ico == '':
|
|
140
249
|
ico = '🟣'
|
|
141
250
|
else:
|
|
@@ -152,22 +261,22 @@ class ProjectEditor(QMainWindow):
|
|
|
152
261
|
if long_name and not is_sub_action else "]")
|
|
153
262
|
|
|
154
263
|
def get_job_at(self, index):
|
|
155
|
-
return None if index < 0 else self.
|
|
264
|
+
return None if index < 0 else self.project_job(index)
|
|
156
265
|
|
|
157
266
|
def get_current_job(self):
|
|
158
|
-
return self.get_job_at(self.
|
|
267
|
+
return self.get_job_at(self.current_job_index())
|
|
159
268
|
|
|
160
269
|
def get_current_action(self):
|
|
161
|
-
return self.get_action_at(self.
|
|
270
|
+
return self.get_action_at(self.current_action_index())
|
|
162
271
|
|
|
163
272
|
def get_action_at(self, action_row):
|
|
164
|
-
job_row = self.
|
|
273
|
+
job_row = self.current_job_index()
|
|
165
274
|
if job_row < 0 or action_row < 0:
|
|
166
275
|
return (job_row, action_row, None)
|
|
167
276
|
action, sub_action, sub_action_index = self.find_action_position(job_row, action_row)
|
|
168
277
|
if not action:
|
|
169
278
|
return (job_row, action_row, None)
|
|
170
|
-
job = self.
|
|
279
|
+
job = self.project_job(job_row)
|
|
171
280
|
if sub_action:
|
|
172
281
|
return (job_row, action_row,
|
|
173
282
|
ActionPosition(job.sub_actions, action.sub_actions,
|
|
@@ -176,9 +285,9 @@ class ProjectEditor(QMainWindow):
|
|
|
176
285
|
ActionPosition(job.sub_actions, None, job.sub_actions.index(action)))
|
|
177
286
|
|
|
178
287
|
def find_action_position(self, job_index, ui_index):
|
|
179
|
-
if not 0 <= job_index <
|
|
288
|
+
if not 0 <= job_index < self.num_project_jobs():
|
|
180
289
|
return (None, None, -1)
|
|
181
|
-
actions = self.
|
|
290
|
+
actions = self.project_job(job_index).sub_actions
|
|
182
291
|
counter = -1
|
|
183
292
|
for action in actions:
|
|
184
293
|
counter += 1
|
|
@@ -190,19 +299,16 @@ class ProjectEditor(QMainWindow):
|
|
|
190
299
|
return (action, sub_action, sub_action_index)
|
|
191
300
|
return (None, None, -1)
|
|
192
301
|
|
|
193
|
-
def refresh_ui(self, job_row=-1, action_row=-1):
|
|
194
|
-
pass
|
|
195
|
-
|
|
196
302
|
def shift_job(self, delta):
|
|
197
|
-
job_index = self.
|
|
303
|
+
job_index = self.current_job_index()
|
|
198
304
|
if job_index < 0:
|
|
199
305
|
return
|
|
200
306
|
new_index = job_index + delta
|
|
201
|
-
if 0 <= new_index <
|
|
202
|
-
jobs = self.
|
|
307
|
+
if 0 <= new_index < self.num_project_jobs():
|
|
308
|
+
jobs = self.project_jobs()
|
|
203
309
|
self.mark_as_modified()
|
|
204
310
|
jobs.insert(new_index, jobs.pop(job_index))
|
|
205
|
-
self.
|
|
311
|
+
self.refresh_ui_signal.emit(new_index, -1)
|
|
206
312
|
|
|
207
313
|
def shift_action(self, delta):
|
|
208
314
|
job_row, action_row, pos = self.get_current_action()
|
|
@@ -218,70 +324,70 @@ class ProjectEditor(QMainWindow):
|
|
|
218
324
|
self.mark_as_modified()
|
|
219
325
|
pos.sub_actions.insert(new_index, pos.sub_actions.pop(pos.sub_action_index))
|
|
220
326
|
new_row = new_row_after_insert(action_row, pos, delta)
|
|
221
|
-
self.
|
|
327
|
+
self.refresh_ui_signal.emit(job_row, new_row)
|
|
222
328
|
|
|
223
329
|
def move_element_up(self):
|
|
224
|
-
if self.
|
|
330
|
+
if self.job_list_has_focus():
|
|
225
331
|
self.shift_job(-1)
|
|
226
|
-
elif self.
|
|
332
|
+
elif self.action_list_has_focus():
|
|
227
333
|
self.shift_action(-1)
|
|
228
334
|
|
|
229
335
|
def move_element_down(self):
|
|
230
|
-
if self.
|
|
336
|
+
if self.job_list_has_focus():
|
|
231
337
|
self.shift_job(+1)
|
|
232
|
-
elif self.
|
|
338
|
+
elif self.action_list_has_focus():
|
|
233
339
|
self.shift_action(+1)
|
|
234
340
|
|
|
235
341
|
def clone_job(self):
|
|
236
|
-
job_index = self.
|
|
237
|
-
if 0 <= job_index <
|
|
238
|
-
job_clone = self.
|
|
342
|
+
job_index = self.current_job_index()
|
|
343
|
+
if 0 <= job_index < self.num_project_jobs():
|
|
344
|
+
job_clone = self.project_job(job_index).clone(self.CLONE_POSTFIX)
|
|
239
345
|
new_job_index = job_index + 1
|
|
240
346
|
self.mark_as_modified()
|
|
241
|
-
self.
|
|
242
|
-
self.
|
|
243
|
-
self.
|
|
244
|
-
self.
|
|
347
|
+
self.project_jobs().insert(new_job_index, job_clone)
|
|
348
|
+
self.set_current_job(new_job_index)
|
|
349
|
+
self.set_current_action(new_job_index)
|
|
350
|
+
self.refresh_ui_signal.emit(new_job_index, -1)
|
|
245
351
|
|
|
246
352
|
def clone_action(self):
|
|
247
353
|
job_row, action_row, pos = self.get_current_action()
|
|
248
354
|
if not pos.actions:
|
|
249
355
|
return
|
|
250
356
|
self.mark_as_modified()
|
|
251
|
-
job = self.
|
|
357
|
+
job = self.project_job(job_row)
|
|
252
358
|
if pos.is_sub_action:
|
|
253
|
-
cloned = pos.sub_action.clone(CLONE_POSTFIX)
|
|
359
|
+
cloned = pos.sub_action.clone(self.CLONE_POSTFIX)
|
|
254
360
|
pos.sub_actions.insert(pos.sub_action_index + 1, cloned)
|
|
255
361
|
else:
|
|
256
|
-
cloned = pos.action.clone(CLONE_POSTFIX)
|
|
362
|
+
cloned = pos.action.clone(self.CLONE_POSTFIX)
|
|
257
363
|
job.sub_actions.insert(pos.action_index + 1, cloned)
|
|
258
364
|
new_row = new_row_after_clone(job, action_row, pos.is_sub_action, cloned)
|
|
259
|
-
self.
|
|
365
|
+
self.refresh_ui_signal.emit(job_row, new_row)
|
|
260
366
|
|
|
261
367
|
def clone_element(self):
|
|
262
|
-
if self.
|
|
368
|
+
if self.job_list_has_focus():
|
|
263
369
|
self.clone_job()
|
|
264
|
-
elif self.
|
|
370
|
+
elif self.action_list_has_focus():
|
|
265
371
|
self.clone_action()
|
|
266
372
|
|
|
267
373
|
def delete_job(self, confirm=True):
|
|
268
|
-
current_index = self.
|
|
269
|
-
if 0 <= current_index <
|
|
374
|
+
current_index = self.current_job_index()
|
|
375
|
+
if 0 <= current_index < self.num_project_jobs():
|
|
270
376
|
if confirm:
|
|
271
377
|
reply = QMessageBox.question(
|
|
272
|
-
self, "Confirm Delete",
|
|
378
|
+
self.parent(), "Confirm Delete",
|
|
273
379
|
"Are you sure you want to delete job "
|
|
274
|
-
f"'{self.
|
|
380
|
+
f"'{self.project_job(current_index).params.get('name', '')}'?",
|
|
275
381
|
QMessageBox.Yes | QMessageBox.No
|
|
276
382
|
)
|
|
277
383
|
else:
|
|
278
384
|
reply = None
|
|
279
385
|
if not confirm or reply == QMessageBox.Yes:
|
|
280
|
-
self.
|
|
386
|
+
self.take_job(current_index)
|
|
281
387
|
self.mark_as_modified()
|
|
282
|
-
current_job = self.
|
|
283
|
-
self.
|
|
284
|
-
self.
|
|
388
|
+
current_job = self.project_jobs().pop(current_index)
|
|
389
|
+
self.clear_action_list()
|
|
390
|
+
self.refresh_ui_signal.emit(-1, -1)
|
|
285
391
|
return current_job
|
|
286
392
|
return None
|
|
287
393
|
|
|
@@ -291,7 +397,7 @@ class ProjectEditor(QMainWindow):
|
|
|
291
397
|
current_action = pos.action if not pos.is_sub_action else pos.sub_action
|
|
292
398
|
if confirm:
|
|
293
399
|
reply = QMessageBox.question(
|
|
294
|
-
self,
|
|
400
|
+
self.parent(),
|
|
295
401
|
"Confirm Delete",
|
|
296
402
|
"Are you sure you want to delete action "
|
|
297
403
|
f"'{self.action_text(current_action, pos.is_sub_action, indent=False)}'?",
|
|
@@ -304,55 +410,53 @@ class ProjectEditor(QMainWindow):
|
|
|
304
410
|
if pos.is_sub_action:
|
|
305
411
|
pos.action.pop_sub_action(pos.sub_action_index)
|
|
306
412
|
else:
|
|
307
|
-
self.
|
|
413
|
+
self.project_job(job_row).pop_sub_action(pos.action_index)
|
|
308
414
|
new_row = new_row_after_delete(action_row, pos)
|
|
309
|
-
self.
|
|
415
|
+
self.refresh_ui_signal.emit(job_row, new_row)
|
|
310
416
|
return current_action
|
|
311
417
|
return None
|
|
312
418
|
|
|
313
419
|
def delete_element(self, confirm=True):
|
|
314
|
-
if self.
|
|
420
|
+
if self.job_list_has_focus():
|
|
315
421
|
element = self.delete_job(confirm)
|
|
316
|
-
elif self.
|
|
422
|
+
elif self.action_list_has_focus():
|
|
317
423
|
element = self.delete_action(confirm)
|
|
318
424
|
else:
|
|
319
425
|
element = None
|
|
320
|
-
if self.job_list.count() > 0:
|
|
321
|
-
self.delete_element_action.setEnabled(True)
|
|
322
426
|
return element
|
|
323
427
|
|
|
324
428
|
def action_config_dialog(self, action):
|
|
325
|
-
return ActionConfigDialog(action, self.current_file_directory(), self)
|
|
429
|
+
return ActionConfigDialog(action, self.current_file_directory(), self.parent())
|
|
326
430
|
|
|
327
431
|
def add_job(self):
|
|
328
432
|
job_action = ActionConfig("Job")
|
|
329
433
|
self.dialog = self.action_config_dialog(job_action)
|
|
330
434
|
if self.dialog.exec() == QDialog.Accepted:
|
|
331
435
|
self.mark_as_modified()
|
|
332
|
-
self.
|
|
333
|
-
self.add_list_item(self.job_list, job_action, False)
|
|
334
|
-
self.
|
|
335
|
-
self.
|
|
336
|
-
self.
|
|
337
|
-
|
|
338
|
-
def add_action(self, type_name
|
|
339
|
-
current_index = self.
|
|
436
|
+
self.project_jobs().append(job_action)
|
|
437
|
+
self.add_list_item(self.job_list(), job_action, False)
|
|
438
|
+
self.set_current_job(self.job_list_count() - 1)
|
|
439
|
+
self.job_list_item(self.job_list_count() - 1).setSelected(True)
|
|
440
|
+
self.refresh_ui_signal.emit(-1, -1)
|
|
441
|
+
|
|
442
|
+
def add_action(self, type_name):
|
|
443
|
+
current_index = self.current_job_index()
|
|
340
444
|
if current_index < 0:
|
|
341
|
-
if
|
|
342
|
-
QMessageBox.warning(self
|
|
445
|
+
if self.num_project_jobs() > 0:
|
|
446
|
+
QMessageBox.warning(self.parent(),
|
|
447
|
+
"No Job Selected", "Please select a job first.")
|
|
343
448
|
else:
|
|
344
|
-
QMessageBox.warning(self
|
|
449
|
+
QMessageBox.warning(self.parent(),
|
|
450
|
+
"No Job Added", "Please add a job first.")
|
|
345
451
|
return
|
|
346
|
-
if type_name is False:
|
|
347
|
-
type_name = self.action_selector.currentText()
|
|
348
452
|
action = ActionConfig(type_name)
|
|
349
453
|
action.parent = self.get_current_job()
|
|
350
454
|
self.dialog = self.action_config_dialog(action)
|
|
351
455
|
if self.dialog.exec() == QDialog.Accepted:
|
|
352
456
|
self.mark_as_modified()
|
|
353
|
-
self.
|
|
354
|
-
self.add_list_item(self.action_list, action, False)
|
|
355
|
-
self.
|
|
457
|
+
self.project_job(current_index).add_sub_action(action)
|
|
458
|
+
self.add_list_item(self.action_list(), action, False)
|
|
459
|
+
self.enable_delete_action_signal.emit(False)
|
|
356
460
|
|
|
357
461
|
def add_list_item(self, widget_list, action, is_sub_action):
|
|
358
462
|
if action.type_name == constants.ACTION_JOB:
|
|
@@ -369,13 +473,13 @@ class ProjectEditor(QMainWindow):
|
|
|
369
473
|
label = QLabel(html_text)
|
|
370
474
|
widget_list.setItemWidget(item, label)
|
|
371
475
|
|
|
372
|
-
def add_sub_action(self, type_name
|
|
373
|
-
current_job_index = self.
|
|
374
|
-
current_action_index = self.
|
|
476
|
+
def add_sub_action(self, type_name):
|
|
477
|
+
current_job_index = self.current_job_index()
|
|
478
|
+
current_action_index = self.current_action_index()
|
|
375
479
|
if current_job_index < 0 or current_action_index < 0 or \
|
|
376
|
-
current_job_index >=
|
|
480
|
+
current_job_index >= self.num_project_jobs():
|
|
377
481
|
return
|
|
378
|
-
job = self.
|
|
482
|
+
job = self.project_job(current_job_index)
|
|
379
483
|
action = None
|
|
380
484
|
action_counter = -1
|
|
381
485
|
for act in job.sub_actions:
|
|
@@ -386,96 +490,93 @@ class ProjectEditor(QMainWindow):
|
|
|
386
490
|
action_counter += len(act.sub_actions)
|
|
387
491
|
if not action or action.type_name != constants.ACTION_COMBO:
|
|
388
492
|
return
|
|
389
|
-
if type_name is False:
|
|
390
|
-
type_name = self.sub_action_selector.currentText()
|
|
391
493
|
sub_action = ActionConfig(type_name)
|
|
392
494
|
self.dialog = self.action_config_dialog(sub_action)
|
|
393
495
|
if self.dialog.exec() == QDialog.Accepted:
|
|
394
496
|
self.mark_as_modified()
|
|
395
497
|
action.add_sub_action(sub_action)
|
|
396
498
|
self.on_job_selected(current_job_index)
|
|
397
|
-
self.
|
|
499
|
+
self.set_current_action(current_action_index)
|
|
398
500
|
|
|
399
501
|
def copy_job(self):
|
|
400
|
-
current_index = self.
|
|
401
|
-
if 0 <= current_index <
|
|
402
|
-
self.
|
|
502
|
+
current_index = self.current_job_index()
|
|
503
|
+
if 0 <= current_index < self.num_project_jobs():
|
|
504
|
+
self.set_copy_buffer(self.project_job(current_index).clone())
|
|
403
505
|
|
|
404
506
|
def copy_action(self):
|
|
405
507
|
_job_row, _action_row, pos = self.get_current_action()
|
|
406
508
|
if pos.actions is not None:
|
|
407
|
-
self.
|
|
509
|
+
self.set_copy_buffer(pos.sub_action.clone()
|
|
510
|
+
if pos.is_sub_action else pos.action.clone())
|
|
408
511
|
|
|
409
512
|
def copy_element(self):
|
|
410
|
-
if self.
|
|
513
|
+
if self.job_list_has_focus():
|
|
411
514
|
self.copy_job()
|
|
412
|
-
elif self.
|
|
515
|
+
elif self.action_list_has_focus():
|
|
413
516
|
self.copy_action()
|
|
414
517
|
|
|
415
518
|
def paste_job(self):
|
|
416
|
-
if self.
|
|
519
|
+
if self.copy_buffer().type_name != constants.ACTION_JOB:
|
|
417
520
|
return
|
|
418
|
-
job_index = self.
|
|
419
|
-
if 0 <= job_index <
|
|
521
|
+
job_index = self.current_job_index()
|
|
522
|
+
if 0 <= job_index < self.num_project_jobs():
|
|
420
523
|
new_job_index = job_index
|
|
421
524
|
self.mark_as_modified()
|
|
422
|
-
self.
|
|
423
|
-
self.
|
|
424
|
-
self.
|
|
425
|
-
self.
|
|
525
|
+
self.project_jobs().insert(new_job_index, self.copy_buffer())
|
|
526
|
+
self.set_current_job(new_job_index)
|
|
527
|
+
self.set_current_action(new_job_index)
|
|
528
|
+
self.refresh_ui_signal.emit(new_job_index, -1)
|
|
426
529
|
|
|
427
530
|
def paste_action(self):
|
|
428
531
|
job_row, action_row, pos = self.get_current_action()
|
|
429
532
|
if pos.actions is not None:
|
|
430
533
|
if not pos.is_sub_action:
|
|
431
|
-
if self.
|
|
534
|
+
if self.copy_buffer().type_name not in constants.ACTION_TYPES:
|
|
432
535
|
return
|
|
433
536
|
self.mark_as_modified()
|
|
434
|
-
pos.actions.insert(pos.action_index, self.
|
|
537
|
+
pos.actions.insert(pos.action_index, self.copy_buffer())
|
|
435
538
|
else:
|
|
436
539
|
if pos.action.type_name != constants.ACTION_COMBO or \
|
|
437
|
-
self.
|
|
540
|
+
self.copy_buffer().type_name not in constants.SUB_ACTION_TYPES:
|
|
438
541
|
return
|
|
439
542
|
self.mark_as_modified()
|
|
440
|
-
pos.sub_actions.insert(pos.sub_action_index, self.
|
|
543
|
+
pos.sub_actions.insert(pos.sub_action_index, self.copy_buffer())
|
|
441
544
|
new_row = new_row_after_paste(action_row, pos)
|
|
442
|
-
self.
|
|
545
|
+
self.refresh_ui_signal.emit(job_row, new_row)
|
|
443
546
|
|
|
444
547
|
def paste_element(self):
|
|
445
|
-
if self.
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
self.
|
|
449
|
-
|
|
450
|
-
self.paste_action()
|
|
548
|
+
if self.has_copy_buffer():
|
|
549
|
+
if self.job_list_has_focus():
|
|
550
|
+
self.paste_job()
|
|
551
|
+
elif self.action_list_has_focus():
|
|
552
|
+
self.paste_action()
|
|
451
553
|
|
|
452
554
|
def cut_element(self):
|
|
453
|
-
self.
|
|
555
|
+
self.set_copy_buffer(self.delete_element(False))
|
|
454
556
|
|
|
455
557
|
def undo(self):
|
|
456
|
-
job_row = self.
|
|
457
|
-
action_row = self.
|
|
458
|
-
if
|
|
459
|
-
self.set_project(self.
|
|
460
|
-
self.
|
|
461
|
-
len_jobs =
|
|
558
|
+
job_row = self.current_job_index()
|
|
559
|
+
action_row = self.current_action_index()
|
|
560
|
+
if self.filled_undo():
|
|
561
|
+
self.set_project(self.pop_undo())
|
|
562
|
+
self.refresh_ui_signal.emit(-1, -1)
|
|
563
|
+
len_jobs = self.num_project_jobs()
|
|
462
564
|
if len_jobs > 0:
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
self.
|
|
466
|
-
len_actions = self.action_list.count()
|
|
565
|
+
job_row = min(job_row, len_jobs - 1)
|
|
566
|
+
self.set_current_job(job_row)
|
|
567
|
+
len_actions = self.action_list_count()
|
|
467
568
|
if len_actions > 0:
|
|
468
569
|
action_row = min(action_row, len_actions)
|
|
469
|
-
self.
|
|
570
|
+
self.set_current_action(action_row)
|
|
470
571
|
|
|
471
572
|
def set_enabled(self, enabled):
|
|
472
573
|
current_action = None
|
|
473
|
-
if self.
|
|
474
|
-
job_row = self.
|
|
475
|
-
if 0 <= job_row <
|
|
476
|
-
current_action = self.
|
|
574
|
+
if self.job_list_has_focus():
|
|
575
|
+
job_row = self.current_job_index()
|
|
576
|
+
if 0 <= job_row < self.num_project_jobs():
|
|
577
|
+
current_action = self.project_job(job_row)
|
|
477
578
|
action_row = -1
|
|
478
|
-
elif self.
|
|
579
|
+
elif self.action_list_has_focus():
|
|
479
580
|
job_row, action_row, pos = self.get_current_action()
|
|
480
581
|
current_action = pos.sub_action if pos.is_sub_action else pos.action
|
|
481
582
|
else:
|
|
@@ -484,7 +585,7 @@ class ProjectEditor(QMainWindow):
|
|
|
484
585
|
if current_action.enabled() != enabled:
|
|
485
586
|
self.mark_as_modified()
|
|
486
587
|
current_action.set_enabled(enabled)
|
|
487
|
-
self.
|
|
588
|
+
self.refresh_ui_signal.emit(job_row, action_row)
|
|
488
589
|
|
|
489
590
|
def enable(self):
|
|
490
591
|
self.set_enabled(True)
|
|
@@ -494,11 +595,11 @@ class ProjectEditor(QMainWindow):
|
|
|
494
595
|
|
|
495
596
|
def set_enabled_all(self, enable=True):
|
|
496
597
|
self.mark_as_modified()
|
|
497
|
-
job_row = self.
|
|
498
|
-
action_row = self.
|
|
499
|
-
for j in self.
|
|
598
|
+
job_row = self.current_job_index()
|
|
599
|
+
action_row = self.current_action_index()
|
|
600
|
+
for j in self.project_jobs():
|
|
500
601
|
j.set_enabled_all(enable)
|
|
501
|
-
self.
|
|
602
|
+
self.refresh_ui_signal.emit(job_row, action_row)
|
|
502
603
|
|
|
503
604
|
def enable_all(self):
|
|
504
605
|
self.set_enabled_all(True)
|
|
@@ -507,15 +608,15 @@ class ProjectEditor(QMainWindow):
|
|
|
507
608
|
self.set_enabled_all(False)
|
|
508
609
|
|
|
509
610
|
def on_job_selected(self, index):
|
|
510
|
-
self.
|
|
511
|
-
if 0 <= index <
|
|
512
|
-
job = self.
|
|
611
|
+
self.clear_action_list()
|
|
612
|
+
if 0 <= index < self.num_project_jobs():
|
|
613
|
+
job = self.project_job(index)
|
|
513
614
|
for action in job.sub_actions:
|
|
514
|
-
self.add_list_item(self.action_list, action, False)
|
|
615
|
+
self.add_list_item(self.action_list(), action, False)
|
|
515
616
|
if len(action.sub_actions) > 0:
|
|
516
617
|
for sub_action in action.sub_actions:
|
|
517
|
-
self.add_list_item(self.action_list, sub_action, True)
|
|
518
|
-
self.
|
|
618
|
+
self.add_list_item(self.action_list(), sub_action, True)
|
|
619
|
+
self.select_signal.emit()
|
|
519
620
|
|
|
520
621
|
def get_current_action_at(self, job, action_index):
|
|
521
622
|
action_counter = -1
|
|
@@ -537,21 +638,3 @@ class ProjectEditor(QMainWindow):
|
|
|
537
638
|
break
|
|
538
639
|
|
|
539
640
|
return current_action, is_sub_action
|
|
540
|
-
|
|
541
|
-
def update_delete_action_state(self):
|
|
542
|
-
has_job_selected = len(self.job_list.selectedItems()) > 0
|
|
543
|
-
has_action_selected = len(self.action_list.selectedItems()) > 0
|
|
544
|
-
self.delete_element_action.setEnabled(has_job_selected or has_action_selected)
|
|
545
|
-
if has_action_selected and has_job_selected:
|
|
546
|
-
job_index = self.job_list.currentRow()
|
|
547
|
-
if job_index >= len(self.project.jobs):
|
|
548
|
-
job_index = len(self.project.jobs) - 1
|
|
549
|
-
action_index = self.action_list.currentRow()
|
|
550
|
-
if job_index >= 0:
|
|
551
|
-
job = self.project.jobs[job_index]
|
|
552
|
-
current_action, is_sub_action = self.get_current_action_at(job, action_index)
|
|
553
|
-
enable_sub_actions = current_action is not None and \
|
|
554
|
-
not is_sub_action and current_action.type_name == constants.ACTION_COMBO
|
|
555
|
-
self.set_enabled_sub_actions_gui(enable_sub_actions)
|
|
556
|
-
else:
|
|
557
|
-
self.set_enabled_sub_actions_gui(False)
|