creatumlibre.ui.manager.tab_manager
1# pylint: disable=no-member 2from pathlib import Path 3 4from PyQt6.QtCore import Qt 5from PyQt6.QtWidgets import ( 6 QLabel, 7 QScrollArea, 8 QSizePolicy, 9 QTabWidget, 10 QVBoxLayout, 11 QWidget, 12) 13 14from creatumlibre.ui.manager.object_manager import ObjectManager 15 16 17class TabManager: 18 """Manages loading new image to object list (positon[0]), tab creation, and scrolling.""" 19 20 def __init__(self, parent): 21 self.parent = parent 22 self.tab_widget = QTabWidget() 23 self.object_manager_instances = {} # Track objectManagers by tab index 24 25 self._init_layout() 26 27 def _init_layout(self): 28 self.tab_widget.setTabsClosable(True) 29 self.tab_widget.tabCloseRequested.connect(self.tab_widget.removeTab) 30 # self.tab_widget.installEventFilter(self.parent.input_handler) 31 self.tab_widget.setMovable(True) 32 self.tab_widget.setFocusPolicy(Qt.FocusPolicy.StrongFocus) 33 self.tab_widget.setFocus() 34 self.tab_widget.setSizePolicy( 35 QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding 36 ) 37 self.parent.workspace_layout.addWidget(self.tab_widget) 38 39 def _add_scroll_container(self, filename): 40 """Add a scroll container around the objects""" 41 scroll_area_widget = QScrollArea() 42 scroll_area_widget.setWidgetResizable(True) 43 scroll_area_widget.setHorizontalScrollBarPolicy( 44 Qt.ScrollBarPolicy.ScrollBarAlwaysOn 45 ) 46 scroll_area_widget.setVerticalScrollBarPolicy( 47 Qt.ScrollBarPolicy.ScrollBarAlwaysOn 48 ) 49 # Fixed image/object-manger container inside the scroll area 50 object_manager_container_widget = QWidget() 51 object_manager_container_layout = QVBoxLayout(object_manager_container_widget) 52 object_manager_container_layout.setContentsMargins(0, 0, 0, 0) 53 54 object_manager_label_widget = QLabel() 55 object_manager_label_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) 56 57 object_manager_container_layout.addWidget(object_manager_label_widget) 58 object_manager_container_widget.setLayout(object_manager_container_layout) 59 60 # Place fixed widget inside the scrollable area 61 scroll_area_widget.setWidget(object_manager_container_widget) 62 tab_index = self.tab_widget.addTab(scroll_area_widget, filename) 63 return tab_index, object_manager_label_widget 64 65 def load_new_image(self, file_path): 66 """Load a new image with scroll support inside a fixed widget.""" 67 object_manager_instance = ObjectManager(file_path) 68 filename = Path(file_path).name 69 70 tab_index, object_manager_label_widget = self._add_scroll_container(filename) 71 self.object_manager_instances[tab_index] = { 72 "manager": object_manager_instance, 73 "widget": object_manager_label_widget, # Store label reference per tab 74 "file_apth": file_path, # saved for saving 75 } 76 77 self.refresh_tab_display(tab_index) 78 self.tab_widget.setCurrentIndex(tab_index) 79 80 def refresh_tab_display(self, tab_index): 81 """Redraws the image for a specific tab by requesting a refreshed pixmap.""" 82 if tab_index not in self.object_manager_instances: 83 return 84 85 obj_ref = self.object_manager_instances[tab_index] 86 87 tab_pixmap = obj_ref[ 88 "manager" 89 ].get_tab_pixmap() # Get final image with all objects/layers 90 self._refresh_widget(widget=obj_ref["widget"], pixmap=tab_pixmap) 91 92 def refresh_active_tab_display(self): 93 """Convinience methot to update the tab""" 94 active_tab = self.get_active_tab_index() 95 self.refresh_tab_display(active_tab) 96 97 def _refresh_widget(self, widget: QWidget, pixmap): 98 """update widget""" 99 widget.setPixmap(pixmap) 100 widget.repaint() 101 102 def get_active_tab(self): 103 """Retrieves the current ObjectManager instance safely.""" 104 if (current_index := self.tab_widget.currentIndex()) == -1: 105 return None 106 107 return self.object_manager_instances.get(current_index, None) 108 109 def get_active_tab_index(self): 110 return self.tab_widget.currentIndex() 111 112 def zoom_in(self): 113 """Increase the zoom level of the active image.""" 114 self.apply_zoom(1.2) 115 116 def zoom_out(self): 117 """Decrease the zoom level of the active image.""" 118 self.apply_zoom(0.8) 119 120 def apply_zoom(self, factor: float): 121 """Zoom in or out while maintaining aspect ratio.""" 122 if (active_tab := self.get_active_tab()) is None: 123 return 124 active_tab["manager"].zoom_factor = max( 125 0.1, min(3.0, active_tab["manager"].zoom_factor * factor) 126 ) # Prevent extreme zoom 127 self._refresh_widget( 128 active_tab["widget"], active_tab["manager"].get_tab_pixmap() 129 ) 130 131 def fit_to_container(self): 132 """Resize the image while preserving aspect ratio.""" 133 print("Fitting image to container with aspect ratio") 134 135 if (active_tab := self.get_active_tab()) is None: 136 return 137 138 container_width = self.tab_widget.width() 139 container_height = self.tab_widget.height() 140 141 image_width, image_height = ( 142 active_tab["manager"].get_base_image().shape[1], 143 active_tab["manager"].get_base_image().shape[0], 144 ) 145 146 # Calculate the best zoom factor 147 scale_x = container_width / image_width 148 scale_y = container_height / image_height 149 active_tab["manager"].zoom_factor = max( 150 scale_x, scale_y 151 ) # Ensures aspect ratio is preserved 152 153 print( 154 f" Calculated zoom factor: {active_tab["manager"].zoom_factor}, {scale_x=}, {scale_y=}" 155 ) 156 # Resize the image 157 self.apply_zoom( 158 active_tab["manager"].zoom_factor 159 ) # Use zoom logic to resize properly 160 161 def reset_zoom(self): 162 """Reset zoom level for active image.""" 163 if (active_tab := self.get_active_tab()) is None: 164 return 165 166 active_tab["manager"].zoom_factor = 1.0 167 self._refresh_widget( 168 active_tab["widget"], active_tab["manager"].get_tab_pixmap() 169 )
class
TabManager:
18class TabManager: 19 """Manages loading new image to object list (positon[0]), tab creation, and scrolling.""" 20 21 def __init__(self, parent): 22 self.parent = parent 23 self.tab_widget = QTabWidget() 24 self.object_manager_instances = {} # Track objectManagers by tab index 25 26 self._init_layout() 27 28 def _init_layout(self): 29 self.tab_widget.setTabsClosable(True) 30 self.tab_widget.tabCloseRequested.connect(self.tab_widget.removeTab) 31 # self.tab_widget.installEventFilter(self.parent.input_handler) 32 self.tab_widget.setMovable(True) 33 self.tab_widget.setFocusPolicy(Qt.FocusPolicy.StrongFocus) 34 self.tab_widget.setFocus() 35 self.tab_widget.setSizePolicy( 36 QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding 37 ) 38 self.parent.workspace_layout.addWidget(self.tab_widget) 39 40 def _add_scroll_container(self, filename): 41 """Add a scroll container around the objects""" 42 scroll_area_widget = QScrollArea() 43 scroll_area_widget.setWidgetResizable(True) 44 scroll_area_widget.setHorizontalScrollBarPolicy( 45 Qt.ScrollBarPolicy.ScrollBarAlwaysOn 46 ) 47 scroll_area_widget.setVerticalScrollBarPolicy( 48 Qt.ScrollBarPolicy.ScrollBarAlwaysOn 49 ) 50 # Fixed image/object-manger container inside the scroll area 51 object_manager_container_widget = QWidget() 52 object_manager_container_layout = QVBoxLayout(object_manager_container_widget) 53 object_manager_container_layout.setContentsMargins(0, 0, 0, 0) 54 55 object_manager_label_widget = QLabel() 56 object_manager_label_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) 57 58 object_manager_container_layout.addWidget(object_manager_label_widget) 59 object_manager_container_widget.setLayout(object_manager_container_layout) 60 61 # Place fixed widget inside the scrollable area 62 scroll_area_widget.setWidget(object_manager_container_widget) 63 tab_index = self.tab_widget.addTab(scroll_area_widget, filename) 64 return tab_index, object_manager_label_widget 65 66 def load_new_image(self, file_path): 67 """Load a new image with scroll support inside a fixed widget.""" 68 object_manager_instance = ObjectManager(file_path) 69 filename = Path(file_path).name 70 71 tab_index, object_manager_label_widget = self._add_scroll_container(filename) 72 self.object_manager_instances[tab_index] = { 73 "manager": object_manager_instance, 74 "widget": object_manager_label_widget, # Store label reference per tab 75 "file_apth": file_path, # saved for saving 76 } 77 78 self.refresh_tab_display(tab_index) 79 self.tab_widget.setCurrentIndex(tab_index) 80 81 def refresh_tab_display(self, tab_index): 82 """Redraws the image for a specific tab by requesting a refreshed pixmap.""" 83 if tab_index not in self.object_manager_instances: 84 return 85 86 obj_ref = self.object_manager_instances[tab_index] 87 88 tab_pixmap = obj_ref[ 89 "manager" 90 ].get_tab_pixmap() # Get final image with all objects/layers 91 self._refresh_widget(widget=obj_ref["widget"], pixmap=tab_pixmap) 92 93 def refresh_active_tab_display(self): 94 """Convinience methot to update the tab""" 95 active_tab = self.get_active_tab_index() 96 self.refresh_tab_display(active_tab) 97 98 def _refresh_widget(self, widget: QWidget, pixmap): 99 """update widget""" 100 widget.setPixmap(pixmap) 101 widget.repaint() 102 103 def get_active_tab(self): 104 """Retrieves the current ObjectManager instance safely.""" 105 if (current_index := self.tab_widget.currentIndex()) == -1: 106 return None 107 108 return self.object_manager_instances.get(current_index, None) 109 110 def get_active_tab_index(self): 111 return self.tab_widget.currentIndex() 112 113 def zoom_in(self): 114 """Increase the zoom level of the active image.""" 115 self.apply_zoom(1.2) 116 117 def zoom_out(self): 118 """Decrease the zoom level of the active image.""" 119 self.apply_zoom(0.8) 120 121 def apply_zoom(self, factor: float): 122 """Zoom in or out while maintaining aspect ratio.""" 123 if (active_tab := self.get_active_tab()) is None: 124 return 125 active_tab["manager"].zoom_factor = max( 126 0.1, min(3.0, active_tab["manager"].zoom_factor * factor) 127 ) # Prevent extreme zoom 128 self._refresh_widget( 129 active_tab["widget"], active_tab["manager"].get_tab_pixmap() 130 ) 131 132 def fit_to_container(self): 133 """Resize the image while preserving aspect ratio.""" 134 print("Fitting image to container with aspect ratio") 135 136 if (active_tab := self.get_active_tab()) is None: 137 return 138 139 container_width = self.tab_widget.width() 140 container_height = self.tab_widget.height() 141 142 image_width, image_height = ( 143 active_tab["manager"].get_base_image().shape[1], 144 active_tab["manager"].get_base_image().shape[0], 145 ) 146 147 # Calculate the best zoom factor 148 scale_x = container_width / image_width 149 scale_y = container_height / image_height 150 active_tab["manager"].zoom_factor = max( 151 scale_x, scale_y 152 ) # Ensures aspect ratio is preserved 153 154 print( 155 f" Calculated zoom factor: {active_tab["manager"].zoom_factor}, {scale_x=}, {scale_y=}" 156 ) 157 # Resize the image 158 self.apply_zoom( 159 active_tab["manager"].zoom_factor 160 ) # Use zoom logic to resize properly 161 162 def reset_zoom(self): 163 """Reset zoom level for active image.""" 164 if (active_tab := self.get_active_tab()) is None: 165 return 166 167 active_tab["manager"].zoom_factor = 1.0 168 self._refresh_widget( 169 active_tab["widget"], active_tab["manager"].get_tab_pixmap() 170 )
Manages loading new image to object list (positon[0]), tab creation, and scrolling.
def
load_new_image(self, file_path):
66 def load_new_image(self, file_path): 67 """Load a new image with scroll support inside a fixed widget.""" 68 object_manager_instance = ObjectManager(file_path) 69 filename = Path(file_path).name 70 71 tab_index, object_manager_label_widget = self._add_scroll_container(filename) 72 self.object_manager_instances[tab_index] = { 73 "manager": object_manager_instance, 74 "widget": object_manager_label_widget, # Store label reference per tab 75 "file_apth": file_path, # saved for saving 76 } 77 78 self.refresh_tab_display(tab_index) 79 self.tab_widget.setCurrentIndex(tab_index)
Load a new image with scroll support inside a fixed widget.
def
refresh_tab_display(self, tab_index):
81 def refresh_tab_display(self, tab_index): 82 """Redraws the image for a specific tab by requesting a refreshed pixmap.""" 83 if tab_index not in self.object_manager_instances: 84 return 85 86 obj_ref = self.object_manager_instances[tab_index] 87 88 tab_pixmap = obj_ref[ 89 "manager" 90 ].get_tab_pixmap() # Get final image with all objects/layers 91 self._refresh_widget(widget=obj_ref["widget"], pixmap=tab_pixmap)
Redraws the image for a specific tab by requesting a refreshed pixmap.
def
refresh_active_tab_display(self):
93 def refresh_active_tab_display(self): 94 """Convinience methot to update the tab""" 95 active_tab = self.get_active_tab_index() 96 self.refresh_tab_display(active_tab)
Convinience methot to update the tab
def
get_active_tab(self):
103 def get_active_tab(self): 104 """Retrieves the current ObjectManager instance safely.""" 105 if (current_index := self.tab_widget.currentIndex()) == -1: 106 return None 107 108 return self.object_manager_instances.get(current_index, None)
Retrieves the current ObjectManager instance safely.
def
zoom_in(self):
113 def zoom_in(self): 114 """Increase the zoom level of the active image.""" 115 self.apply_zoom(1.2)
Increase the zoom level of the active image.
def
zoom_out(self):
117 def zoom_out(self): 118 """Decrease the zoom level of the active image.""" 119 self.apply_zoom(0.8)
Decrease the zoom level of the active image.
def
apply_zoom(self, factor: float):
121 def apply_zoom(self, factor: float): 122 """Zoom in or out while maintaining aspect ratio.""" 123 if (active_tab := self.get_active_tab()) is None: 124 return 125 active_tab["manager"].zoom_factor = max( 126 0.1, min(3.0, active_tab["manager"].zoom_factor * factor) 127 ) # Prevent extreme zoom 128 self._refresh_widget( 129 active_tab["widget"], active_tab["manager"].get_tab_pixmap() 130 )
Zoom in or out while maintaining aspect ratio.
def
fit_to_container(self):
132 def fit_to_container(self): 133 """Resize the image while preserving aspect ratio.""" 134 print("Fitting image to container with aspect ratio") 135 136 if (active_tab := self.get_active_tab()) is None: 137 return 138 139 container_width = self.tab_widget.width() 140 container_height = self.tab_widget.height() 141 142 image_width, image_height = ( 143 active_tab["manager"].get_base_image().shape[1], 144 active_tab["manager"].get_base_image().shape[0], 145 ) 146 147 # Calculate the best zoom factor 148 scale_x = container_width / image_width 149 scale_y = container_height / image_height 150 active_tab["manager"].zoom_factor = max( 151 scale_x, scale_y 152 ) # Ensures aspect ratio is preserved 153 154 print( 155 f" Calculated zoom factor: {active_tab["manager"].zoom_factor}, {scale_x=}, {scale_y=}" 156 ) 157 # Resize the image 158 self.apply_zoom( 159 active_tab["manager"].zoom_factor 160 ) # Use zoom logic to resize properly
Resize the image while preserving aspect ratio.
def
reset_zoom(self):
162 def reset_zoom(self): 163 """Reset zoom level for active image.""" 164 if (active_tab := self.get_active_tab()) is None: 165 return 166 167 active_tab["manager"].zoom_factor = 1.0 168 self._refresh_widget( 169 active_tab["widget"], active_tab["manager"].get_tab_pixmap() 170 )
Reset zoom level for active image.