Source code for cgl.ui.widgets.notes

import os.path
import sys
import logging
from PySide6.QtGui import QIcon, QPixmap, QPainter, QColor, QImage
from PySide6.QtWidgets import (
    QWidget,
    QTextEdit,
    QHBoxLayout,
    QVBoxLayout,
    QLabel,
    QScrollArea,
    QDialog,
    QSizePolicy,
    QGridLayout,
    QApplication,
    QPushButton,
    QMessageBox,
    QFileDialog,
)
from PySide6.QtCore import Qt

from cgl.core.notes import Notes
from cgl.core.path.object import PathObject
from cgl.ui.widgets.button import LJButton
from cgl.apps.alchemy.data.filedialogcontextmanager import FPContextMgr
from pathlib import Path
from cgl.core.config.query import AlchemyConfigManager

CFG = AlchemyConfigManager()


[docs] class TransparentBackgroundWidget(QWidget): def __init__(self, parent=None): super().__init__(parent)
[docs] def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing, True) painter.setBrush(QColor(30, 30, 30, 255)) # RGBA: black with 80% opacity painter.setPen(Qt.NoPen) painter.drawRect(self.rect()) painter.end()
[docs] class NotesDockWidget(QWidget): def __init__(self, parent=None): super().__init__(parent) self.setup_ui() self.fp_context_mgr = FPContextMgr.get_instance() self.setup_connections()
[docs] def setup_ui(self): # layout1 = QVBoxLayout(self) # layout1.setContentsMargins(0, 0, 0, 0) # Set layout margins to zero # layout1.setSpacing(0) # Create a custom widget with a transparent black background # self.transparent_background = TransparentBackgroundWidget(self) # layout1.addWidget(self.transparent_background) self.info = InfoMetaTab() self.notes = NotesTab() layout2 = QVBoxLayout() layout2.setContentsMargins(0, 0, 0, 0) # Set layout margins to zero layout2.addWidget(self.info, 1) layout2.addWidget(self.notes, 3) # Set the dock widget properties self.setLayout(layout2)
[docs] def scroll_notes(self): self.notes.scroll_notes()
[docs] def set_data(self, path: str): self.data = path self.info.tab_page1.update_display(self.data) self.notes.tab_page1.update_display(self.data)
[docs] def show(self): print("showing notes") super().show()
[docs] def setup_connections(self): # Connect the FPContextMgr's current_po_changed signal to the update_notes method self.fp_context_mgr.po_changed.connect(self.update_notes)
[docs] def update_notes(self): self.set_data(self.fp_context_mgr.get_current_po())
# self.show()
[docs] class ThumbWidget(QWidget): """Custom widget for displaying and updating thumbnails.""" def __init__(self, parent=None): """Initialize the widget.""" super().__init__(parent) layout = QHBoxLayout() meta_layout = QVBoxLayout() grid_layout = QGridLayout() cfg = CFG self.item_label = QLabel(self) self.item_label.setText("") self.item_label.setObjectName("notes_file_path") grid_layout.addWidget(self.item_label, 0, 0) meta_layout.addLayout(grid_layout) icon = QIcon(cfg.icon_path("image_gallery.png")) pixmap = QPixmap(icon.pixmap(80, 50)) # Create a QVBoxLayout for the thumblabel and center the image_plane vertically thumb_layout = QVBoxLayout() self.thumblabel = QLabel(self) self.thumblabel.setPixmap(pixmap) self.thumblabel.setFixedSize(120, 120) self.thumblabel.setScaledContents( True ) # to scale image_plane with QLabel's size thumb_layout.addWidget(self.thumblabel) thumb_layout.setAlignment(self.thumblabel, Qt.AlignCenter) layout.addLayout(thumb_layout) layout.addLayout(meta_layout) self.setLayout(layout)
[docs] def select_image(self) -> None: """Open file dialog to select new image_plane.""" image_path, _ = QFileDialog.getOpenFileName( self, "Select Image", "", "Images (*.png *.xpm *.jpg *.jpeg *.bmp *.gif)" ) if image_path: self.set_image(image_path)
[docs] def set_image(self, image_path: str) -> None: """Save the selected image_plane to thumbnail path and update the QLabel.""" po = FPContextMgr.get_instance().get_current_po() thumb_path = po.get_thumb_path() if not os.path.exists(thumb_path): thumb_path = po.get_filetype_thumb_path() Path(thumb_path).parent.mkdir(parents=True, exist_ok=True) image = QPixmap(image_path) image.save(thumb_path) self.thumblabel.setPixmap(image)
[docs] def crop_image( self, image: QImage, target_width: int, target_height: int ) -> QImage: """Crop the image_plane to the target size while maintaining the original aspect ratio."""
# ...
[docs] def update_display(self, po: PathObject) -> None: """Update the QLabel with the new image_plane.""" if po: self.item_label.setText(po.filename) self.item_label.setStyleSheet("color: rgb(255, 255, 255);font: 10pt ;") thumb_path = po.get_thumb_path() if not os.path.exists(thumb_path): thumb_path = po.get_filetype_thumb_path() icon = QIcon(thumb_path) pixmap = QPixmap(icon.pixmap(100, 100)) # Use the crop_image() function # cropped_pixmap = QPixmap.fromImage(self.crop_image(pixmap.toImage(), 100, 100)) # self.thumblabel.setPixmap(cropped_pixmap) self.thumblabel.setPixmap(pixmap)
[docs] class InfoMetaTab(QWidget): def __init__(self, parent=None): super().__init__(parent) # self.tabBar().setObjectName("info_tab_widget") self.tab_page1 = ThumbWidget() self.tab_page2 = QWidget() # self.addTab(self.tab_page1, "INFO") # self.addTab(self.tab_page2, "METADATA") # Add some widgets to the tab pages self.layout = QVBoxLayout(self) self.layout.addWidget(self.tab_page1) self.layout.addWidget(self.tab_page2) self.setLayout(self.layout) self.layout.addStretch(1) # self.setFixedHeight(200) self.setMinimumWidth(320)
# layout2 = QVBoxLayout() # label2 = QLabel("This is Tab 2") # layout2.addWidget(label2) # self.tab_page2.setLayout(layout2)
[docs] class Note(QWidget): def __init__(self, data, parent=None): super().__init__(parent) self.setObjectName("note_container") layout = QHBoxLayout() NotSidelayout = QVBoxLayout() self.data = data self.user = QLabel(self) self.user.setObjectName("noteuser") try: names = data["user"].split(" ", 2) f = names[0][0] ln = names[1][0] name = f"{f}{ln}" except Exception as e: print(e) name = data["user"] self.user.setText(name) self.user.setStyleSheet( "color: rgb(0, 0, 0); font: bold 15pt; qproperty-alignment: AlignCenter;" ) self.date = QLabel(self) self.date.setText(data["date"].strip()) self.date.setObjectName("notedate") # self.date.setMargin(0) self.date.setStyleSheet("padding: 0px; margin: 0px;") self.note = QLabel(self) self.note.setWordWrap(True) self.note.setText(data["note"]) self.note.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Minimum ) # Set size policy for QLabel self.note.setObjectName("notetext") self.note.setStyleSheet("padding: 10px; margin: 10px;line-height: 10px;") layout.addWidget(self.user, 1) NotSidelayout.addWidget(self.date) NotSidelayout.addWidget(self.note) NotSidelayout.addStretch(1) layout.addLayout(NotSidelayout, 1) self.setLayout(layout) self.setMinimumHeight(20)
# self.setFixedWidth(250)
[docs] class NotesWidget(QWidget): def __init__(self, source, parent=None): self.path_object = None self.source = source self.data = None self.n = None super().__init__(parent) self.layout_h = QHBoxLayout(self) layout = QVBoxLayout(self) self.layout_h.addLayout(layout) self.layout_h.addStretch(1) self.notes_scroll = QScrollArea() self.notes_scroll.setObjectName("notes_scroll") self.notewidget = QWidget() self.notewidget.setObjectName("notes_widget") # self.notewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.notes_scroll.setWidget(self.notewidget) self.notes_scroll.setWidgetResizable(True) self.note_layout = QVBoxLayout() self.notewidget.setLayout(self.note_layout) layout.addWidget(self.notes_scroll, 5) bottomLayout = QVBoxLayout() self.input_field = QTextEdit(self) self.input_field.setPlaceholderText("add note...") self.input_field.setObjectName("notes_input_field") bottomBottomLayout = QHBoxLayout() self.submit_button = LJButton() self.submit_button.setText("Submit") bottomLayout.addWidget(self.input_field) bottomBottomLayout.addWidget(QWidget(), 2) bottomBottomLayout.addWidget(self.submit_button, 1) bottomLayout.addLayout(bottomBottomLayout) layout.addLayout(bottomLayout, 1) # self.setLayout(self.layout_h) self.submit_button.clicked.connect(self.add_new_note) # self.setFixedWidth(400) # self.setMaximumWidth(400)
[docs] def add_new_note(self): # TODO, the shotgrind user info should come from the shotgrid layer # if self.n is None: # if self.data is not None: self.path_object = FPContextMgr.get_current_po() logging.info( "path_object ************** adding note ", self.path_object.get_path() ) self.n = Notes(self.path_object) # else: # print("Data is not set. Cannot initialize FileNotesContainer.") # #add a warning, no file selected # QMessageBox.warning(self, "No File Selected", "Please select a file to add a note.") # return ucfg = CFG.user_config shotgrid_user_info = ucfg["user_info"] first = shotgrid_user_info["first"] last = shotgrid_user_info["last"] name = first + " " + last self.n.addNote(name, self.input_field.toPlainText().strip()) self.input_field.setText("") self.add_note_to_display(self.data, self.path_object)
[docs] def scroll_to_bottom(self): QApplication.instance().processEvents() scrollbar = self.notes_scroll.verticalScrollBar() scrollbar.setValue(scrollbar.maximum())
[docs] def add_note_to_display(self, data, po): self.data = data self.path_object = po self.n = Notes(po) note = self.n.notes[-1] nw = Note(note, self.notewidget) self.note_layout.addWidget(nw) # self.notewidget.adjustSize() self.scroll_to_bottom()
[docs] def remove_all_notes(self): layout = self.note_layout while layout.count(): item = layout.takeAt(0) widget = item.widget() if widget is not None: widget.setParent(None) del item
[docs] def update_display(self, po: PathObject): if po: self.n = Notes(po) self.remove_all_notes() for note in self.n.notes: nw = Note(note, self.notewidget) self.note_layout.addWidget(nw) self.notewidget.layout().invalidate() # self.notewidget.adjustSize() self.scroll_to_bottom()
[docs] class NotesTab(QWidget): def __init__(self, parent=None): super().__init__(parent) # self.tabBar().setObjectName("info_tab_widget") self.tab_page1 = NotesWidget("file") self.tab_page2 = NotesWidget("version") # self.addTab(self.tab_page1, "File Notes") self.layout = QVBoxLayout() self.setLayout(self.layout) self.layout.addWidget(self.tab_page1) # self.setMaximumWidth(300) # self.layout.setSpacing(0) # self.layout.addWidget(self.tab_page2) # self.setStyleSheet("QWidget { background-color: grey; }") # self.addTab(self.tab_page2, "Version Notes")
[docs] def scroll_notes(self): self.tab_page1.scroll_to_bottom()
[docs] def add_comment(path_object): """This is meant to run inside an already running QApp it will prompt the user for a note and add it Args: path_object (_type_): _description_ """ dialog = QDialog() layout = QVBoxLayout() label = QLabel( "Please add a comment for this version {}".format(path_object.version) ) layout.addWidget(label) text_edit = QTextEdit() text_edit.setFixedHeight( 100 ) # Adjust this value to change the height of the text box layout.addWidget(text_edit) button = QPushButton("OK") button.clicked.connect(dialog.accept) layout.addWidget(button) dialog.setLayout(layout) dialog.setWindowTitle("Version Comment") dialog.exec() text = text_edit.toPlainText() if text: notes = Notes(path_object) notes.addNote(path_object.user, text) notes.save() QMessageBox.information(None, "SUCCESS", "comment:\n {}".format(text)) else: QMessageBox.warning(None, "Warning", "Sorry, you need to add a comment.")
if __name__ == "__main__": app = QApplication(sys.argv) main_window = NotesWidget(None) main_window.show() app.exec()