diff --git a/app.py b/app.py index c5301f3..2ffd81e 100644 --- a/app.py +++ b/app.py @@ -1,6 +1,8 @@ import sys, os, pathlib -from PyQt6.QtCore import Qt, QSize, QDir, QSize -from PyQt6.QtGui import QFileSystemModel, QPixmap, QMovie, QIcon, QAction +from PyQt6.QtCore import Qt, QSize, QDir, QSize, QUrl +from PyQt6.QtGui import QFileSystemModel, QPixmap, QMovie, QIcon, QAction, QImage +from PyQt6.QtMultimedia import QMediaPlayer +from PyQt6.QtMultimediaWidgets import QVideoWidget from PyQt6.QtWidgets import ( QApplication, QMainWindow, @@ -16,17 +18,42 @@ QListWidget, QDockWidget, QToolBar, - QGridLayout + QGridLayout, + QScrollArea, + QSplitter ) class MainWindow(QMainWindow): def __init__(self): + self.filetype_switcher = { + ".png": self.display_static, + ".jpg": self.display_static, + ".ico": self.display_static, + ".svg": self.display_static, + ".tif": self.display_static, + ".jpeg": self.display_static, + ".tiff": self.display_static, + ".gif": self.display_animated, + ".webp": self.display_animated, + ".mp4": self.display_video, + ".mkv": self.display_video, + ".avi": self.display_video, + ".mov": self.display_video, + ".wmv": self.display_video, + ".flv": self.display_video, + ".mpg": self.display_video, + ".m4v": self.display_video, + ".3gp": self.display_video, + ".webm": self.display_video, + ".mpeg": self.display_video, + } + # region Setup super().__init__() self.setWindowTitle("Media Magic") - self.resize(QSize(500, 300)) + self.resize(QSize(800, 500)) # endregion # region Menu Bar @@ -49,6 +76,7 @@ def __init__(self): self.action_addFolder = self.menu_view.addAction("Add Folder \tCtrl+Shift+A") self.action_addFolder.setStatusTip("Add a Parent Directory to this View") self.action_addFolder.triggered.connect(self.add_folder) + self.action_addFolder.setShortcut("Ctrl+Shift+A") self.menu_help = self.menu_bar.addMenu("Help") self.action_about = self.menu_help.addAction("About Media Magic") @@ -95,28 +123,33 @@ def __init__(self): # region Browser View self.browser_detailview = QListWidget() - self.browser_thumbnails = QGridLayout() - self.browser_detailview.itemSelectionChanged.connect(self.show_media) + # self.browser_thumbnails = QGridLayout() + self.browser_detailview.itemSelectionChanged.connect(self.display_media) browser = QWidget() - browserToggles = QToolBar() - detailview = QAction(QIcon("icons/details.png"),"", self, checkable=True, checked=True) - thumbnails = QAction(QIcon("icons/thumbs.png"),"", self, checkable=True) - detailview.toggled.connect(lambda checked: self.toggle_view(detailview, thumbnails, checked, False)) - thumbnails.toggled.connect(lambda checked: self.toggle_view(thumbnails, detailview, checked, True)) - browserToggles.addAction(detailview) - browserToggles.addAction(thumbnails) - browserToggles.widgetForAction(detailview).setFixedSize(21,21) - browserToggles.widgetForAction(thumbnails).setFixedSize(21,21) - browserToggles.setContentsMargins(0, 0, 0, 0) - browserToggles.setLayoutDirection(Qt.LayoutDirection.RightToLeft) + # browserToggles = QToolBar() + # detailview = QAction(QIcon("icons/details.png"),"", self, checkable=True, checked=True) + # thumbnails = QAction(QIcon("icons/thumbs.png"),"", self, checkable=True) + # detailview.toggled.connect(lambda checked: self.toggle_view(detailview, thumbnails, checked, False)) + # thumbnails.toggled.connect(lambda checked: self.toggle_view(thumbnails, detailview, checked, True)) + # browserToggles.addAction(detailview) + # browserToggles.addAction(thumbnails) + # browserToggles.widgetForAction(detailview).setFixedSize(21,21) + # browserToggles.widgetForAction(thumbnails).setFixedSize(21,21) + # browserToggles.setContentsMargins(0, 0, 0, 0) + # browserToggles.setLayoutDirection(Qt.LayoutDirection.RightToLeft) browserLayout = QVBoxLayout() browser.setLayout(browserLayout) - grid = QWidget() - grid.setLayout(self.browser_thumbnails) + # grid = QWidget() + # grid.setLayout(self.browser_thumbnails) + # scroll_area = QScrollArea(self) + # scroll_area.setWidgetResizable(True) + # scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) + # scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + # scroll_area.setWidget(grid) browserLayout.addWidget(self.browser_detailview) - browserLayout.addWidget(grid) + # browserLayout.addWidget(scroll_area) # browserLayout.addLayout(self.browser_thumbnails) - browserLayout.addWidget(browserToggles) + # browserLayout.addWidget(browserToggles) browserLayout.setContentsMargins(0, 0, 0, 0) browserLayout.setSpacing(0) self.browserView = QWidget() @@ -126,15 +159,21 @@ def __init__(self): # endregion # region Media View - self.media = QLabel() + self.image = QLabel() + self.video = QVideoWidget() + self.video.hide() mediaLayout = QVBoxLayout() - mediaLayout.addWidget(self.media) - mediaLayout.addWidget(QLabel("Tags and Values")) + mediaLayout.addWidget(self.image) + mediaLayout.addWidget(self.video) + mediaLayout.addWidget(QLabel("Tags and Values", alignment=Qt.AlignmentFlag.AlignCenter)) mediaLayout.setContentsMargins(0, 0, 0, 0) - mediaView = QWidget() - mediaView.setLayout(mediaLayout) + media_view = QWidget() + media_view.setLayout(mediaLayout) self.dock_media = QDockWidget("Media") - self.dock_media.setWidget(mediaView) + self.dock_media.setWidget(media_view) + self.media_player = QMediaPlayer() + self.media_player.setVideoOutput(self.video) + self.resizeEvent = self.update_size # endregion # region Docking @@ -142,6 +181,12 @@ def __init__(self): self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.dock_folders) self.splitDockWidget(self.dock_folders, self.dock_browser, Qt.Orientation.Horizontal) self.splitDockWidget(self.dock_browser, self.dock_media, Qt.Orientation.Horizontal) + self.dock_folders.setMinimumWidth(150) + self.dock_browser.setMinimumWidth(300) + # self.dock_media.setMinimumWidth(200) + for x in self.findChildren(QSplitter): + x.splitterMoved.connect(self.update_size) + self.image_src = QImage() # endregion # region Setup @@ -150,27 +195,23 @@ def __init__(self): self.show() # endregion - def toggle_view(self, button, other, checked, thumb): - if checked: - button.setChecked(True) - other.setChecked(False) - else: - button.setChecked(False) - other.setChecked(True) - if thumb: - self.browser_thumbnails.setEnabled(True) - self.browser_detailview.setEnabled(False) - # self.browser_detailview.hide() - # for i in range(self.browser_thumbnails.count()): - # widget = self.browser_thumbnails.itemAt(i).widget() - # widget.show() - else: - self.browser_thumbnails.setEnabled(False) - self.browser_detailview.setEnabled(True) - # self.browser_detailview.show() - # for i in range(self.browser_thumbnails.count()): - # widget = self.browser_thumbnails.itemAt(i).widget() - # widget.hide() + # def toggle_view(self, button, other, checked, thumb): + # if checked: + # button.setChecked(True) + # other.setChecked(False) + # else: + # button.setChecked(False) + # other.setChecked(True) + # if thumb: + # self.browser_detailview.hide() + # for i in range(self.browser_thumbnails.count()): + # widget = self.browser_thumbnails.itemAt(i).widget() + # widget.show() + # else: + # self.browser_detailview.show() + # for i in range(self.browser_thumbnails.count()): + # widget = self.browser_thumbnails.itemAt(i).widget() + # widget.hide() def add_folder(self): @@ -183,26 +224,53 @@ def add_folder(self): os.symlink(path, target, target_is_directory=True) files = [os.path.join(root, f) for root, dir, file in os.walk(path) for f in file] self.browser_detailview.addItems(files) - for i, file in enumerate(files): - widget = QWidget() - layout = QVBoxLayout() - thumbnail = QLabel() - thumbnail.setPixmap(QPixmap(file).scaledToWidth(200)) - layout.addWidget(thumbnail) - layout.addWidget(QLabel(os.path.basename(file))) - widget.setLayout(layout) - self.browser_thumbnails.addWidget(widget, i // 4, i % 4) + # for i, file in enumerate(files): + # widget = QWidget() + # layout = QVBoxLayout() + # thumbnail = QLabel() + # thumbnail.setPixmap(QPixmap(file).scaledToWidth(200)) + # layout.addWidget(thumbnail) + # layout.addWidget(QLabel(os.path.basename(file))) + # widget.setLayout(layout) + # self.browser_thumbnails.addWidget(widget, i // 4, i % 4) self.status.showMessage(f"Added - {path}") - def show_media(self): + def display_media(self): file_path = self.browser_detailview.currentItem().text() - if file_path.endswith(".gif") or file_path.endswith(".webp"): - movie = QMovie(file_path) - self.media.setMovie(movie) - movie.start() + _, extension = os.path.splitext(file_path) + if extension in self.filetype_switcher: + self.filetype_switcher[extension](file_path) else: - pixmap = QPixmap(file_path) - self.media.setPixmap(pixmap.scaled(800, 600, Qt.AspectRatioMode.KeepAspectRatio)) + self.status.showMessage(f"Unsupported file type - {extension}") + + def display_static(self, file_path): + self.media_player.stop() + self.image.show() + self.video.hide() + # use qimage to display a pixmap scaled to the width of the dock + self.image_src = QImage(file_path) + self.image.setPixmap(QPixmap.fromImage(self.image_src.scaled(self.dock_media.size(),Qt.AspectRatioMode.KeepAspectRatio))) + + # pixmap = QPixmap(file_path) + # self.image.setPixmap(pixmap.scaled(self.dock_media.width(), 500, Qt.AspectRatioMode.KeepAspectRatio)) + + def display_animated(self, file_path): + self.media_player.stop() + self.image.show() + self.video.hide() + movie = QMovie(file_path) + self.image.setMovie(movie) + movie.start() + self.image.setPixmap(self.image.pixmap().scaled(self.dock_media.width(), 500, Qt.AspectRatioMode.KeepAspectRatio)) + + def display_video(self, file_path): + self.image.hide() + self.video.show() + self.media_player.setSource(QUrl.fromLocalFile(file_path)) + self.media_player.play() + + def update_size(self, event=None): + self.image.setPixmap(QPixmap.fromImage(self.image_src.scaled(self.dock_media.size(),Qt.AspectRatioMode.KeepAspectRatio))) def search(self): self.status.showMessage(f"Searching - {self.search_bar.text()}") diff --git a/raw/grid.py b/raw/grid.py new file mode 100644 index 0000000..9e64daa --- /dev/null +++ b/raw/grid.py @@ -0,0 +1,74 @@ +import sys +from PyQt6.QtWidgets import QWidget, QGridLayout, QScrollArea, QLabel, QSizePolicy, QMainWindow, QHBoxLayout, QSpacerItem +from PyQt6.QtGui import QPixmap +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QApplication + +class ImageGridWidget(QWidget): + def __init__(self): + super().__init__() + self.grid_container = QWidget(self) + self.grid = QGridLayout(self.grid_container) + self.grid.setAlignment(Qt.AlignmentFlag.AlignTop) + self.grid.setHorizontalSpacing(10) + self.grid.setVerticalSpacing(10) + self.scroll_area = QScrollArea(self) + self.scroll_area.setWidgetResizable(True) + self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) + self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.scroll_area.setWidget(self.grid_container) + + # Create layout to hold scroll area and spacer item to keep scroll bar on the right + self.main_layout = QHBoxLayout(self) + self.main_layout.addWidget(self.scroll_area) + + self.setLayout(self.main_layout) + self.images = [] + + def add_image(self, filepath): + label = QLabel(self) + label.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) + label.setAlignment(Qt.AlignmentFlag.AlignCenter) + pixmap = QPixmap(filepath) + scaled_pixmap = pixmap.scaledToWidth(200, Qt.TransformationMode.SmoothTransformation) + label.setPixmap(scaled_pixmap) + self.grid.addWidget(label, len(self.images) // self.columnCount, len(self.images) % self.columnCount) + self.images.append(label) + + def clear_images(self): + for image in self.images: + self.grid.removeWidget(image) + image.deleteLater() + self.images = [] + + def set_column_count(self, count): + self.columnCount = count + + def refresh_view(self): + self.grid.update() + self.updateGeometry() + + def set_thumbnail_height(self, height): + self.thumbnail_height = height + for image in self.images: + pixmap = image.pixmap() + scaled_pixmap = pixmap.scaledToHeight(height, Qt.TransformationMode.SmoothTransformation) + image.setPixmap(scaled_pixmap) + + def zoom_in(self): + self.set_thumbnail_height(self.thumbnail_height * 1.2) + + def zoom_out(self): + self.set_thumbnail_height(self.thumbnail_height / 1.2) + + +# Example driver code: +if __name__ == '__main__': + app = QApplication(sys.argv) + widget = ImageGridWidget() + widget.set_column_count(2) + widget.set_thumbnail_height(200) + for i in range(5): + widget.add_image(r'C:\Users\Rafay\OneDrive\Pictures\test.jpg') + widget.show() + sys.exit(app.exec()) diff --git a/raw/paths.csv b/raw/paths.csv new file mode 100644 index 0000000..706615c --- /dev/null +++ b/raw/paths.csv @@ -0,0 +1,3 @@ +paths +self.image = QPixmap(r'C:\Users\Rafay\OneDrive\data\sample.png') +self.animated_image = QMovie(r'C:\Users\Rafay\OneDrive\data\sample2.webp') \ No newline at end of file diff --git a/raw/scale.py b/raw/scale.py new file mode 100644 index 0000000..cde62a5 --- /dev/null +++ b/raw/scale.py @@ -0,0 +1,54 @@ +import sys +from PyQt6.QtCore import Qt +from PyQt6.QtGui import QPixmap, QMovie, QResizeEvent +from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + + # Set window properties + self.setWindowTitle("Image and Animated Image Example") + self.setMinimumSize(400, 400) + + # Create labels to display images + self.image_label = QLabel(self) + self.animated_image_label = QLabel(self) + + # Load images + self.image = QPixmap(r'C:\Users\Rafay\OneDrive\data\sample.png') + self.animated_image = QMovie(r'C:\Users\Rafay\OneDrive\data\sample2.webp') + + # Set initial image sizes + self.update_image_sizes() + + # Set image alignments + self.image_label.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter) + self.animated_image_label.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter) + + # Add labels to the window + self.setCentralWidget(self.image_label) + self.statusBar().addPermanentWidget(self.animated_image_label) + + # Connect to the window's resize event to update the image sizes + self.resizeEvent = self.update_image_sizes + + # Start the animated image + self.animated_image.start() + + def update_image_sizes(self, event=None): + # Update image sizes when the window is resized + window_width = self.width() + image_width = min(window_width, self.image.width()) + if self.image.width() > 0: + image_height = int(image_width * self.image.height() / self.image.width()) + else: + image_height = 0 + self.image_label.setPixmap(self.image.scaled(image_width, image_height, Qt.AspectRatioMode.KeepAspectRatio)) + self.animated_image_label.setFixedHeight(int(self.height() / 10)) + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = MainWindow() + window.show() + sys.exit(app.exec()) diff --git a/raw/viewer.py b/raw/viewer.py new file mode 100644 index 0000000..352e5ac --- /dev/null +++ b/raw/viewer.py @@ -0,0 +1,71 @@ +import sys, os +from PyQt6.QtCore import * +from PyQt6.QtGui import * +from PyQt6.QtWidgets import * +from PyQt6.QtMultimedia import * +from PyQt6.QtMultimediaWidgets import * + + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + + # Set up the window + self.setWindowTitle("Media Viewer") + self.setMinimumSize(800, 600) + + # Create the widgets + self.folder_button = QPushButton("Open Folder") + self.list_view = QListWidget() + self.image_label = QLabel() + self.video_player = QMediaPlayer() + self.video_widget = QVideoWidget() + self.viewer_widget = QStackedWidget() + + # Create the docks + self.list_dock = QDockWidget("Media List") + self.viewer_dock = QDockWidget("Media Viewer") + self.list_dock.setWidget(self.list_view) + self.viewer_dock.setWidget(self.viewer_widget) + self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.list_dock) + self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.viewer_dock) + + # Set up the layout + central_widget = QWidget() + self.setCentralWidget(central_widget) + layout = QVBoxLayout() + central_widget.setLayout(layout) + layout.addWidget(self.folder_button) + layout.addWidget(self.image_label) + layout.addWidget(self.video_widget) + + # Connect the signals and slots + self.folder_button.clicked.connect(self.open_folder) + self.list_view.itemSelectionChanged.connect(self.update_viewer) + + def open_folder(self): + path = QFileDialog.getExistingDirectory(self, "Open Folder", QDir.homePath()) + files = [os.path.join(root, f) for root, dir, file in os.walk(path) for f in file] + self.list_view.addItems(files) + + + def update_viewer(self): + if selected.indexes(): + file_path = selected.indexes()[0].data() + if file_path.endswith((".jpg", ".png", ".bmp")): + self.viewer_widget.setCurrentWidget(self.image_label) + pixmap = QPixmap(file_path) + pixmap = pixmap.scaled(self.image_label.width(), self.image_label.height(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) + self.image_label.setPixmap(pixmap) + elif file_path.endswith((".mp4", ".avi", ".mkv")): + self.viewer_widget.setCurrentWidget(self.video_widget) + self.video_player.setSource(QUrl.fromLocalFile(file_path)) + self.video_player.setVideoOutput(self.video_widget) + self.video_player.play() + + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = MainWindow() + window.show() + sys.exit(app.exec())