shinestacker 1.4.0__py3-none-any.whl → 1.5.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.

@@ -1,4 +1,4 @@
1
- # pylint: disable=C0114, C0115, C0116, E0611, R0902, R0914, R0915, R0904
1
+ # pylint: disable=C0114, C0115, C0116, E0611, R0902, R0914, R0915, R0904, W0108
2
2
  from functools import partial
3
3
  import numpy as np
4
4
  from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QFrame, QLabel, QMenu,
@@ -8,6 +8,7 @@ from PySide6.QtCore import Qt
8
8
  from PySide6.QtGui import QGuiApplication
9
9
  from .. config.constants import constants
10
10
  from .. config.gui_constants import gui_constants
11
+ from .. gui.recent_file_manager import RecentFileManager
11
12
  from .image_viewer import ImageViewer
12
13
  from .shortcuts_help import ShortcutsHelp
13
14
  from .brush import Brush
@@ -22,7 +23,7 @@ from .denoise_filter import DenoiseFilter
22
23
  from .unsharp_mask_filter import UnsharpMaskFilter
23
24
  from .white_balance_filter import WhiteBalanceFilter
24
25
  from .vignetting_filter import VignettingFilter
25
- from .. gui.recent_file_manager import RecentFileManager
26
+ from .transformation_manager import TransfromationManager
26
27
 
27
28
 
28
29
  class ImageEditorUI(QMainWindow, LayerCollectionHandler):
@@ -31,23 +32,23 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
31
32
  LayerCollectionHandler.__init__(self, LayerCollection())
32
33
  self._recent_file_manager = RecentFileManager("shinestacker-recent-images-files.txt")
33
34
  self.thumbnail_highlight = gui_constants.THUMB_MASTER_HI_COLOR
34
- self.undo_manager = UndoManager()
35
- self.undo_action = None
36
- self.redo_action = None
37
- self.undo_manager.stack_changed.connect(self.update_undo_redo_actions)
38
35
  self.io_gui_handler = None
39
36
  self.display_manager = None
40
37
  self.brush = Brush()
41
38
  self.brush_tool = BrushTool()
42
39
  self.modified = False
43
40
  self.mask_layer = None
41
+ self.transformation_manager = TransfromationManager(self)
42
+ self.undo_manager = UndoManager(self.transformation_manager)
43
+ self.undo_action = None
44
+ self.redo_action = None
45
+ self.undo_manager.stack_changed.connect(self.update_undo_redo_actions)
44
46
  self.filter_manager = FilterManager(self)
45
47
  self.filter_manager.register_filter("Denoise", DenoiseFilter)
46
48
  self.filter_manager.register_filter("Unsharp Mask", UnsharpMaskFilter)
47
49
  self.filter_manager.register_filter("White Balance", WhiteBalanceFilter)
48
50
  self.filter_manager.register_filter("Vignetting Correction", VignettingFilter)
49
51
  self.shortcuts_help_dialog = None
50
-
51
52
  self.update_title()
52
53
  self.resize(1400, 900)
53
54
  center = QGuiApplication.primaryScreen().geometry().center()
@@ -66,18 +67,15 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
66
67
  side_layout = QVBoxLayout(side_panel)
67
68
  side_layout.setContentsMargins(0, 0, 0, 0)
68
69
  side_layout.setSpacing(2)
69
-
70
70
  brush_panel = QFrame()
71
71
  brush_panel.setFrameShape(QFrame.StyledPanel)
72
72
  brush_panel.setContentsMargins(0, 0, 0, 0)
73
73
  brush_layout = QVBoxLayout(brush_panel)
74
74
  brush_layout.setContentsMargins(0, 0, 0, 0)
75
75
  brush_layout.setSpacing(2)
76
-
77
76
  brush_label = QLabel("Brush Size")
78
77
  brush_label.setAlignment(Qt.AlignCenter)
79
78
  brush_layout.addWidget(brush_label)
80
-
81
79
  self.brush_size_slider = QSlider(Qt.Horizontal)
82
80
  self.brush_size_slider.setRange(0, gui_constants.BRUSH_SIZE_SLIDER_MAX)
83
81
 
@@ -92,7 +90,6 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
92
90
 
93
91
  self.brush_size_slider.setValue(brush_size_to_slider(self.brush.size))
94
92
  brush_layout.addWidget(self.brush_size_slider)
95
-
96
93
  hardness_label = QLabel("Brush Hardness")
97
94
  hardness_label.setAlignment(Qt.AlignCenter)
98
95
  brush_layout.addWidget(hardness_label)
@@ -100,7 +97,6 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
100
97
  self.hardness_slider.setRange(0, 100)
101
98
  self.hardness_slider.setValue(self.brush.hardness)
102
99
  brush_layout.addWidget(self.hardness_slider)
103
-
104
100
  opacity_label = QLabel("Brush Opacity")
105
101
  opacity_label.setAlignment(Qt.AlignCenter)
106
102
  brush_layout.addWidget(opacity_label)
@@ -108,7 +104,6 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
108
104
  self.opacity_slider.setRange(0, 100)
109
105
  self.opacity_slider.setValue(self.brush.opacity)
110
106
  brush_layout.addWidget(self.opacity_slider)
111
-
112
107
  flow_label = QLabel("Brush Flow")
113
108
  flow_label.setAlignment(Qt.AlignCenter)
114
109
  brush_layout.addWidget(flow_label)
@@ -116,7 +111,6 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
116
111
  self.flow_slider.setRange(1, 100)
117
112
  self.flow_slider.setValue(self.brush.flow)
118
113
  brush_layout.addWidget(self.flow_slider)
119
-
120
114
  side_layout.addWidget(brush_panel)
121
115
  self.brush_preview_widget = QLabel()
122
116
  self.brush_preview_widget.setContentsMargins(0, 0, 0, 0)
@@ -133,7 +127,6 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
133
127
  self.brush_preview_widget.setFixedHeight(100)
134
128
  brush_layout.addWidget(self.brush_preview_widget)
135
129
  side_layout.addWidget(brush_panel)
136
-
137
130
  master_label = QLabel("Master")
138
131
  master_label.setStyleSheet("""
139
132
  QLabel {
@@ -238,8 +231,6 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
238
231
  self.master_thumbnail_label, self.thumbnail_list, parent=self)
239
232
  self.io_gui_handler = IOGuiHandler(self.layer_collection, self.undo_manager, parent=self)
240
233
  self.display_manager.status_message_requested.connect(self.show_status_message)
241
- self.display_manager.cursor_preview_state_changed.connect(
242
- self.image_viewer.set_allow_cursor_preview)
243
234
  self.io_gui_handler.status_message_requested.connect(self.show_status_message)
244
235
  self.io_gui_handler.update_title_requested.connect(self.update_title)
245
236
  self.io_gui_handler.mark_as_modified_requested.connect(self.mark_as_modified)
@@ -277,8 +268,8 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
277
268
 
278
269
  file_menu.addAction("&Close", self.close_file, "Ctrl+W")
279
270
  file_menu.addSeparator()
280
- file_menu.addAction("&Import frames", self.io_gui_handler.import_frames)
281
- file_menu.addAction("Import &EXIF data", self.io_gui_handler.select_exif_path)
271
+ file_menu.addAction("&Import Frames", self.io_gui_handler.import_frames)
272
+ file_menu.addAction("Import &EXIF Data", self.io_gui_handler.select_exif_path)
282
273
 
283
274
  edit_menu = menubar.addMenu("&Edit")
284
275
  self.undo_action = QAction("Undo", self)
@@ -293,7 +284,21 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
293
284
  edit_menu.addAction(self.redo_action)
294
285
  edit_menu.addSeparator()
295
286
 
296
- copy_action = QAction("Copy Layer to Master", self)
287
+ transf_menu = QMenu("&Transform")
288
+ rotate_90_cw_action = QAction(gui_constants.ROTATE_90_CW_LABEL, self)
289
+ transf_menu.addAction(rotate_90_cw_action)
290
+ rotate_90_cw_action.triggered.connect(lambda: self.transformation_manager.rotate_90_cw())
291
+ rotate_90_ccw_action = QAction(gui_constants.ROTATE_90_CCW_LABEL, self)
292
+ transf_menu.addAction(rotate_90_ccw_action)
293
+ rotate_90_ccw_action.triggered.connect(lambda: self.transformation_manager.rotate_90_ccw())
294
+ rotate_180_action = QAction(gui_constants.ROTATE_180_LABEL, self)
295
+ rotate_180_action.triggered.connect(lambda: self.transformation_manager.rotate_180())
296
+ transf_menu.addAction(rotate_180_action)
297
+ edit_menu.addMenu(transf_menu)
298
+
299
+ edit_menu.addSeparator()
300
+
301
+ copy_action = QAction("Copy Current Layer to Master", self)
297
302
  copy_action.setShortcut("Ctrl+M")
298
303
  copy_action.triggered.connect(self.copy_layer_to_master)
299
304
  edit_menu.addAction(copy_action)
@@ -310,59 +315,58 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
310
315
 
311
316
  view_strategy_menu = QMenu("View &Mode", view_menu)
312
317
 
313
- self.view_action_modes = {
318
+ self.view_mode_actions = {
314
319
  'overlaid': QAction("Overlaid", self),
315
- 'sidebyside': QAction("Side By Side", self),
320
+ 'sidebyside': QAction("Side by Side", self),
316
321
  'topbottom': QAction("Top-Bottom", self)
317
322
  }
318
- overlaid_mode = self.view_action_modes['overlaid']
323
+ overlaid_mode = self.view_mode_actions['overlaid']
319
324
  overlaid_mode.setShortcut("Ctrl+1")
320
325
  overlaid_mode.setCheckable(True)
321
- overlaid_mode.triggered.connect(lambda: set_strategy('overlaid'))
326
+ overlaid_mode.triggered.connect(lambda: self.set_strategy('overlaid'))
322
327
  view_strategy_menu.addAction(overlaid_mode)
323
- side_by_side_mode = self.view_action_modes['sidebyside']
328
+ side_by_side_mode = self.view_mode_actions['sidebyside']
324
329
  side_by_side_mode.setShortcut("Ctrl+2")
325
330
  side_by_side_mode.setCheckable(True)
326
- side_by_side_mode.triggered.connect(lambda: set_strategy('sidebyside'))
331
+ side_by_side_mode.triggered.connect(lambda: self.set_strategy('sidebyside'))
327
332
  view_strategy_menu.addAction(side_by_side_mode)
328
- side_by_side_mode = self.view_action_modes['topbottom']
333
+ side_by_side_mode = self.view_mode_actions['topbottom']
329
334
  side_by_side_mode.setShortcut("Ctrl+3")
330
335
  side_by_side_mode.setCheckable(True)
331
- side_by_side_mode.triggered.connect(lambda: set_strategy('topbottom'))
336
+ side_by_side_mode.triggered.connect(lambda: self.set_strategy('topbottom'))
332
337
  view_strategy_menu.addAction(side_by_side_mode)
333
338
  view_menu.addMenu(view_strategy_menu)
334
339
 
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
340
  cursor_menu = view_menu.addMenu("Cursor Style")
346
341
 
347
- cursor_stype = self.image_viewer.get_cursor_style()
348
- brush_action = QAction("Simple Brush", self)
342
+ self.cursor_style_actions = {
343
+ 'brush': QAction("Simple Brush", self),
344
+ 'preview': QAction("Brush Preview", self),
345
+ 'outline': QAction("Outline Only", self)
346
+ }
347
+ brush_action = self.cursor_style_actions['brush']
349
348
  brush_action.setCheckable(True)
350
- brush_action.setChecked(cursor_stype == 'brush')
351
- brush_action.triggered.connect(lambda: self.image_viewer.set_cursor_style('brush'))
349
+ brush_action.triggered.connect(lambda: set_cursor_style('brush'))
352
350
  cursor_menu.addAction(brush_action)
353
351
 
354
- preview_action = QAction("Brush Preview", self)
352
+ preview_action = self.cursor_style_actions['preview']
355
353
  preview_action.setCheckable(True)
356
- preview_action.setChecked(cursor_stype == 'preview')
357
- preview_action.triggered.connect(lambda: self.image_viewer.set_cursor_style('preview'))
354
+ preview_action.triggered.connect(lambda: set_cursor_style('preview'))
358
355
  cursor_menu.addAction(preview_action)
359
356
 
360
- outline_action = QAction("Outline Only", self)
357
+ outline_action = self.cursor_style_actions['outline']
361
358
  outline_action.setCheckable(True)
362
- outline_action.setChecked(cursor_stype == 'outline')
363
- outline_action.triggered.connect(lambda: self.image_viewer.set_cursor_style('outline'))
359
+ outline_action.triggered.connect(lambda: set_cursor_style('outline'))
364
360
  cursor_menu.addAction(outline_action)
365
361
 
362
+ def set_cursor_style(cursor_style):
363
+ self.image_viewer.set_cursor_style(cursor_style)
364
+ for label, style in self.cursor_style_actions.items():
365
+ style.setEnabled(label != cursor_style)
366
+ style.setChecked(label == cursor_style)
367
+
368
+ set_cursor_style(self.image_viewer.get_cursor_style())
369
+
366
370
  cursor_group = QActionGroup(self)
367
371
  cursor_group.addAction(preview_action)
368
372
  cursor_group.addAction(outline_action)
@@ -409,7 +413,7 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
409
413
  view_menu.addAction(self.toggle_view_master_individual_action)
410
414
  view_menu.addSeparator()
411
415
 
412
- set_strategy('overlaid')
416
+ self.set_strategy('overlaid')
413
417
 
414
418
  sort_asc_action = QAction("Sort Layers A-Z", self)
415
419
  sort_asc_action.triggered.connect(lambda: self.sort_layers('asc'))
@@ -432,13 +436,15 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
432
436
  white_balance_action = QAction("White Balance", self)
433
437
  white_balance_action.triggered.connect(self.white_balance)
434
438
  filter_menu.addAction(white_balance_action)
435
- vignetting_action = QAction("Vignetting correction", self)
439
+ vignetting_action = QAction("Vignetting Correction", self)
436
440
  vignetting_action.triggered.connect(self.vignetting_correction)
437
441
  filter_menu.addAction(vignetting_action)
438
442
 
439
443
  help_menu = menubar.addMenu("&Help")
440
444
  help_menu.setObjectName("Help")
441
- shortcuts_help_action = QAction("Shortcuts and mouse", self)
445
+ shortcuts_help_action = QAction("Shortcuts and Mouse", self)
446
+
447
+ self.statusBar().showMessage("Shine Stacker ready.", 2000)
442
448
 
443
449
  def shortcuts_help():
444
450
  self.shortcuts_help_dialog = ShortcutsHelp(self)
@@ -453,6 +459,16 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
453
459
  next_layer.activated.connect(self.next_layer)
454
460
  self.installEventFilter(self)
455
461
 
462
+ def set_strategy(self, strategy):
463
+ self.image_viewer.set_strategy(strategy)
464
+ enable_shortcuts = strategy == 'overlaid'
465
+ self.view_master_action.setEnabled(enable_shortcuts)
466
+ self.view_individual_action.setEnabled(enable_shortcuts)
467
+ self.toggle_view_master_individual_action.setEnabled(enable_shortcuts)
468
+ for label, mode in self.view_mode_actions.items():
469
+ mode.setEnabled(label != strategy)
470
+ mode.setChecked(label == strategy)
471
+
456
472
  def update_title(self):
457
473
  title = constants.APP_TITLE
458
474
  if self.io_gui_handler is not None:
@@ -693,13 +709,11 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
693
709
 
694
710
  def set_view_master(self):
695
711
  self.display_manager.set_view_master()
696
- self.display_manager.refresh_master_view()
697
712
  self.thumbnail_highlight = gui_constants.THUMB_MASTER_HI_COLOR
698
713
  self.highlight_master_thumbnail()
699
714
 
700
715
  def set_view_individual(self):
701
716
  self.display_manager.set_view_individual()
702
- self.display_manager.refresh_current_view()
703
717
  self.thumbnail_highlight = gui_constants.THUMB_MASTER_LO_COLOR
704
718
  self.highlight_master_thumbnail()
705
719
 
@@ -59,3 +59,7 @@ class ImageViewStatus(QObject):
59
59
 
60
60
  def set_max_scale(self, min_scale):
61
61
  self.max_scale = min_scale
62
+
63
+ def set_scroll(self, h_scroll, v_scroll):
64
+ self.h_scroll = h_scroll
65
+ self.v_scroll = v_scroll
@@ -35,8 +35,14 @@ class ImageViewer(QWidget):
35
35
  self.strategy.show()
36
36
  self.strategy.resize(self.size())
37
37
  if not self.strategy.empty():
38
+ self.strategy.cleanup_brush_preview()
38
39
  self.strategy.update_master_display()
39
40
  self.strategy.update_current_display()
41
+ self.strategy.setup_brush_cursor()
42
+ self.strategy.update_brush_cursor()
43
+ self.strategy.show_master()
44
+ self.strategy.setFocus()
45
+ self.strategy.activateWindow()
40
46
 
41
47
  def empty(self):
42
48
  return self.strategy.empty()
@@ -81,9 +87,6 @@ class ImageViewer(QWidget):
81
87
  def set_allow_cursor_preview(self, state):
82
88
  self.strategy.set_allow_cursor_preview(state)
83
89
 
84
- def setup_brush_cursor(self):
85
- self.strategy.setup_brush_cursor()
86
-
87
90
  def zoom_in(self):
88
91
  self.strategy.zoom_in()
89
92
 
@@ -103,7 +106,8 @@ class ImageViewer(QWidget):
103
106
  return self.strategy.get_cursor_style()
104
107
 
105
108
  def set_cursor_style(self, style):
106
- self.strategy.set_cursor_style(style)
109
+ for st in self._strategies.values():
110
+ st.set_cursor_style(style)
107
111
 
108
112
  def position_on_image(self, pos):
109
113
  return self.strategy.position_on_image(pos)
@@ -56,8 +56,6 @@ class IOGuiHandler(QObject, LayerCollectionHandler):
56
56
  self.set_layer_labels(labels)
57
57
  self.set_master_layer(master_layer)
58
58
  self.image_viewer.set_master_image_np(master_layer)
59
- self.image_viewer.show_master()
60
- self.image_viewer.update_master_display()
61
59
  self.undo_manager.reset()
62
60
  self.blank_layer = np.zeros(master_layer.shape[:2])
63
61
  self.finish_loading_setup(f"Loaded: {self.current_file_path()}")
@@ -165,7 +163,6 @@ class IOGuiHandler(QObject, LayerCollectionHandler):
165
163
  self.display_manager.update_thumbnails()
166
164
  self.mark_as_modified_requested.emit(True)
167
165
  self.change_layer_requested.emit(0)
168
- self.image_viewer.setup_brush_cursor()
169
166
  self.status_message_requested.emit(message)
170
167
  self.update_title_requested.emit()
171
168
  self.add_recent_file_requested.emit(self.current_file_path_master)
@@ -143,6 +143,9 @@ class LayerCollectionHandler:
143
143
  def has_master_layer(self):
144
144
  return self.layer_collection.has_master_layer()
145
145
 
146
+ def set_layer(self, idx, img):
147
+ self.layer_collection.layer_stack[idx] = img
148
+
146
149
  def set_layer_stack(self, stk):
147
150
  self.layer_collection.set_layer_stack(stk)
148
151
 
@@ -1,5 +1,4 @@
1
1
  # pylint: disable=C0114, C0115, C0116, E0611, E1101, R0904, R0912, R0914, R0902
2
- from PySide6.QtGui import QPixmap
3
2
  from PySide6.QtCore import Qt, QPointF, QEvent, QRectF
4
3
  from .. config.gui_constants import gui_constants
5
4
  from .view_strategy import ViewStrategy, ImageGraphicsViewBase, ViewSignals
@@ -23,12 +22,21 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
23
22
  def get_master_view(self):
24
23
  return self
25
24
 
25
+ def get_current_view(self):
26
+ return self
27
+
26
28
  def get_master_scene(self):
27
29
  return self.scene
28
30
 
31
+ def get_current_scene(self):
32
+ return self.scene
33
+
29
34
  def get_master_pixmap(self):
30
35
  return self.pixmap_item_master
31
36
 
37
+ def get_current_pixmap(self):
38
+ return self.pixmap_item_current
39
+
32
40
  def get_views(self):
33
41
  return [self]
34
42
 
@@ -41,66 +49,6 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
41
49
  self.pixmap_item_current: self
42
50
  }
43
51
 
44
- def set_master_image(self, qimage):
45
- self.status.set_master_image(qimage)
46
- pixmap = self.status.pixmap_master
47
- self.setSceneRect(QRectF(pixmap.rect()))
48
-
49
- img_width, img_height = pixmap.width(), pixmap.height()
50
- self.set_min_scale(min(gui_constants.MIN_ZOOMED_IMG_WIDTH / img_width,
51
- gui_constants.MIN_ZOOMED_IMG_HEIGHT / img_height))
52
- self.set_max_scale(gui_constants.MAX_ZOOMED_IMG_PX_SIZE)
53
- self.set_zoom_factor(1.0)
54
- self.fitInView(self.pixmap_item_master, Qt.KeepAspectRatio)
55
- self.set_zoom_factor(self.get_current_scale())
56
- self.set_zoom_factor(max(self.min_scale(), min(self.max_scale(), self.zoom_factor())))
57
- self.scale(self.zoom_factor(), self.zoom_factor())
58
-
59
- def set_current_image(self, qimage):
60
- self.status.set_current_image(qimage)
61
- if self.empty():
62
- self.setSceneRect(QRectF(self.status.pixmap_current.rect()))
63
-
64
- def show_master(self):
65
- self.pixmap_item_master.setVisible(True)
66
- self.pixmap_item_current.setVisible(False)
67
-
68
- def show_current(self):
69
- self.pixmap_item_master.setVisible(False)
70
- self.pixmap_item_current.setVisible(True)
71
-
72
- def update_master_display(self):
73
- if not self.empty():
74
- master_qimage = self.numpy_to_qimage(
75
- self.master_layer())
76
- if master_qimage:
77
- self.pixmap_item_master.setPixmap(QPixmap.fromImage(master_qimage))
78
-
79
- def update_current_display(self):
80
- if not self.empty() and self.number_of_layers() > 0:
81
- current_qimage = self.numpy_to_qimage(
82
- self.current_layer())
83
- if current_qimage:
84
- self.pixmap_item_current.setPixmap(QPixmap.fromImage(current_qimage))
85
-
86
- def set_view_state(self, state):
87
- self.status.set_state(state)
88
- if state:
89
- self.resetTransform()
90
- self.scale(state['zoom'], state['zoom'])
91
- self.horizontalScrollBar().setValue(state['h_scroll'])
92
- self.verticalScrollBar().setValue(state['v_scroll'])
93
- self.set_zoom_factor(state['zoom'])
94
-
95
- def handle_key_press_event(self, event):
96
- if event.key() == Qt.Key_X:
97
- self.temp_view_requested.emit(True)
98
- self.update_brush_cursor()
99
-
100
- def handle_key_release_event(self, event):
101
- if event.key() == Qt.Key_X:
102
- self.temp_view_requested.emit(False)
103
-
104
52
  # pylint: disable=C0103
105
53
  def mousePressEvent(self, event):
106
54
  self.mouse_press_event(event)
@@ -113,6 +61,7 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
113
61
  self.mouse_release_event(event)
114
62
  super().mouseReleaseEvent(event)
115
63
 
64
+ # pylint: enable=R0801
116
65
  def wheelEvent(self, event):
117
66
  if self.empty() or self.gesture_active:
118
67
  return
@@ -120,8 +69,8 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
120
69
  if self.control_pressed:
121
70
  self.brush_size_change_requested.emit(1 if event.angleDelta().y() > 0 else -1)
122
71
  else:
123
- zoom_in_factor = 1.10
124
- zoom_out_factor = 1 / zoom_in_factor
72
+ zoom_in_factor = gui_constants.ZOOM_IN_FACTOR
73
+ zoom_out_factor = gui_constants.ZOOM_OUT_FACTOR
125
74
  current_scale = self.get_current_scale()
126
75
  if event.angleDelta().y() > 0: # Zoom in
127
76
  new_scale = current_scale * zoom_in_factor
@@ -146,11 +95,14 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
146
95
  else:
147
96
  self.zoom_out()
148
97
  event.accept()
98
+ # pylint: disable=R0801
149
99
 
150
100
  def enterEvent(self, event):
151
101
  self.activateWindow()
152
102
  self.setFocus()
153
- if not self.empty():
103
+ if self.empty():
104
+ self.setCursor(Qt.ArrowCursor)
105
+ else:
154
106
  self.setCursor(Qt.BlankCursor)
155
107
  if self.brush_cursor:
156
108
  self.brush_cursor.show()
@@ -162,6 +114,89 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
162
114
  return self.handle_gesture_event(event)
163
115
  return super().event(event)
164
116
 
117
+ def setup_scene_image(self, pixmap, pixmap_item):
118
+ self.setSceneRect(QRectF(pixmap.rect()))
119
+ img_width, img_height = pixmap.width(), pixmap.height()
120
+ self.set_max_min_scales(img_width, img_height)
121
+ view_rect = self.viewport().rect()
122
+ scale_x = view_rect.width() / img_width
123
+ scale_y = view_rect.height() / img_height
124
+ scale_factor = min(scale_x, scale_y)
125
+ scale_factor = max(self.min_scale(), min(scale_factor, self.max_scale()))
126
+ self.set_zoom_factor(scale_factor)
127
+ self.resetTransform()
128
+ self.scale(scale_factor, scale_factor)
129
+ self.centerOn(pixmap_item)
130
+ self.center_image(self)
131
+ self.update_cursor_pen_width()
132
+
133
+ def set_master_image(self, qimage):
134
+ self.status.set_master_image(qimage)
135
+ self.setup_scene_image(self.status.pixmap_master, self.pixmap_item_master)
136
+ self.update_master_display()
137
+
138
+ def set_current_image(self, qimage):
139
+ self.status.set_current_image(qimage)
140
+ if self.empty():
141
+ self.setup_scene_image(self.status.pixmap_current, self.pixmap_item_current)
142
+
143
+ def setup_brush_cursor(self):
144
+ super().setup_brush_cursor()
145
+ self.update_cursor_pen_width()
146
+
147
+ def show_master(self):
148
+ self.pixmap_item_master.setVisible(True)
149
+ self.pixmap_item_current.setVisible(False)
150
+ self.brush_preview.show()
151
+ if self.brush_cursor:
152
+ self.scene.removeItem(self.brush_cursor)
153
+ self.brush_cursor = self.create_circle(self.scene)
154
+ self.update_brush_cursor()
155
+
156
+ def show_current(self):
157
+ self.pixmap_item_master.setVisible(False)
158
+ self.pixmap_item_current.setVisible(True)
159
+ self.brush_preview.hide()
160
+ if self.brush_cursor:
161
+ self.scene.removeItem(self.brush_cursor)
162
+ self.brush_cursor = self.create_alt_circle(self.scene)
163
+ self.update_brush_cursor()
164
+
165
+ def arrange_images(self):
166
+ if self.empty():
167
+ return
168
+ if self.pixmap_item_master.isVisible():
169
+ pixmap = self.pixmap_item_master.pixmap()
170
+ if not pixmap.isNull():
171
+ self.setSceneRect(QRectF(pixmap.rect()))
172
+ self.centerOn(self.pixmap_item_master)
173
+ self.center_image(self)
174
+ elif self.pixmap_item_current.isVisible():
175
+ pixmap = self.pixmap_item_current.pixmap()
176
+ if not pixmap.isNull():
177
+ self.setSceneRect(QRectF(pixmap.rect()))
178
+ self.centerOn(self.pixmap_item_current)
179
+ self.center_image(self)
180
+ current_scale = self.get_current_scale()
181
+ scale_factor = self.zoom_factor() / current_scale
182
+ self.scale(scale_factor, scale_factor)
183
+
184
+ def handle_key_press_event(self, event):
185
+ if event.key() in [Qt.Key_Up, Qt.Key_Down]:
186
+ return False
187
+ if event.key() == Qt.Key_X:
188
+ self.temp_view_requested.emit(True)
189
+ return False
190
+ return True
191
+
192
+ def handle_key_release_event(self, event):
193
+ if event.key() in [Qt.Key_Up, Qt.Key_Down]:
194
+ return False
195
+ if event.key() == Qt.Key_X:
196
+ self.temp_view_requested.emit(False)
197
+ return False
198
+ return True
199
+
165
200
  def handle_gesture_event(self, event):
166
201
  if self.empty():
167
202
  return False
@@ -190,23 +225,3 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
190
225
  self.scroll_view(self, int(scaled_delta.x()), int(scaled_delta.y()))
191
226
  elif pan_gesture.state() == Qt.GestureFinished:
192
227
  self.gesture_active = False
193
-
194
- def handle_pinch_gesture(self, pinch):
195
- if pinch.state() == Qt.GestureStarted:
196
- self.pinch_start_scale = self.get_current_scale()
197
- self.pinch_center_view = pinch.centerPoint()
198
- self.pinch_center_scene = self.mapToScene(self.pinch_center_view.toPoint())
199
- self.gesture_active = True
200
- elif pinch.state() == Qt.GestureUpdated:
201
- new_scale = self.pinch_start_scale * pinch.totalScaleFactor()
202
- new_scale = max(self.min_scale(), min(new_scale, self.max_scale()))
203
- if abs(new_scale - self.get_current_scale()) > 0.01:
204
- self.resetTransform()
205
- self.scale(new_scale, new_scale)
206
- self.set_zoom_factor(new_scale)
207
- new_center = self.mapToScene(self.pinch_center_view.toPoint())
208
- delta = self.pinch_center_scene - new_center
209
- self.translate(delta.x(), delta.y())
210
- self.update_brush_cursor()
211
- elif pinch.state() in (Qt.GestureFinished, Qt.GestureCanceled):
212
- self.gesture_active = False