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 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 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)
# 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 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()