Source code for cgl.ui.widgets.widgets
import logging
import os
import webbrowser
from PySide6 import QtCore, QtGui, QtWidgets
from cgl.ui.widgets.button import LJButton
try:
from PySide6.QtSvg import QSvgRenderer
except ImportError:
from PySide6.QtSvg import QSvgRenderer
from cgl.apps.alchemy.data.filedialogcontextmanager import FPContextMgr
from cgl.core import path
from cgl.core.config.query import AlchemyConfigManager, get_task_source
from cgl.core.utils.general import cgl_copy
from cgl.ui.util import define_palettes
from cgl.ui.widgets.containers.model import ListItemModel
from cgl.ui.widgets.containers.table import LJTableWidget
CFG = AlchemyConfigManager()
[docs]
class LJTag(QtWidgets.QFrame):
close_clicked = QtCore.Signal()
def __init__(self, parent=None, text="Tab Text", height=30):
QtWidgets.QFrame.__init__(self, parent)
self.setMinimumHeight(height)
self.setProperty("role", "tag")
self.setMaximumHeight(height + 0)
self.text = text
close_width = height / 2
layout = QtWidgets.QHBoxLayout(self)
layout.setContentsMargins(6, 0, 0, 0)
label = QtWidgets.QLabel(text)
close_button = QtWidgets.QToolButton()
close_button.setText("x")
close_button.setMaximumWidth(close_width)
close_button.setMaximumHeight(close_width)
layout.addWidget(label)
layout.addWidget(close_button)
# Shape of the button is a "Frame" with an hlayout
# close button is a "tool button" with an 'x'
close_button.clicked.connect(self.delete_tag)
[docs]
class TagWidget(QtWidgets.QWidget):
def __init__(self, parent=None, entry_type="line_edit", validation_list=None):
QtWidgets.QWidget.__init__(self, parent)
layout = QtWidgets.QVBoxLayout(self)
layout.setContentsMargins(0, 5, 0, 5)
layout.setSpacing(0)
self.frame = TagFrame(entry_type=entry_type, validation_list=validation_list)
layout.addWidget(self.frame)
[docs]
class TagFrame(QtWidgets.QFrame):
tags_changed = QtCore.Signal(object)
def __init__(
self, parent=None, tag_height=34, entry_type="line_edit", validation_list=None
):
QtWidgets.QFrame.__init__(self, parent)
self.entry_type = entry_type
self.validation_list = validation_list
if validation_list:
self.validation_list.insert(0, "")
self.tag_height = tag_height
# self.setProperty("surface", "1")
self.setMinimumHeight(tag_height + 4)
self.layout = QtWidgets.QHBoxLayout(self)
self.layout.setSpacing(0)
self.layout.setContentsMargins(0, 0, 0, 0)
self.tags_layout = QtWidgets.QHBoxLayout()
self.tags_layout.setContentsMargins(0, 0, 0, 0)
self.tags_layout.setSpacing(5)
if entry_type == "line_edit":
self.text_entry = QtWidgets.QLineEdit()
self.text_entry.setProperty("tone", "transparent")
self.text_entry.setMinimumHeight(tag_height + 10)
self.text_entry.setMinimumWidth(300)
self.text_entry.textEdited.connect(self.on_text_entry_changed)
self.text_entry.returnPressed.connect(self.on_text_entry_return)
elif entry_type == "combo":
self.text_entry = QtWidgets.QComboBox()
self.text_entry.setEditable(True)
if self.validation_list:
self.text_entry.addItems(self.validation_list)
self.text_entry.currentIndexChanged.connect(self.on_text_entry_changed)
# self.text_entry.setProperty("class", "tag_entry")
self.tag_dict = {}
self.tags = []
self.layout.addLayout(self.tags_layout)
self.layout.addWidget(self.text_entry)
[docs]
def on_text_entry_changed(self):
if self.entry_type == "line_edit":
text = self.sender().text()
if "," in text:
text = text.replace(",", "")
self.add_tag(tag_text=text)
self.sender().setText("")
else:
text = self.sender().currentText()
self.sender().setCurrentIndex(0)
if text:
self.add_tag(tag_text=text)
[docs]
def on_text_entry_return(self):
"""
Adds a tag to the tag widget
Returns:
"""
if self.entry_type == "line_edit":
text = self.sender().text()
self.add_tag(tag_text=text)
self.sender().setText("")
[docs]
def add_tag(self, tag_text):
if self.validate_tag(tag_text):
tag = LJTag(text=tag_text, height=self.tag_height)
tag.close_clicked.connect(self.remove_tag)
self.tag_dict["tag_text"] = tag
self.tags.append(tag_text)
self.tags_layout.addWidget(tag)
self.tags_changed.emit(self.tags)
else:
print(
"{} not found in validation list {}".format(
tag_text, self.validation_list
)
)
self.tags_changed.emit(self.tags)
[docs]
def remove_tag(self, tag_text=None):
if not tag_text:
tag_text = self.sender().text
widget = self.sender()
self.sender().deleteLater()
else:
widget = self.find_tag_widget(tag_text)
if tag_text in self.tags:
self.tags.remove(tag_text)
if widget:
widget.deleteLater()
self.layout.removeWidget(widget)
self.tags_changed.emit(self.tags)
[docs]
def remove_all_tags(self):
"""
Removes all tags from the tag widget
"""
for i in range(self.tags_layout.count()):
widget = self.tags_layout.itemAt(i).widget()
widget.deleteLater()
self.layout.removeWidget(widget)
self.tags = []
self.tags_changed.emit(self.tags)
[docs]
def find_tag_widget(self, tag_text):
# iterate over the widgets in the self.layout and find the tag with the tag_text
for i in range(self.tags_layout.count()):
widget = self.tags_layout.itemAt(i).widget()
if widget.text == tag_text:
return widget
[docs]
def validate_tag(self, tag_text):
"""
Validates the tag against the validation list
Returns:
"""
if self.validation_list:
if tag_text in self.validation_list:
return True
else:
return False
else:
return True
[docs]
class HelpMenu(LJButton):
"""
This is the the hat menu that appears on the UI
"""
def __init__(self, parent):
LJButton.__init__(self, parent)
print(parent)
self.parent = parent
self.parent.report_bug_dialog = None
self.parent.request_a_feature_dialog = None
self.menu = QtWidgets.QMenu()
self.setText("")
self.setup_menu()
self.setToolTip("Help")
[docs]
def load_msd_clicked(self):
"""
Loads the msd from the filesystem
Returns:
"""
print("loading msd")
[docs]
def clear_widget_clicked(self):
"""
Clears the table widget
Returns:
"""
print("clearing table widget")
print(self.parent())
[docs]
def tutorials_clicked(self):
"""
Returns:
"""
url = r"conflence url for cglumberjack's tutorials"
print(url)
# webbrowser.open_new_tab(url)
[docs]
def documentation_clicked(self):
"""
sends the user to alchemy's code documentation.
Returns:
"""
url = r"http://docs.alchemystudio.io"
webbrowser.open_new_tab(url)
[docs]
def report_bug_clicked(self):
from cgl.ui.widgets.help import ReportBugDialog
self.parent.report_bug_dialog = ReportBugDialog(parent=None)
self.parent.report_bug_dialog.show()
self.parent.report_bug_dialog.raise_()
[docs]
def request_feature_clicked(self):
from cgl.ui.widgets.help import ReportBugDialog
self.request_a_feature_dialog = ReportBugDialog(title="Request A Feature").exec()
self.request_a_feature_dialog.show()
self.request_a_feature_dialog.raise_()
[docs]
def IT_request_clicked(self):
from cgl.ui.widgets.help import ReportBugDialog
ReportBugDialog(title="Pipeline IT Request").exec()
[docs]
class LoginMenu(LJButton):
def __init__(self, parent):
LJButton.__init__(self, parent)
self.user = "tom.m"
self.menu = QtWidgets.QMenu()
self.setObjectName("login")
# self.setText(self.tr("login"))
self.setup_menu()
[docs]
def get_current_user(self):
# TODO - get the current user from the config
self.user = "tom.m"
self.setup_menu()
[docs]
def login_clicked(self):
from cgl.apps.magic_browser.to_delete.config import ConfigDialog
dialog = ConfigDialog()
dialog.exec()
[docs]
def logout_clicked(self):
from cgl.apps.magic_browser.to_delete.config import ConfigDialog
# TODO - delete the user data in the user config
dialog = ConfigDialog()
dialog.exec()
[docs]
def settings_clicked(self):
from cgl.apps.magic_browser.to_delete.config import ConfigDialog
dialog = ConfigDialog()
dialog.exec()
[docs]
class VersionButton(LJButton):
def __init__(self, parent):
LJButton.__init__(self, parent)
self.menu = QtWidgets.QMenu()
self.setText(self.tr("Version Up"))
self.selected_act = self.menu.addAction(self.tr("New Version From Selected"))
self.empty_act = self.menu.addAction(self.tr("New Empty Version"))
self.empty_act.setToolTip(self.tr("Create a new empty version"))
self.empty_act.triggered.connect(
lambda: self.parent().create_empty_version.emit()
)
self.selected_act.triggered.connect(
lambda: self.parent().copy_selected_version.emit()
)
self.selected_act.setToolTip(
self.tr("Create a new version copying from current version")
)
# self.latest_act = self.menu.addAction(self.tr("Copy Latest Version"))
# self.latest_act.triggered.connect(lambda: self.parent().copy_latest_version.emit())
# self.latest_act.setToolTip(self.tr("Create a new version copying from the latest version"))
self.setMenu(self.menu)
[docs]
def set_new_version(self):
self.selected_act.setVisible(False)
self.latest_act.setVisible(False)
self.setEnabled(True)
[docs]
def set_version_selected(self):
self.selected_act.setVisible(True)
self.latest_act.setVisible(True)
self.setEnabled(True)
[docs]
class EmptyStateWidget(QtWidgets.QPushButton):
files_added = QtCore.Signal()
def __init__(
self, parent=None, path_object=None, text="Drag/Drop to Add Files", files=False
):
QtWidgets.QPushButton.__init__(self, parent)
self.files = files
self.path_object = path_object
self.setAcceptDrops(True)
self.setMinimumWidth(300)
self.setMinimumHeight(100)
self.setText(text)
self.setProperty("class", "empty_state")
self.to_path = ""
self.to_object = None
[docs]
def dragMoveEvent(self, e):
if e.mimeData().hasUrls:
e.setDropAction(QtCore.Qt.CopyAction)
e.accept()
else:
e.ignore()
[docs]
def dropEvent(self, e):
if e.mimeData().hasUrls():
e.accept()
urls = e.mimeData().urls()
self.handle_dropped_files(urls)
elif e.mimeData().hasFormat("application/x-qabstractitemmodeldatalist"):
e.accept()
self.handle_table_drag_drop(e)
else:
e.ignore()
[docs]
def handle_dropped_files(self, urls):
for url in urls:
file_path = url.toLocalFile()
print("FILE PATH::::::::::::::", file_path)
file_name = os.path.basename(file_path)
extension = os.path.splitext(file_path)[-1]
directory = os.path.dirname(file_path)
# Get the icon for the dropped file
path_object = FPContextMgr.get_current_po()
destination_path = path_object.copy(
filename=file_name, ext=extension
).get_source_path()
print("DESTINATION PATH", destination_path)
destination_path = destination_path.replace("render", "source")
directory = os.path.dirname(destination_path)
if not os.path.exists(directory):
os.makedirs(directory)
print("MOVING FROM ", file_path, "TO", destination_path)
cgl_copy(file_path, destination_path)
self.files_added.emit()
[docs]
class FileTableModel(ListItemModel):
[docs]
def data(self, index, role):
row = index.row()
col = index.column()
if role == QtCore.Qt.DisplayRole:
return self.data_[row][col]
if role == QtCore.Qt.DecorationRole:
data = self.data_[row][col]
if "." not in data:
return QtGui.QIcon(CFG.get_icon_path("folder2.png"))
[docs]
class QHLine(QtWidgets.QFrame):
def __init__(self):
super(QHLine, self).__init__()
self.setFrameShape(QtWidgets.QFrame.HLine)
self.setFrameShadow(QtWidgets.QFrame.Sunken)
[docs]
class QVLine(QtWidgets.QFrame):
def __init__(self):
super(QVLine, self).__init__()
self.setFrameShape(QtWidgets.QFrame.VLine)
self.setFrameShadow(QtWidgets.QFrame.Sunken)
[docs]
class AssetWidget(QtWidgets.QWidget):
"""
GUI Element for Displaying shots, assets, and "my tasks"
"""
button_clicked = QtCore.Signal(object)
filter_changed = QtCore.Signal()
add_clicked = QtCore.Signal()
assign_clicked = QtCore.Signal(object)
def __init__(
self,
parent,
title,
filter_string=None,
search_box=None,
):
QtWidgets.QWidget.__init__(self, parent)
self.right_click = False
self.v_layout = QtWidgets.QVBoxLayout(self)
v_list = QtWidgets.QVBoxLayout()
self.scope_layout = QtWidgets.QHBoxLayout()
self.shots_icon = QtGui.QPixmap(CFG.get_icon_path("shots24px.png"))
self.assets_icon = QtGui.QPixmap(CFG.get_icon_path("assets24px.png"))
self.worlds_icon = QtGui.QPixmap(CFG.get_icon_path("unreal-engine24px.png"))
self.tool_button_layout = QtWidgets.QHBoxLayout()
self.sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
QtWidgets.QSizePolicy.MinimumExpanding,
)
self.setSizePolicy(self.sizePolicy)
self.filter_string = filter_string
self.label = title
self.task = None
self.user = None
min_width = 340
self.message = QtWidgets.QLabel("")
self.message.setMinimumWidth(min_width)
try:
self.message.setSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
)
except AttributeError:
logging.info("PySide6 Natively does not have QtWidgets.QSizePolicy")
self.message.setAlignment(QtCore.Qt.AlignCenter)
self.search_box = search_box
self.add_button = QtWidgets.QToolButton()
self.add_button.setText("add")
self.add_button.setProperty("class", "add_button")
self.data_table = LJTableWidget(self, path_object=self.path_object)
self.data_table.title = title
self.data_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.data_table.setMinimumWidth(min_width)
# self.setProperty('class', 'basic')
# tasks the filter options row
self.world_radio = QtWidgets.QRadioButton("World")
self.assets_radio = QtWidgets.QRadioButton("Assets")
self.shots_radio = QtWidgets.QRadioButton("Shots")
self.tasks_radio = QtWidgets.QRadioButton("My Tasks")
self.radio_group_scope = QtWidgets.QButtonGroup(self)
self.radio_group_scope.addButton(self.shots_radio)
self.radio_group_scope.addButton(self.assets_radio)
self.radio_group_scope.addButton(self.tasks_radio)
self.radio_group_scope.addButton(self.world_radio)
self.shot_icon = QtWidgets.QLabel()
self.shot_icon.setPixmap(self.shots_icon)
self.asset_icon = QtWidgets.QLabel()
self.asset_icon.setPixmap(self.assets_icon)
self.world_icon = QtWidgets.QLabel()
self.world_icon.setPixmap(self.worlds_icon)
self.scope_layout.addWidget(self.tasks_radio)
self.scope_layout.addWidget(self.world_icon)
self.scope_layout.addWidget(self.world_radio)
self.scope_layout.addWidget(self.shot_icon)
self.scope_layout.addWidget(self.shots_radio)
self.scope_layout.addWidget(self.asset_icon)
self.scope_layout.addWidget(self.assets_radio)
self.scope_layout.addStretch(1)
self.scope_layout.addWidget(self.add_button)
v_list.addItem(
QtWidgets.QSpacerItem(
0, 3, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum
)
)
v_list.addWidget(self.data_table, 1)
self.v_layout.addLayout(self.scope_layout)
self.v_layout.addWidget(self.message)
self.v_layout.addLayout(v_list)
self.v_layout.setContentsMargins(0, 12, 0, 0)
self.add_button.clicked.connect(self.on_add_button_clicked)
[docs]
def set_icon(self, scope="assets"):
if scope == "assets":
self.shot_icon.setPixmap(self.assets_icon)
self.add_button.setText("add asset")
elif scope == "shots":
self.shot_icon.setPixmap(self.shots_icon)
self.add_button.setText("add shot")
[docs]
def setup(self, mdl):
self.data_table.set_item_model(mdl)
self.data_table.set_search_box(self.search_box)
[docs]
def on_show_button_clicked(self):
self.show_combos()
self.hide_button.show()
self.show_button.hide()
[docs]
def on_hide_button_clicked(self):
self.hide_combos()
self.hide_button.hide()
self.show_button.show()
[docs]
def set_title(self, new_title):
self.title.setText("<h2>Project: %s</h2>" % new_title.title_label())
[docs]
class LJListWidget(QtWidgets.QWidget):
def __init__(
self, label, pixmap, empty_state_text="", empty_state_icon=None, search_box=None
):
QtWidgets.QWidget.__init__(self)
self.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum
)
layout = QtWidgets.QVBoxLayout(self)
self.label = QtWidgets.QLabel(label)
self.label.setProperty("class", "ultra_title")
self.add_button = QtWidgets.QToolButton()
self.add_button.setText("+")
self.add_button.setProperty("class", "add_button")
self.h_layout = QtWidgets.QHBoxLayout()
self.search_box = search_box
layout.setContentsMargins(0, 0, 0, 0)
if pixmap:
self.icon = QtWidgets.QLabel()
self.icon.setPixmap(pixmap)
self.h_layout.addWidget(self.icon)
self.h_layout.addWidget(self.label)
self.h_layout.addStretch(1)
self.h_layout.addWidget(self.add_button)
self.list = QtWidgets.QListWidget()
self.list.setProperty("class", "basic")
self.empty_state = QtWidgets.QPushButton(empty_state_text)
if empty_state_icon:
self.set_icon(empty_state_icon)
self.empty_state.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
QtWidgets.QSizePolicy.MinimumExpanding,
)
self.empty_state.setProperty("class", "empty_state2")
self.empty_state.hide()
layout.addLayout(self.h_layout)
layout.addWidget(self.list)
layout.addWidget(self.empty_state)
# self.combo.hide()
[docs]
class CreateProjectDialog(QtWidgets.QDialog):
path_object = None
def __init__(self, parent, company, variable):
QtWidgets.QDialog.__init__(self, parent=parent)
self.variable = variable
self.company = company
self.project_management = get_task_source()
self.proj_management_label = QtWidgets.QLabel("Project Management")
layout = QtWidgets.QVBoxLayout(self)
self.proj_management_combo = QtWidgets.QComboBox()
self.proj_management_combo.addItems(
["magic_browser", "ftrack", "shotgrid", "google_docs"]
)
self.red_palette, self.green_palette, self.black_palette = define_palettes()
self.server_label = QtWidgets.QLabel("server url:")
self.api_key_label = QtWidgets.QLabel("api key:")
self.api_user = QtWidgets.QLabel("api user:")
self.server_line_edit = QtWidgets.QLineEdit()
self.api_key_line_edit = QtWidgets.QLineEdit()
self.api_user_line_edit = QtWidgets.QLineEdit()
self.cancel_button = QtWidgets.QPushButton("Cancel")
self.ok_button = QtWidgets.QPushButton("Ok")
self.button = ""
button_layout = QtWidgets.QHBoxLayout()
button_layout.addStretch(1)
button_layout.addWidget(self.cancel_button)
button_layout.addWidget(self.ok_button)
proj_label = QtWidgets.QLabel("%s Name" % self.variable.title_label())
self.proj_line_edit = QtWidgets.QLineEdit("")
self.message = QtWidgets.QLabel()
self.grid_layout = QtWidgets.QGridLayout()
self.grid_layout.addWidget(proj_label, 0, 0)
self.grid_layout.addWidget(self.proj_line_edit, 0, 1)
self.grid_layout.addWidget(self.proj_management_label, 2, 0)
self.grid_layout.addWidget(self.proj_management_combo, 2, 1)
self.grid_layout.addWidget(self.server_label, 3, 0)
self.grid_layout.addWidget(self.server_line_edit, 3, 1)
self.grid_layout.addWidget(self.api_key_label, 4, 0)
self.grid_layout.addWidget(self.api_key_line_edit, 4, 1)
self.grid_layout.addWidget(self.api_user, 5, 0)
self.grid_layout.addWidget(self.api_user_line_edit, 5, 1)
layout.addLayout(self.grid_layout)
layout.addWidget(self.message)
layout.addLayout(button_layout)
self.proj_line_edit.textChanged.connect(self.on_project_text_changed)
self.ok_button.clicked.connect(self.on_ok_clicked)
self.cancel_button.clicked.connect(self.on_cancel_clicked)
self.proj_management_combo.currentIndexChanged.connect(self.on_pm_changed)
self.adjust_to_variable()
self.set_project_management()
self.set_colors()
[docs]
def set_colors(self):
APP_COLORS = CFG.project_config["colors"]
self.setStyleSheet("background: {};".format(APP_COLORS["text"]))
self.proj_management_combo.setStyleSheet(
"background: {}; color: {};".format(
APP_COLORS["secondary"], APP_COLORS["text"]
)
)
[docs]
def set_project_management(self, proj_man=None):
self.proj_management_combo.setCurrentIndex(0)
self.hide_api_info()
# if not proj_man:
# proj_man = self.project_management
# index = self.proj_management_combo.findText(proj_man)
# self.proj_management_combo.setCurrentIndex(index)
[docs]
def adjust_to_variable(self):
if self.variable.lower() == "project":
self.setWindowTitle("Create a Project")
self.hide_api_info()
# self.proj_management_combo.hide()
# self.proj_management_label.hide()
elif self.variable.lower() == "company":
self.setWindowTitle("Create a Company")
self.hide_api_info()
self.proj_management_combo.show()
self.proj_management_label.show()
[docs]
def hide_api_info(self):
self.server_label.hide()
self.api_key_label.hide()
self.api_user.hide()
self.server_line_edit.hide()
self.api_key_line_edit.hide()
self.api_user_line_edit.hide()
[docs]
def show_api_info(self):
self.server_label.show()
self.api_key_label.show()
self.api_user.show()
self.server_line_edit.show()
self.api_key_line_edit.show()
self.api_user_line_edit.show()
[docs]
def on_pm_changed(self):
if self.proj_management_combo.currentText() == "magic_browser":
self.hide_api_info()
else:
self.hide_api_info()
[docs]
def on_project_text_changed(self):
input_text = self.proj_line_edit.text()
message = CFG.test_string_against_rules(input_text, self.variable, self.message)
if input_text:
if message:
self.message.setText(message)
self.message.setPalette(self.red_palette)
else:
self.message.setText("Creating %s: %s" % (self.variable, input_text))
else:
self.message.setText("")
[docs]
def on_ok_clicked(self):
d = {}
if self.variable.lower() == "project":
d = {
"company": self.company,
"project": self.proj_line_edit.text(),
"context": "source",
"branch": "master",
}
elif self.variable.lower() == "company":
d = {"company": self.proj_line_edit.text()}
self.path_object = path.PathObject().from_dict(d)
self.button = "Ok"
self.accept()
[docs]
class AdvComboBoxLabeled(QtWidgets.QVBoxLayout):
def __init__(self, label):
QtWidgets.QVBoxLayout.__init__(self)
self.label = QtWidgets.QLabel("<b>%s</b>" % label)
[docs]
class AdvComboBox(QtWidgets.QComboBox):
def __init__(self, parent=None, editable=True):
super(AdvComboBox, self).__init__(parent)
self.user_selected = False
self.setFocusPolicy(QtCore.Qt.StrongFocus)
self.setEditable(editable)
self.SizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
self.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum
)
# add a filter model to filter matching items
self.pFilterModel = QtCore.QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.pFilterModel.setSourceModel(self.model())
# set the indicator icon
# add a completer
self.completer = QtWidgets.QCompleter(self)
# Set the model that the QCompleter uses
# - in PySide doing this as a separate step worked better
self.completer.setModel(self.pFilterModel)
# always show all (filtered) completions
self.completer.setCompletionMode(QtWidgets.QCompleter.UnfilteredPopupCompletion)
self.setCompleter(self.completer)
self.setProperty("class", "basic")
self.setMinimumWidth(130)
def filter_(text):
self.pFilterModel.setFilterFixedString(str(text))
self.lineEdit().textEdited.connect(filter_)
self.completer.activated.connect(self.on_completer_activated)
# on selection of an item from the completer, select the corresponding item from combobox
[docs]
def on_completer_activated(self, text):
if text:
index = self.findText(str(text))
self.setCurrentIndex(index)
# on model change, update the models of the filter and completer as well
[docs]
def setModel(self, model):
super(AdvComboBox, self).setModel(model)
self.pFilterModel.setSourceModel(model)
self.completer.setModel(self.pFilterModel)
# on model column change, update the model column of the filter and completer as well
[docs]
def setModelColumn(self, column):
self.completer.setCompletionColumn(column)
self.pFilterModel.setFilterKeyColumn(column)
super(AdvComboBox, self).setModelColumn(column)
[docs]
def populate_from_project(self, keys):
self.clear()
# load the shading/texture assets from the library
# clear duplicates
obj_list = []
for key in keys:
if str(key) not in obj_list:
obj_list.append(str(key))
for item in obj_list:
self.addItem(item)
[docs]
def find_text(self, text):
index = self.findText(text)
if index != -1:
self.setCurrentIndex(index)
else:
self.setCurrentIndex(0)
[docs]
class GifWidget(QtWidgets.QWidget):
def __init__(self, parent=None, gif_path=None, animated=True):
QtWidgets.QWidget.__init__(self, parent=parent)
self.setProperty("class", "gif_widget")
self.animated = animated
layout = QtWidgets.QHBoxLayout()
self.image = QtWidgets.QLabel()
self.label_1 = QtWidgets.QLabel("") # QtWidgets.QLabel("Working...")
self.label_2 = QtWidgets.QLabel("")
self.label_1.setProperty("class", "feedback")
self.label_2.setProperty("class", "feedback")
self.label_1.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum
)
self.label_2.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum
)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# Create the Actual Gif Thingy
if animated:
self.gif = QtGui.QMovie(gif_path)
self.image.setMovie(self.gif)
else:
self.gif = QtGui.QPixmap(gif_path)
self.image.setPixmap(self.gif)
self.gif.setScaledSize(QtCore.QSize(120, 120))
layout.addWidget(self.label_1)
layout.addWidget(self.image)
layout.addWidget(self.label_2)
self.setLayout(layout)
[docs]
class LJToolButton(QtWidgets.QToolButton):
def __init__(
self,
svg_path,
default_color="black",
hover_color="blue",
width=40,
height=40,
parent=None,
):
super().__init__(parent)
self.svg_path = svg_path
self.default_color = QtGui.QColor(default_color)
self.hover_color = QtGui.QColor(hover_color)
self.icon_size = QtCore.QSize(width, height)
self.is_hovered = False
# Set the initial icon with the default color
self.set_svg_icon_color(self.default_color)
[docs]
def set_svg_icon_color(self, color=None):
"""
Set the SVG icon with the given color.
"""
if color is None:
color = self.default_color
# Create a QtSvg.QSvgRenderer to load the SVG file
renderer = QSvgRenderer(self.svg_path)
# Create a QtGui.QPixmap to render the SVG
pixmap = QtGui.QPixmap(self.icon_size)
pixmap.fill(QtCore.Qt.transparent) # Start with a transparent pixmap
# Create a QPainter to paint on the pixmap
painter = QtGui.QPainter(pixmap)
# Render the SVG onto the pixmap
renderer.render(painter)
# Apply the color using CompositionMode_SourceIn
painter.setCompositionMode(QtGui.QPainter.CompositionMode_SourceIn)
painter.fillRect(pixmap.rect(), color)
# Finish painting
painter.end()
# Set the pixmap as an icon for the button
icon = QtGui.QIcon(pixmap)
self.setIcon(icon)
self.setIconSize(self.icon_size)
[docs]
def set_color(self, color):
"""
Convenience method to change the color of the SVG icon.
"""
self.set_svg_icon_color(QtGui.QColor(color))
[docs]
def enterEvent(self, event):
"""
Event handler for mouse hover enter.
"""
self.is_hovered = True
self.set_svg_icon_color(self.hover_color)
super().enterEvent(event)
[docs]
def leaveEvent(self, event):
"""
Event handler for mouse hover leave.
"""
self.is_hovered = False
self.set_svg_icon_color(self.default_color)
super().leaveEvent(event)
[docs]
def svg_icon(svg_path, color=None, size=16):
"""
Set the SVG icon with the given color.
"""
icon_size = QtCore.QSize(size, size)
if color is None:
color = self.default_color
# Create a QtSvg.QSvgRenderer to load the SVG file
renderer = QSvgRenderer(svg_path)
# Create a QtGui.QPixmap to render the SVG
pixmap = QtGui.QPixmap(icon_size)
pixmap.fill(QtCore.Qt.transparent) # Start with a transparent pixmap
# Create a QPainter to paint on the pixmap
painter = QtGui.QPainter(pixmap)
# Render the SVG onto the pixmap
renderer.render(painter)
# Apply the color using CompositionMode_SourceIn
painter.setCompositionMode(QtGui.QPainter.CompositionMode_SourceIn)
painter.fillRect(pixmap.rect(), color)
# Finish painting
painter.end()
# Set the pixmap as an icon for the button
icon = QtGui.QIcon(pixmap)
return icon