shinestacker 1.3.1__py3-none-any.whl → 1.4.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 +198 -18
- shinestacker/algorithms/align_parallel.py +17 -1
- shinestacker/algorithms/balance.py +23 -13
- shinestacker/algorithms/noise_detection.py +3 -1
- shinestacker/algorithms/utils.py +21 -10
- shinestacker/algorithms/vignetting.py +2 -0
- shinestacker/config/gui_constants.py +2 -2
- shinestacker/core/core_utils.py +10 -1
- shinestacker/gui/action_config.py +172 -7
- shinestacker/gui/action_config_dialog.py +246 -285
- shinestacker/gui/gui_run.py +2 -2
- shinestacker/gui/main_window.py +14 -5
- shinestacker/gui/menu_manager.py +26 -2
- shinestacker/gui/project_controller.py +4 -0
- shinestacker/gui/recent_file_manager.py +93 -0
- shinestacker/retouch/base_filter.py +5 -5
- shinestacker/retouch/brush_preview.py +3 -0
- shinestacker/retouch/brush_tool.py +11 -11
- shinestacker/retouch/display_manager.py +21 -37
- shinestacker/retouch/image_editor_ui.py +129 -71
- shinestacker/retouch/image_view_status.py +61 -0
- shinestacker/retouch/image_viewer.py +89 -431
- shinestacker/retouch/io_gui_handler.py +12 -2
- shinestacker/retouch/overlaid_view.py +212 -0
- shinestacker/retouch/shortcuts_help.py +13 -3
- shinestacker/retouch/sidebyside_view.py +479 -0
- shinestacker/retouch/view_strategy.py +466 -0
- {shinestacker-1.3.1.dist-info → shinestacker-1.4.0.dist-info}/METADATA +1 -1
- {shinestacker-1.3.1.dist-info → shinestacker-1.4.0.dist-info}/RECORD +34 -29
- {shinestacker-1.3.1.dist-info → shinestacker-1.4.0.dist-info}/WHEEL +0 -0
- {shinestacker-1.3.1.dist-info → shinestacker-1.4.0.dist-info}/entry_points.txt +0 -0
- {shinestacker-1.3.1.dist-info → shinestacker-1.4.0.dist-info}/licenses/LICENSE +0 -0
- {shinestacker-1.3.1.dist-info → shinestacker-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# pylint: disable=C0114, C0115, C0116, E0611, R0902, R0914, R0915, R0904
|
|
2
|
+
from functools import partial
|
|
2
3
|
import numpy as np
|
|
3
|
-
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QFrame, QLabel,
|
|
4
|
+
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QFrame, QLabel, QMenu,
|
|
4
5
|
QListWidget, QSlider, QMainWindow, QMessageBox)
|
|
5
6
|
from PySide6.QtGui import QShortcut, QKeySequence, QAction, QActionGroup
|
|
6
7
|
from PySide6.QtCore import Qt
|
|
@@ -21,12 +22,14 @@ from .denoise_filter import DenoiseFilter
|
|
|
21
22
|
from .unsharp_mask_filter import UnsharpMaskFilter
|
|
22
23
|
from .white_balance_filter import WhiteBalanceFilter
|
|
23
24
|
from .vignetting_filter import VignettingFilter
|
|
25
|
+
from .. gui.recent_file_manager import RecentFileManager
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
27
29
|
def __init__(self):
|
|
28
30
|
QMainWindow.__init__(self)
|
|
29
31
|
LayerCollectionHandler.__init__(self, LayerCollection())
|
|
32
|
+
self._recent_file_manager = RecentFileManager("shinestacker-recent-images-files.txt")
|
|
30
33
|
self.thumbnail_highlight = gui_constants.THUMB_MASTER_HI_COLOR
|
|
31
34
|
self.undo_manager = UndoManager()
|
|
32
35
|
self.undo_action = None
|
|
@@ -53,12 +56,12 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
53
56
|
self.setCentralWidget(central_widget)
|
|
54
57
|
layout = QHBoxLayout(central_widget)
|
|
55
58
|
self.image_viewer = ImageViewer(self.layer_collection)
|
|
56
|
-
self.image_viewer.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
self.image_viewer.connect_signals(
|
|
60
|
+
self.handle_temp_view,
|
|
61
|
+
self.begin_copy_brush_area,
|
|
62
|
+
self.continue_copy_brush_area,
|
|
63
|
+
self.end_copy_brush_area,
|
|
64
|
+
self.handle_brush_size_change)
|
|
62
65
|
side_panel = QWidget()
|
|
63
66
|
side_layout = QVBoxLayout(side_panel)
|
|
64
67
|
side_layout.setContentsMargins(0, 0, 0, 0)
|
|
@@ -115,9 +118,9 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
115
118
|
brush_layout.addWidget(self.flow_slider)
|
|
116
119
|
|
|
117
120
|
side_layout.addWidget(brush_panel)
|
|
118
|
-
self.
|
|
119
|
-
self.
|
|
120
|
-
self.
|
|
121
|
+
self.brush_preview_widget = QLabel()
|
|
122
|
+
self.brush_preview_widget.setContentsMargins(0, 0, 0, 0)
|
|
123
|
+
self.brush_preview_widget.setStyleSheet("""
|
|
121
124
|
QLabel {
|
|
122
125
|
background-color: #f0f0f0;
|
|
123
126
|
border: 1px solid #ccc;
|
|
@@ -126,9 +129,9 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
126
129
|
margin: 0px;
|
|
127
130
|
}
|
|
128
131
|
""")
|
|
129
|
-
self.
|
|
130
|
-
self.
|
|
131
|
-
brush_layout.addWidget(self.
|
|
132
|
+
self.brush_preview_widget.setAlignment(Qt.AlignCenter)
|
|
133
|
+
self.brush_preview_widget.setFixedHeight(100)
|
|
134
|
+
brush_layout.addWidget(self.brush_preview_widget)
|
|
132
135
|
side_layout.addWidget(brush_panel)
|
|
133
136
|
|
|
134
137
|
master_label = QLabel("Master")
|
|
@@ -236,22 +239,27 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
236
239
|
self.io_gui_handler = IOGuiHandler(self.layer_collection, self.undo_manager, parent=self)
|
|
237
240
|
self.display_manager.status_message_requested.connect(self.show_status_message)
|
|
238
241
|
self.display_manager.cursor_preview_state_changed.connect(
|
|
239
|
-
|
|
242
|
+
self.image_viewer.set_allow_cursor_preview)
|
|
240
243
|
self.io_gui_handler.status_message_requested.connect(self.show_status_message)
|
|
241
244
|
self.io_gui_handler.update_title_requested.connect(self.update_title)
|
|
242
245
|
self.io_gui_handler.mark_as_modified_requested.connect(self.mark_as_modified)
|
|
243
246
|
self.io_gui_handler.change_layer_requested.connect(self.change_layer)
|
|
244
|
-
self.
|
|
247
|
+
self.io_gui_handler.add_recent_file_requested.connect(self.add_recent_file)
|
|
248
|
+
self.brush_tool.setup_ui(self.brush, self.brush_preview_widget, self.image_viewer,
|
|
245
249
|
self.brush_size_slider, self.hardness_slider, self.opacity_slider,
|
|
246
250
|
self.flow_slider)
|
|
247
|
-
self.image_viewer.
|
|
251
|
+
self.image_viewer.set_brush(self.brush_tool.brush)
|
|
252
|
+
self.image_viewer.set_preview_brush(self.brush_tool.brush)
|
|
248
253
|
self.brush_tool.update_brush_thumb()
|
|
249
254
|
self.io_gui_handler.setup_ui(self.display_manager, self.image_viewer)
|
|
250
|
-
self.image_viewer.
|
|
255
|
+
self.image_viewer.set_display_manager(self.display_manager)
|
|
251
256
|
|
|
252
257
|
menubar = self.menuBar()
|
|
253
258
|
file_menu = menubar.addMenu("&File")
|
|
254
259
|
file_menu.addAction("&Open...", self.io_gui_handler.open_file, "Ctrl+O")
|
|
260
|
+
self.recent_files_menu = QMenu("Open &Recent", file_menu)
|
|
261
|
+
file_menu.addMenu(self.recent_files_menu)
|
|
262
|
+
self.update_recent_files()
|
|
255
263
|
self.save_action = QAction("&Save", self)
|
|
256
264
|
self.save_action.setShortcut("Ctrl+S")
|
|
257
265
|
self.save_action.triggered.connect(self.io_gui_handler.save_file)
|
|
@@ -300,6 +308,69 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
300
308
|
|
|
301
309
|
view_menu.addSeparator()
|
|
302
310
|
|
|
311
|
+
view_strategy_menu = QMenu("View &Mode", view_menu)
|
|
312
|
+
|
|
313
|
+
self.view_action_modes = {
|
|
314
|
+
'overlaid': QAction("Overlaid", self),
|
|
315
|
+
'sidebyside': QAction("Side By Side", self),
|
|
316
|
+
'topbottom': QAction("Top-Bottom", self)
|
|
317
|
+
}
|
|
318
|
+
overlaid_mode = self.view_action_modes['overlaid']
|
|
319
|
+
overlaid_mode.setShortcut("Ctrl+1")
|
|
320
|
+
overlaid_mode.setCheckable(True)
|
|
321
|
+
overlaid_mode.triggered.connect(lambda: set_strategy('overlaid'))
|
|
322
|
+
view_strategy_menu.addAction(overlaid_mode)
|
|
323
|
+
side_by_side_mode = self.view_action_modes['sidebyside']
|
|
324
|
+
side_by_side_mode.setShortcut("Ctrl+2")
|
|
325
|
+
side_by_side_mode.setCheckable(True)
|
|
326
|
+
side_by_side_mode.triggered.connect(lambda: set_strategy('sidebyside'))
|
|
327
|
+
view_strategy_menu.addAction(side_by_side_mode)
|
|
328
|
+
side_by_side_mode = self.view_action_modes['topbottom']
|
|
329
|
+
side_by_side_mode.setShortcut("Ctrl+3")
|
|
330
|
+
side_by_side_mode.setCheckable(True)
|
|
331
|
+
side_by_side_mode.triggered.connect(lambda: set_strategy('topbottom'))
|
|
332
|
+
view_strategy_menu.addAction(side_by_side_mode)
|
|
333
|
+
view_menu.addMenu(view_strategy_menu)
|
|
334
|
+
|
|
335
|
+
def set_strategy(strategy):
|
|
336
|
+
self.image_viewer.set_strategy(strategy)
|
|
337
|
+
enable_shortcuts = strategy == 'overlaid'
|
|
338
|
+
self.view_master_action.setEnabled(enable_shortcuts)
|
|
339
|
+
self.view_individual_action.setEnabled(enable_shortcuts)
|
|
340
|
+
self.toggle_view_master_individual_action.setEnabled(enable_shortcuts)
|
|
341
|
+
for label, mode in self.view_action_modes.items():
|
|
342
|
+
mode.setEnabled(label != strategy)
|
|
343
|
+
mode.setChecked(label == strategy)
|
|
344
|
+
|
|
345
|
+
cursor_menu = view_menu.addMenu("Cursor Style")
|
|
346
|
+
|
|
347
|
+
cursor_stype = self.image_viewer.get_cursor_style()
|
|
348
|
+
brush_action = QAction("Simple Brush", self)
|
|
349
|
+
brush_action.setCheckable(True)
|
|
350
|
+
brush_action.setChecked(cursor_stype == 'brush')
|
|
351
|
+
brush_action.triggered.connect(lambda: self.image_viewer.set_cursor_style('brush'))
|
|
352
|
+
cursor_menu.addAction(brush_action)
|
|
353
|
+
|
|
354
|
+
preview_action = QAction("Brush Preview", self)
|
|
355
|
+
preview_action.setCheckable(True)
|
|
356
|
+
preview_action.setChecked(cursor_stype == 'preview')
|
|
357
|
+
preview_action.triggered.connect(lambda: self.image_viewer.set_cursor_style('preview'))
|
|
358
|
+
cursor_menu.addAction(preview_action)
|
|
359
|
+
|
|
360
|
+
outline_action = QAction("Outline Only", self)
|
|
361
|
+
outline_action.setCheckable(True)
|
|
362
|
+
outline_action.setChecked(cursor_stype == 'outline')
|
|
363
|
+
outline_action.triggered.connect(lambda: self.image_viewer.set_cursor_style('outline'))
|
|
364
|
+
cursor_menu.addAction(outline_action)
|
|
365
|
+
|
|
366
|
+
cursor_group = QActionGroup(self)
|
|
367
|
+
cursor_group.addAction(preview_action)
|
|
368
|
+
cursor_group.addAction(outline_action)
|
|
369
|
+
cursor_group.addAction(brush_action)
|
|
370
|
+
cursor_group.setExclusive(True)
|
|
371
|
+
|
|
372
|
+
view_menu.addSeparator()
|
|
373
|
+
|
|
303
374
|
zoom_in_action = QAction("Zoom In", self)
|
|
304
375
|
zoom_in_action.setShortcut("Ctrl++")
|
|
305
376
|
zoom_in_action.triggered.connect(self.image_viewer.zoom_in)
|
|
@@ -316,27 +387,30 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
316
387
|
view_menu.addAction(adapt_action)
|
|
317
388
|
|
|
318
389
|
actual_size_action = QAction("Actual Size", self)
|
|
319
|
-
actual_size_action.setShortcut("Ctrl
|
|
390
|
+
actual_size_action.setShortcut("Ctrl+R")
|
|
320
391
|
actual_size_action.triggered.connect(self.image_viewer.actual_size)
|
|
321
392
|
view_menu.addAction(actual_size_action)
|
|
322
393
|
view_menu.addSeparator()
|
|
323
394
|
|
|
324
|
-
view_master_action = QAction("View Master", self)
|
|
325
|
-
view_master_action.setShortcut("M")
|
|
326
|
-
view_master_action.triggered.connect(self.set_view_master)
|
|
327
|
-
view_menu.addAction(view_master_action)
|
|
328
|
-
|
|
329
|
-
view_individual_action = QAction("View Individual", self)
|
|
330
|
-
view_individual_action.setShortcut("L")
|
|
331
|
-
view_individual_action.triggered.connect(self.set_view_individual)
|
|
332
|
-
view_menu.addAction(view_individual_action)
|
|
333
|
-
|
|
334
|
-
toggle_view_master_individual_action = QAction("Toggle Master/Individual", self)
|
|
335
|
-
toggle_view_master_individual_action.setShortcut("T")
|
|
336
|
-
toggle_view_master_individual_action.triggered.connect(
|
|
337
|
-
|
|
395
|
+
self.view_master_action = QAction("View Master", self)
|
|
396
|
+
self.view_master_action.setShortcut("M")
|
|
397
|
+
self.view_master_action.triggered.connect(self.set_view_master)
|
|
398
|
+
view_menu.addAction(self.view_master_action)
|
|
399
|
+
|
|
400
|
+
self.view_individual_action = QAction("View Individual", self)
|
|
401
|
+
self.view_individual_action.setShortcut("L")
|
|
402
|
+
self.view_individual_action.triggered.connect(self.set_view_individual)
|
|
403
|
+
view_menu.addAction(self.view_individual_action)
|
|
404
|
+
|
|
405
|
+
self.toggle_view_master_individual_action = QAction("Toggle Master/Individual", self)
|
|
406
|
+
self.toggle_view_master_individual_action.setShortcut("T")
|
|
407
|
+
self.toggle_view_master_individual_action.triggered.connect(
|
|
408
|
+
self.toggle_view_master_individual)
|
|
409
|
+
view_menu.addAction(self.toggle_view_master_individual_action)
|
|
338
410
|
view_menu.addSeparator()
|
|
339
411
|
|
|
412
|
+
set_strategy('overlaid')
|
|
413
|
+
|
|
340
414
|
sort_asc_action = QAction("Sort Layers A-Z", self)
|
|
341
415
|
sort_asc_action.triggered.connect(lambda: self.sort_layers('asc'))
|
|
342
416
|
view_menu.addAction(sort_asc_action)
|
|
@@ -347,32 +421,6 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
347
421
|
|
|
348
422
|
view_menu.addSeparator()
|
|
349
423
|
|
|
350
|
-
cursor_menu = view_menu.addMenu("Cursor Style")
|
|
351
|
-
|
|
352
|
-
brush_action = QAction("Simple Brush", self)
|
|
353
|
-
brush_action.setCheckable(True)
|
|
354
|
-
brush_action.setChecked(self.image_viewer.cursor_style == 'brush')
|
|
355
|
-
brush_action.triggered.connect(lambda: self.image_viewer.set_cursor_style('brush'))
|
|
356
|
-
cursor_menu.addAction(brush_action)
|
|
357
|
-
|
|
358
|
-
preview_action = QAction("Brush Preview", self)
|
|
359
|
-
preview_action.setCheckable(True)
|
|
360
|
-
preview_action.setChecked(self.image_viewer.cursor_style == 'preview')
|
|
361
|
-
preview_action.triggered.connect(lambda: self.image_viewer.set_cursor_style('preview'))
|
|
362
|
-
cursor_menu.addAction(preview_action)
|
|
363
|
-
|
|
364
|
-
outline_action = QAction("Outline Only", self)
|
|
365
|
-
outline_action.setCheckable(True)
|
|
366
|
-
outline_action.setChecked(self.image_viewer.cursor_style == 'outline')
|
|
367
|
-
outline_action.triggered.connect(lambda: self.image_viewer.set_cursor_style('outline'))
|
|
368
|
-
cursor_menu.addAction(outline_action)
|
|
369
|
-
|
|
370
|
-
cursor_group = QActionGroup(self)
|
|
371
|
-
cursor_group.addAction(preview_action)
|
|
372
|
-
cursor_group.addAction(outline_action)
|
|
373
|
-
cursor_group.addAction(brush_action)
|
|
374
|
-
cursor_group.setExclusive(True)
|
|
375
|
-
|
|
376
424
|
filter_menu = menubar.addMenu("&Filter")
|
|
377
425
|
filter_menu.setObjectName("Filter")
|
|
378
426
|
denoise_action = QAction("Denoise", self)
|
|
@@ -415,6 +463,19 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
415
463
|
title += " *"
|
|
416
464
|
self.window().setWindowTitle(title)
|
|
417
465
|
|
|
466
|
+
def update_recent_files(self):
|
|
467
|
+
self.recent_files_menu.clear()
|
|
468
|
+
recent_files = self._recent_file_manager.get_files_with_display_names()
|
|
469
|
+
for file_path, display_name in recent_files.items():
|
|
470
|
+
action = self.recent_files_menu.addAction(display_name)
|
|
471
|
+
action.setData(file_path)
|
|
472
|
+
action.triggered.connect(partial(self.io_gui_handler.open_file, file_path))
|
|
473
|
+
self.recent_files_menu.setEnabled(len(recent_files) > 0)
|
|
474
|
+
|
|
475
|
+
def add_recent_file(self, file_path):
|
|
476
|
+
self._recent_file_manager.add_file(file_path)
|
|
477
|
+
self.update_recent_files()
|
|
478
|
+
|
|
418
479
|
def show_status_message(self, message):
|
|
419
480
|
self.statusBar().showMessage(message)
|
|
420
481
|
|
|
@@ -440,7 +501,7 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
440
501
|
|
|
441
502
|
# pylint: disable=C0103
|
|
442
503
|
def keyPressEvent(self, event):
|
|
443
|
-
if self.image_viewer.empty:
|
|
504
|
+
if self.image_viewer.empty():
|
|
444
505
|
return
|
|
445
506
|
if event.text() == '[':
|
|
446
507
|
self.brush_tool.decrease_brush_size()
|
|
@@ -467,14 +528,12 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
467
528
|
|
|
468
529
|
def change_layer(self, layer_idx):
|
|
469
530
|
if 0 <= layer_idx < self.number_of_layers():
|
|
470
|
-
view_state = self.image_viewer.get_view_state()
|
|
471
531
|
self.set_current_layer_idx(layer_idx)
|
|
472
|
-
self.display_manager.
|
|
473
|
-
self.image_viewer.set_view_state(view_state)
|
|
532
|
+
self.display_manager.refresh_current_view()
|
|
474
533
|
self.thumbnail_list.setCurrentRow(layer_idx)
|
|
475
534
|
self.thumbnail_list.setFocus()
|
|
476
535
|
self.image_viewer.update_brush_cursor()
|
|
477
|
-
self.image_viewer.setFocus()
|
|
536
|
+
self.image_viewer.strategy.setFocus()
|
|
478
537
|
|
|
479
538
|
def prev_layer(self):
|
|
480
539
|
if self.layer_stack() is not None:
|
|
@@ -503,8 +562,7 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
503
562
|
if reply == QMessageBox.Yes:
|
|
504
563
|
self.set_master_layer(self.current_layer().copy())
|
|
505
564
|
self.master_layer().setflags(write=True)
|
|
506
|
-
self.display_manager.
|
|
507
|
-
self.display_manager.update_thumbnails()
|
|
565
|
+
self.display_manager.refresh_master_view()
|
|
508
566
|
self.mark_as_modified()
|
|
509
567
|
self.statusBar().showMessage(f"Copied layer {self.current_layer_idx() + 1} to master")
|
|
510
568
|
|
|
@@ -540,8 +598,7 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
540
598
|
|
|
541
599
|
def end_copy_brush_area(self):
|
|
542
600
|
if self.display_manager.update_timer.isActive():
|
|
543
|
-
self.display_manager.
|
|
544
|
-
self.display_manager.update_master_thumbnail()
|
|
601
|
+
self.display_manager.refresh_master_view()
|
|
545
602
|
self.undo_manager.save_undo_state(self.master_layer_copy(), 'Brush Stroke')
|
|
546
603
|
self.display_manager.update_timer.stop()
|
|
547
604
|
self.mark_as_modified()
|
|
@@ -629,17 +686,20 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
629
686
|
|
|
630
687
|
def close_file(self):
|
|
631
688
|
if self.check_unsaved_changes():
|
|
689
|
+
self.image_viewer.reset_zoom()
|
|
632
690
|
self.io_gui_handler.close_file()
|
|
633
691
|
self.set_master_layer(None)
|
|
634
692
|
self.mark_as_modified(False)
|
|
635
693
|
|
|
636
694
|
def set_view_master(self):
|
|
637
695
|
self.display_manager.set_view_master()
|
|
696
|
+
self.display_manager.refresh_master_view()
|
|
638
697
|
self.thumbnail_highlight = gui_constants.THUMB_MASTER_HI_COLOR
|
|
639
698
|
self.highlight_master_thumbnail()
|
|
640
699
|
|
|
641
700
|
def set_view_individual(self):
|
|
642
701
|
self.display_manager.set_view_individual()
|
|
702
|
+
self.display_manager.refresh_current_view()
|
|
643
703
|
self.thumbnail_highlight = gui_constants.THUMB_MASTER_LO_COLOR
|
|
644
704
|
self.highlight_master_thumbnail()
|
|
645
705
|
|
|
@@ -663,15 +723,13 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
|
|
|
663
723
|
|
|
664
724
|
def undo(self):
|
|
665
725
|
if self.undo_manager.undo(self.master_layer()):
|
|
666
|
-
self.display_manager.
|
|
667
|
-
self.display_manager.update_master_thumbnail()
|
|
726
|
+
self.display_manager.refresh_master_view()
|
|
668
727
|
self.mark_as_modified()
|
|
669
728
|
self.statusBar().showMessage("Undo applied", 2000)
|
|
670
729
|
|
|
671
730
|
def redo(self):
|
|
672
731
|
if self.undo_manager.redo(self.master_layer()):
|
|
673
|
-
self.display_manager.
|
|
674
|
-
self.display_manager.update_master_thumbnail()
|
|
732
|
+
self.display_manager.refresh_master_view()
|
|
675
733
|
self.mark_as_modified()
|
|
676
734
|
self.statusBar().showMessage("Redo applied", 2000)
|
|
677
735
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116, E0611, R0902
|
|
2
|
+
from PySide6.QtCore import QObject, QRectF
|
|
3
|
+
from PySide6.QtGui import QPixmap
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ImageViewStatus(QObject):
|
|
7
|
+
def __init__(self, parent=None):
|
|
8
|
+
super().__init__(parent)
|
|
9
|
+
self.pixmap_master = QPixmap()
|
|
10
|
+
self.pixmap_current = QPixmap()
|
|
11
|
+
self.zoom_factor = 1.0
|
|
12
|
+
self.min_scale = 0.0
|
|
13
|
+
self.max_scale = 0.0
|
|
14
|
+
self.h_scroll = 0
|
|
15
|
+
self.v_scroll = 0
|
|
16
|
+
self.scene_rect = QRectF()
|
|
17
|
+
|
|
18
|
+
def empty(self):
|
|
19
|
+
return self.pixmap_master.isNull()
|
|
20
|
+
|
|
21
|
+
def set_master_image(self, qimage):
|
|
22
|
+
pixmap = QPixmap.fromImage(qimage)
|
|
23
|
+
self.pixmap_master = pixmap
|
|
24
|
+
if not self.empty():
|
|
25
|
+
self.scene_rect = QRectF(pixmap.rect())
|
|
26
|
+
|
|
27
|
+
def set_current_image(self, qimage):
|
|
28
|
+
pixmap = QPixmap.fromImage(qimage)
|
|
29
|
+
self.pixmap_current = pixmap
|
|
30
|
+
|
|
31
|
+
def clear(self):
|
|
32
|
+
self.pixmap_master = QPixmap()
|
|
33
|
+
self.pixmap_current = QPixmap()
|
|
34
|
+
self.zoom_factor = 1.0
|
|
35
|
+
self.min_scale = 0.0
|
|
36
|
+
self.max_scale = 0.0
|
|
37
|
+
self.h_scroll = 0
|
|
38
|
+
self.v_scroll = 0
|
|
39
|
+
self.scene_rect = QRectF()
|
|
40
|
+
|
|
41
|
+
def get_state(self):
|
|
42
|
+
return {
|
|
43
|
+
'zoom': self.zoom_factor,
|
|
44
|
+
'h_scroll': self.h_scroll,
|
|
45
|
+
'v_scroll': self.v_scroll
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
def set_state(self, state):
|
|
49
|
+
if state:
|
|
50
|
+
self.zoom_factor = state['zoom']
|
|
51
|
+
self.h_scroll = state['h_scroll']
|
|
52
|
+
self.v_scroll = state['v_scroll']
|
|
53
|
+
|
|
54
|
+
def set_zoom_factor(self, zoom_factor):
|
|
55
|
+
self.zoom_factor = zoom_factor
|
|
56
|
+
|
|
57
|
+
def set_min_scale(self, min_scale):
|
|
58
|
+
self.min_scale = min_scale
|
|
59
|
+
|
|
60
|
+
def set_max_scale(self, min_scale):
|
|
61
|
+
self.max_scale = min_scale
|