diff --git a/openpype/style/data.json b/openpype/style/data.json index 977de50be2..026eaf4264 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -59,7 +59,12 @@ "color-selected": "#F0F2F5", "color-hover": "#F0F2F5" }, - + "nice-checkbox": { + "bg-checked": "#56a06f", + "bg-unchecked": "#434b56", + "bg-checker": "#D3D8DE", + "bg-checker-hover": "#F0F2F5" + }, "loader": { "asset-view": { "selected": "rgba(168, 175, 189, 0.6)", @@ -79,6 +84,34 @@ "bg-expander-hover": "#2d6c9f", "bg-expander-selected-hover": "#3784c5" } + }, + "settings": { + "invalid-light": "#C93636", + "invalid-dark": "#AD2E2E", + + "modified-light": "#46b1f3", + "modified-mid": "#189AEA", + "modified-dark": "#106AA2", + + "studio-light": "#73C990", + "studio-dark": "#56a06f", + "studio-label-hover": "#FFFFFF", + + "project-light": "#FFA64D", + "project-mid": "#FF8C1A", + "project-dark": "#E67300", + + "label-fg": "#969b9e", + "label-fg-hover": "#b8c1c5", + + "breadcrumbs-btn-bg": "rgba(127, 127, 127, 60)", + "breadcrumbs-btn-bg-hover": "rgba(127, 127, 127, 90)", + + "content-hightlighted": "rgba(19, 26, 32, 15)", + "focus-border": "#839caf", + "image-btn": "#bfccd6", + "image-btn-hover": "#189aea", + "image-btn-disabled": "#bfccd6" } } } diff --git a/openpype/style/style.css b/openpype/style/style.css index fa5b41cd07..a60c3592d7 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -660,15 +660,6 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } -/* Globally used names */ -#Separator { - background: {color:bg-menu-separator}; -} - -#IconButton { - padding: 4px 4px 4px 4px; -} - /* Password dialog*/ #PasswordBtn { border: none; @@ -971,7 +962,235 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: transparent; } +/* Settings - NOT USED YET +- we need to define font family for settings UI */ + +#SettingsMainWidget { + background: #141a1f; +} +/* Change focus borders. */ +#SettingsMainWidget QAbstractSpinBox:focus, #SettingsMainWidget QLineEdit:focus, #SettingsMainWidget QPlainTextEdit:focus, #SettingsMainWidget QTextEdit:focus { + border-color: {color:settings:focus-border}; +} +/* Modify tab widget for settings */ +#SettingsMainWidget QTabWidget::pane { + border-top-style: none; +} + +#SettingsMainWidget QTabBar { + background: transparent; +} + +#SettingsMainWidget QTabBar::tab { + border: none; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + padding: 5px; +} + +#SettingsMainWidget QTabBar::tab:selected { + background: {color:bg}; + border-color: #9B9B9B; + border-bottom-color: #C2C7CB; +} + +#SettingsMainWidget QTabBar::tab:!selected { + margin-top: 2px; + background: #21252B; +} + +#SettingsMainWidget QTabBar::tab:!selected:hover { + background: #333840; +} + +#SettingsMainWidget QTabBar::tab:first:selected { + margin-left: 0; +} + +#SettingsMainWidget QTabBar::tab:last:selected { + margin-right: 0; +} + +#SettingsMainWidget QTabBar::tab:only-one { + margin: 0; +} + +#SettingsToolIconBtn { + border: 0px solid #bfccd6; + background-color: transparent; +} + +#SettingsToolBtn { + border: 1px solid #bfccd6; + border-radius: 10px; + background-color: transparent; +} + +#SettingsToolBtn:hover { + border-color: #189aea; + color: {color:settings:modified-light}; + background-color: transparent; +} +#SettingsToolBtn:disabled { + background-color: #464b54; +} + +#ExpandToggleBtn { + background: transparent; +} + +#SettingsLabel { + background: transparent; + color: {color:settings:label-fg}; +} +#SettingsLabel:hover {color: {color:settings:label-fg-hover};} +#SettingsLabel[state="studio"] {color: {color:settings:studio-light};} +#SettingsLabel[state="studio"]:hover {color: {color:settings:studio-label-hover};} +#SettingsLabel[state="modified"] {color: {color:settings:modified-mid};} +#SettingsLabel[state="modified"]:hover {color: {color:settings:modified-light};} +#SettingsLabel[state="overriden-modified"] {color: {color:settings:modified-mid};} +#SettingsLabel[state="overriden-modified"]:hover {color: {color:settings:modified-light};} +#SettingsLabel[state="overriden"] {color: {color:settings:project-mid};} +#SettingsLabel[state="overriden"]:hover {color: {color:settings:project-light};} +#SettingsLabel[state="invalid"] {color:{color:settings:invalid-dark};} +#SettingsLabel[state="invalid"]:hover {color: {color:settings:invalid-dark};} + +/* TODO Replace these with explicit widget types if possible */ +#SettingsMainWidget QWidget[input-state="modified"] { + border-color: {color:settings:modified-mid}; +} +#SettingsMainWidget QWidget[input-state="overriden-modified"] { + border-color: {color:settings:modified-mid}; +} +#SettingsMainWidget QWidget[input-state="overriden"] { + border-color: {color:settings:project-mid}; +} +#SettingsMainWidget QWidget[input-state="invalid"] { + border-color: {color:settings:invalid-dark}; +} + +#GroupWidget { + border-bottom: 1px solid #21252B; +} + +#ProjectListWidget QLabel { + background: transparent; + font-weight: bold; +} + +#MultiSelectionComboBox { + font-size: 12px; +} + +#DictKey[state="modified"] {border-color: {color:settings:modified-mid};} +#DictKey[state="invalid"] {border-color: {color:settings:invalid-dark};} + +#ExpandLabel { + font-weight: bold; + color: {color:settings:label-fg}; +} +#ExpandLabel:hover { + color: {color:settings:label-fg-hover}; +} + +#ContentWidget { + background-color: transparent; +} +#ContentWidget[content_state="hightlighted"] { + background-color: {color:settings:content-hightlighted}; +} + +#SideLineWidget { + background-color: #333942; + border-style: solid; + border-color: #4e5254; + border-left-width: 3px; + border-bottom-width: 0px; + border-right-width: 0px; + border-top-width: 0px; +} + +#SideLineWidget:hover { + border-color: #7d8386; +} + +#SideLineWidget[state="child-studio"] {border-color: {color:settings:studio-dark};} +#SideLineWidget[state="child-studio"]:hover {border-color: {color:settings:studio-light};} + +#SideLineWidget[state="child-modified"] {border-color: {color:settings:modified-dark};} +#SideLineWidget[state="child-modified"]:hover {border-color: {color:settings:modified-mid};} + +#SideLineWidget[state="child-invalid"] {border-color: {color:settings:invalid-dark};} +#SideLineWidget[state="child-invalid"]:hover {border-color: {color:settings:invalid-light};} + +#SideLineWidget[state="child-overriden"] {border-color: {color:settings:project-dark};} +#SideLineWidget[state="child-overriden"]:hover {border-color: {color:settings:project-mid};} + +#SideLineWidget[state="child-overriden-modified"] {border-color: {color:settings:modified-dark};} +#SideLineWidget[state="child-overriden-modified"]:hover {border-color: {color:settings:modified-mid};} + +#DictAsWidgetBody { + background: transparent; +} +#DictAsWidgetBody[show_borders="1"] { + border: 1px solid #4e5254; + border-radius: 5px; +} + +#ShadowWidget { + font-size: 36pt; +} + +#BreadcrumbsPathInput { + padding: 2px; + font-size: 9pt; +} + +#BreadcrumbsButton { + padding-right: 12px; + font-size: 9pt; + background: transparent; +} + +#BreadcrumbsButton[empty="1"] { + padding-right: 0px; +} + +#BreadcrumbsButton::menu-button { + border: none; + width: 12px; + background: {color:settings:breadcrumbs-btn-bg}; +} +#BreadcrumbsButton::menu-button:hover { + background: {color:settings:breadcrumbs-btn-bg-hover}; +} + +#BreadcrumbsPanel { + border: 1px solid #4e5254; + border-radius: 5px; + background: #21252B; +} + +/* Globally used names */ +#Separator { + background: {color:bg-menu-separator}; +} + +#IconButton { + padding: 4px 4px 4px 4px; +} + #NiceCheckbox { /* Default size hint of NiceCheckbox is defined by font size. */ font-size: 7pt; } + +#ImageButton { + padding: 0; + background: transparent; + font-size: 11pt; +} + +#ImageButton:disabled { + background: {color:bg-buttons-disabled}; +} diff --git a/openpype/tools/settings/__init__.py b/openpype/tools/settings/__init__.py index a156228dc1..3e77a8348a 100644 --- a/openpype/tools/settings/__init__.py +++ b/openpype/tools/settings/__init__.py @@ -1,12 +1,13 @@ import sys from Qt import QtWidgets, QtGui + +from openpype import style from .lib import ( BTN_FIXED_SIZE, CHILD_OFFSET ) from .local_settings import LocalSettingsWindow from .settings import ( - style, MainWidget, ProjectListWidget ) @@ -36,8 +37,6 @@ __all__ = ( "BTN_FIXED_SIZE", "CHILD_OFFSET", - "style", - "MainWidget", "ProjectListWidget", "LocalSettingsWindow", diff --git a/openpype/tools/settings/local_settings/apps_widget.py b/openpype/tools/settings/local_settings/apps_widget.py index e6a4132955..850e009937 100644 --- a/openpype/tools/settings/local_settings/apps_widget.py +++ b/openpype/tools/settings/local_settings/apps_widget.py @@ -172,7 +172,9 @@ class LocalApplicationsWidgets(QtWidgets.QWidget): def _reset_app_widgets(self): while self.content_layout.count() > 0: item = self.content_layout.itemAt(0) - item.widget().hide() + widget = item.widget() + if widget is not None: + widget.setVisible(False) self.content_layout.removeItem(item) self.widgets_by_group_name.clear() diff --git a/openpype/tools/settings/local_settings/projects_widget.py b/openpype/tools/settings/local_settings/projects_widget.py index 9cd3b9a38e..7e2ad661a0 100644 --- a/openpype/tools/settings/local_settings/projects_widget.py +++ b/openpype/tools/settings/local_settings/projects_widget.py @@ -6,10 +6,7 @@ from openpype.settings.constants import ( PROJECT_ANATOMY_KEY, DEFAULT_PROJECT_KEY ) -from .widgets import ( - SpacerWidget, - ProxyLabelWidget -) +from .widgets import ProxyLabelWidget from .constants import ( LABEL_REMOVE_DEFAULT, LABEL_ADD_DEFAULT, @@ -238,9 +235,9 @@ class SitesWidget(QtWidgets.QWidget): comboboxes_layout = QtWidgets.QHBoxLayout(comboboxes_widget) comboboxes_layout.setContentsMargins(0, 0, 0, 0) - comboboxes_layout.addWidget(active_site_widget) - comboboxes_layout.addWidget(remote_site_widget) - comboboxes_layout.addWidget(SpacerWidget(comboboxes_widget), 1) + comboboxes_layout.addWidget(active_site_widget, 0) + comboboxes_layout.addWidget(remote_site_widget, 0) + comboboxes_layout.addStretch(1) content_widget = QtWidgets.QWidget(self) content_layout = QtWidgets.QVBoxLayout(content_widget) @@ -259,7 +256,9 @@ class SitesWidget(QtWidgets.QWidget): def _clear_widgets(self): while self.content_layout.count(): item = self.content_layout.itemAt(0) - item.widget().hide() + widget = item.widget() + if widget is not None: + widget.setVisible(False) self.content_layout.removeItem(item) self.input_objects = {} @@ -383,7 +382,7 @@ class SitesWidget(QtWidgets.QWidget): self.input_objects[site_name] = site_input_objects # Add spacer so other widgets are squeezed to top - self.content_layout.addWidget(SpacerWidget(self), 1) + self.content_layout.addStretch(1) def _on_input_value_change(self, site_name, key): if ( @@ -456,6 +455,8 @@ class _SiteCombobox(QtWidgets.QWidget): self ) combobox_input = QtWidgets.QComboBox(self) + combobox_delegate = QtWidgets.QStyledItemDelegate() + combobox_input.setItemDelegate(combobox_delegate) main_layout = QtWidgets.QHBoxLayout(self) main_layout.addWidget(label_widget) @@ -464,6 +465,7 @@ class _SiteCombobox(QtWidgets.QWidget): combobox_input.currentIndexChanged.connect(self._on_index_change) self.label_widget = label_widget self.combobox_input = combobox_input + self._combobox_delegate = combobox_delegate def _set_current_text(self, text): index = None @@ -777,7 +779,7 @@ class RootSiteWidget(QtWidgets.QWidget): main_layout = QtWidgets.QVBoxLayout(self) main_layout.addWidget(sites_widget) - main_layout.addWidget(SpacerWidget(self), 1) + main_layout.addStretch(1) self.sites_widget = sites_widget diff --git a/openpype/tools/settings/local_settings/widgets.py b/openpype/tools/settings/local_settings/widgets.py index b164f1b407..2733aef187 100644 --- a/openpype/tools/settings/local_settings/widgets.py +++ b/openpype/tools/settings/local_settings/widgets.py @@ -1,7 +1,6 @@ from Qt import QtWidgets, QtCore from openpype.tools.settings.settings.widgets import ( - ExpandingWidget, - SpacerWidget + ExpandingWidget ) @@ -56,7 +55,5 @@ class ProxyLabelWidget(QtWidgets.QWidget): __all__ = ( "ExpandingWidget", - "SpacerWidget", "Separator", - "SpacerWidget" ) diff --git a/openpype/tools/settings/local_settings/window.py b/openpype/tools/settings/local_settings/window.py index f22e397323..a00bc232f4 100644 --- a/openpype/tools/settings/local_settings/window.py +++ b/openpype/tools/settings/local_settings/window.py @@ -1,7 +1,7 @@ import logging from Qt import QtWidgets, QtGui -from ..settings import style +from openpype import style from openpype.settings.lib import ( get_local_settings, @@ -15,7 +15,6 @@ from openpype.api import ( from openpype.modules import ModulesManager from .widgets import ( - SpacerWidget, ExpandingWidget ) from .mongo_widget import OpenPypeMongoWidget @@ -58,8 +57,7 @@ class LocalSettingsWidget(QtWidgets.QWidget): self._create_app_ui() self._create_project_ui() - # Add spacer to main layout - self.main_layout.addWidget(SpacerWidget(self), 1) + self.main_layout.addStretch(1) def _create_pype_mongo_ui(self): pype_mongo_expand_widget = ExpandingWidget("OpenPype Mongo URL", self) @@ -210,7 +208,7 @@ class LocalSettingsWindow(QtWidgets.QWidget): footer_layout = QtWidgets.QHBoxLayout(footer) footer_layout.addWidget(reset_btn, 0) - footer_layout.addWidget(SpacerWidget(footer), 1) + footer_layout.addStretch(1) footer_layout.addWidget(save_btn, 0) main_layout = QtWidgets.QVBoxLayout(self) diff --git a/openpype/tools/settings/settings/__init__.py b/openpype/tools/settings/settings/__init__.py index 6b4cf94357..9eadd456b7 100644 --- a/openpype/tools/settings/settings/__init__.py +++ b/openpype/tools/settings/settings/__init__.py @@ -1,10 +1,8 @@ -from . import style from .window import MainWidget from .widgets import ProjectListWidget __all__ = ( - "style", "MainWidget", "ProjectListWidget" ) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index 92fffe6f9c..f8378ed18c 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -470,10 +470,9 @@ class GUIWidget(BaseWidget): self.entity_widget.add_widget_to_layout(self) def _create_label_ui(self): - self.setObjectName("LabelWidget") - label = self.entity["label"] label_widget = QtWidgets.QLabel(label, self) + label_widget.setObjectName("SettingsLabel") layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 5, 0, 5) @@ -481,7 +480,7 @@ class GUIWidget(BaseWidget): def _create_separator_ui(self): splitter_item = QtWidgets.QWidget(self) - splitter_item.setObjectName("SplitterItem") + splitter_item.setObjectName("Separator") splitter_item.setMinimumHeight(self.separator_height) splitter_item.setMaximumHeight(self.separator_height) @@ -513,10 +512,9 @@ class MockUpWidget(BaseWidget): child_invalid = False def create_ui(self): - self.setObjectName("LabelWidget") - label = "Mockup widget for entity {}".format(self.entity.path) label_widget = QtWidgets.QLabel(label, self) + label_widget.setObjectName("SettingsLabel") layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 5, 0, 5) diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py index 5f9051344d..a6e4154b2b 100644 --- a/openpype/tools/settings/settings/categories.py +++ b/openpype/tools/settings/settings/categories.py @@ -391,7 +391,9 @@ class SettingsCategoryWidget(QtWidgets.QWidget): while self.content_layout.count() != 0: widget = self.content_layout.itemAt(0).widget() - widget.hide() + if widget is not None: + widget.setVisible(False) + self.content_layout.removeWidget(widget) widget.deleteLater() diff --git a/openpype/tools/settings/settings/dict_conditional.py b/openpype/tools/settings/settings/dict_conditional.py index 3e3270cac9..2e1617f505 100644 --- a/openpype/tools/settings/settings/dict_conditional.py +++ b/openpype/tools/settings/settings/dict_conditional.py @@ -164,6 +164,7 @@ class DictConditionalWidget(BaseWidget): content_widget.setProperty("show_borders", show_borders) label_widget = QtWidgets.QLabel(self.entity.label) + label_widget.setObjectName("SettingsLabel") content_layout = QtWidgets.QGridLayout(content_widget) content_layout.setContentsMargins(5, 5, 5, 5) diff --git a/openpype/tools/settings/settings/dict_mutable_widget.py b/openpype/tools/settings/settings/dict_mutable_widget.py index 9afce7259e..294711b38a 100644 --- a/openpype/tools/settings/settings/dict_mutable_widget.py +++ b/openpype/tools/settings/settings/dict_mutable_widget.py @@ -3,7 +3,12 @@ from uuid import uuid4 from Qt import QtWidgets, QtCore, QtGui from .base import BaseWidget -from .lib import create_deffered_value_change_timer +from .lib import ( + create_deffered_value_change_timer, + create_add_btn, + create_remove_btn, + create_confirm_btn +) from .widgets import ( ExpandingWidget, IconButton @@ -21,92 +26,6 @@ KEY_INPUT_TOOLTIP = ( ) -class PaintHelper: - cached_icons = {} - - @classmethod - def _draw_image(cls, width, height, brush): - image = QtGui.QPixmap(width, height) - image.fill(QtCore.Qt.transparent) - - icon_path_stroker = QtGui.QPainterPathStroker() - icon_path_stroker.setCapStyle(QtCore.Qt.RoundCap) - icon_path_stroker.setJoinStyle(QtCore.Qt.RoundJoin) - icon_path_stroker.setWidth(height / 5) - - painter = QtGui.QPainter(image) - painter.setPen(QtCore.Qt.transparent) - painter.setBrush(brush) - rect = QtCore.QRect(0, 0, image.width(), image.height()) - fifteenth = rect.height() / 15 - # Left point - p1 = QtCore.QPoint( - rect.x() + (5 * fifteenth), - rect.y() + (9 * fifteenth) - ) - # Middle bottom point - p2 = QtCore.QPoint( - rect.center().x(), - rect.y() + (11 * fifteenth) - ) - # Top right point - p3 = QtCore.QPoint( - rect.x() + (10 * fifteenth), - rect.y() + (5 * fifteenth) - ) - - path = QtGui.QPainterPath(p1) - path.lineTo(p2) - path.lineTo(p3) - - stroked_path = icon_path_stroker.createStroke(path) - painter.drawPath(stroked_path) - - painter.end() - - return image - - @classmethod - def get_confirm_icon(cls, width, height): - key = "{}x{}-confirm_image".format(width, height) - icon = cls.cached_icons.get(key) - - if icon is None: - image = cls._draw_image(width, height, QtCore.Qt.white) - icon = QtGui.QIcon(image) - cls.cached_icons[key] = icon - return icon - - -def create_add_btn(parent): - add_btn = QtWidgets.QPushButton("+", parent) - add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - add_btn.setProperty("btn-type", "tool-item") - add_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - return add_btn - - -def create_remove_btn(parent): - remove_btn = QtWidgets.QPushButton("-", parent) - remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - remove_btn.setProperty("btn-type", "tool-item") - remove_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - return remove_btn - - -def create_confirm_btn(parent): - confirm_btn = QtWidgets.QPushButton(parent) - - icon = PaintHelper.get_confirm_icon( - BTN_FIXED_SIZE, BTN_FIXED_SIZE - ) - confirm_btn.setIcon(icon) - confirm_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - confirm_btn.setProperty("btn-type", "tool-item") - confirm_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - return confirm_btn - - class ModifiableDictEmptyItem(QtWidgets.QWidget): def __init__(self, entity_widget, store_as_list, parent): super(ModifiableDictEmptyItem, self).__init__(parent) @@ -375,7 +294,7 @@ class ModifiableDictItem(QtWidgets.QWidget): "fa.edit", QtCore.Qt.lightGray, QtCore.Qt.white ) edit_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - edit_btn.setProperty("btn-type", "tool-item-icon") + edit_btn.setObjectName("SettingsToolIconBtn") edit_btn.setFixedHeight(BTN_FIXED_SIZE) confirm_btn = create_confirm_btn(self) diff --git a/openpype/tools/settings/settings/images/__init__.py b/openpype/tools/settings/settings/images/__init__.py new file mode 100644 index 0000000000..3ad65e114a --- /dev/null +++ b/openpype/tools/settings/settings/images/__init__.py @@ -0,0 +1,19 @@ +import os +from Qt import QtGui + + +def get_image_path(image_filename): + return os.path.join( + os.path.dirname(os.path.abspath(__file__)), + image_filename + ) + + +def get_image(image_filename): + image_path = get_image_path(image_filename) + return QtGui.QImage(image_path) + + +def get_pixmap(image_filename): + image_path = get_image_path(image_filename) + return QtGui.QPixmap(image_path) diff --git a/openpype/tools/settings/settings/images/add.png b/openpype/tools/settings/settings/images/add.png new file mode 100644 index 0000000000..91ef720d32 Binary files /dev/null and b/openpype/tools/settings/settings/images/add.png differ diff --git a/openpype/tools/settings/settings/images/confirm.png b/openpype/tools/settings/settings/images/confirm.png new file mode 100644 index 0000000000..a0fdc66d3e Binary files /dev/null and b/openpype/tools/settings/settings/images/confirm.png differ diff --git a/openpype/tools/settings/settings/images/down.png b/openpype/tools/settings/settings/images/down.png new file mode 100644 index 0000000000..f78622922f Binary files /dev/null and b/openpype/tools/settings/settings/images/down.png differ diff --git a/openpype/tools/settings/settings/images/mask.png b/openpype/tools/settings/settings/images/mask.png new file mode 100644 index 0000000000..f10f00be2c Binary files /dev/null and b/openpype/tools/settings/settings/images/mask.png differ diff --git a/openpype/tools/settings/settings/images/remove.png b/openpype/tools/settings/settings/images/remove.png new file mode 100644 index 0000000000..79ea6eb973 Binary files /dev/null and b/openpype/tools/settings/settings/images/remove.png differ diff --git a/openpype/tools/settings/settings/images/up.png b/openpype/tools/settings/settings/images/up.png new file mode 100644 index 0000000000..4fccb08fe1 Binary files /dev/null and b/openpype/tools/settings/settings/images/up.png differ diff --git a/openpype/tools/settings/settings/item_widgets.py b/openpype/tools/settings/settings/item_widgets.py index a28bee8d36..2e00967a60 100644 --- a/openpype/tools/settings/settings/item_widgets.py +++ b/openpype/tools/settings/settings/item_widgets.py @@ -7,8 +7,8 @@ from .widgets import ( NumberSpinBox, GridLabelWidget, SettingsComboBox, - NiceCheckbox, SettingsPlainTextEdit, + SettingsNiceCheckbox, SettingsLineEdit ) from .multiselection_combobox import MultiSelectionComboBox @@ -21,6 +21,7 @@ from .base import ( BaseWidget, InputWidget ) + from openpype.widgets.sliders import NiceSlider from openpype.tools.settings import CHILD_OFFSET @@ -129,6 +130,7 @@ class DictImmutableKeysWidget(BaseWidget): content_widget.setProperty("show_borders", show_borders) label_widget = QtWidgets.QLabel(self.entity.label) + label_widget.setObjectName("SettingsLabel") content_layout = QtWidgets.QGridLayout(content_widget) content_layout.setContentsMargins(5, 5, 5, 5) @@ -324,12 +326,7 @@ class DictImmutableKeysWidget(BaseWidget): class BoolWidget(InputWidget): def _add_inputs_to_layout(self): - checkbox_height = self.style().pixelMetric( - QtWidgets.QStyle.PM_IndicatorHeight - ) - self.input_field = NiceCheckbox( - height=checkbox_height, parent=self.content_widget - ) + self.input_field = SettingsNiceCheckbox(parent=self.content_widget) self.content_layout.addWidget(self.input_field, 0) self.content_layout.addStretch(1) @@ -352,6 +349,9 @@ class BoolWidget(InputWidget): def _on_value_change(self): if self.ignore_input_changes: return + self.start_value_timer() + + def _on_value_change_timer(self): self.entity.set(self.input_field.isChecked()) diff --git a/openpype/tools/settings/settings/lib.py b/openpype/tools/settings/settings/lib.py index 577aaa5671..d12a14259a 100644 --- a/openpype/tools/settings/settings/lib.py +++ b/openpype/tools/settings/settings/lib.py @@ -1,5 +1,7 @@ from Qt import QtCore +from .widgets import SettingsToolBtn + # Offset of value change trigger in ms VALUE_CHANGE_OFFSET_MS = 300 @@ -16,3 +18,33 @@ def create_deffered_value_change_timer(callback): timer.setInterval(VALUE_CHANGE_OFFSET_MS) timer.timeout.connect(callback) return timer + + +def create_add_btn(parent): + add_btn = SettingsToolBtn("add", parent) + add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + return add_btn + + +def create_remove_btn(parent): + remove_btn = SettingsToolBtn("remove", parent) + remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + return remove_btn + + +def create_up_btn(parent): + remove_btn = SettingsToolBtn("up", parent) + remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + return remove_btn + + +def create_down_btn(parent): + add_btn = SettingsToolBtn("down", parent) + add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + return add_btn + + +def create_confirm_btn(parent): + remove_btn = SettingsToolBtn("confirm", parent) + remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + return remove_btn diff --git a/openpype/tools/settings/settings/list_item_widget.py b/openpype/tools/settings/settings/list_item_widget.py index 128af92631..cd1fd912ae 100644 --- a/openpype/tools/settings/settings/list_item_widget.py +++ b/openpype/tools/settings/settings/list_item_widget.py @@ -1,13 +1,17 @@ from Qt import QtWidgets, QtCore -from .base import InputWidget -from .widgets import ExpandingWidget from openpype.tools.settings import ( - BTN_FIXED_SIZE, CHILD_OFFSET ) -from avalon.vendor import qtawesome +from .base import InputWidget +from .widgets import ExpandingWidget +from .lib import ( + create_add_btn, + create_remove_btn, + create_up_btn, + create_down_btn +) class EmptyListItem(QtWidgets.QWidget): @@ -16,18 +20,11 @@ class EmptyListItem(QtWidgets.QWidget): self.entity_widget = entity_widget - add_btn = QtWidgets.QPushButton("+", self) - remove_btn = QtWidgets.QPushButton("-", self) + add_btn = create_add_btn(self) + remove_btn = create_remove_btn(self) - add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) remove_btn.setEnabled(False) - add_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - remove_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - - add_btn.setProperty("btn-type", "tool-item") - remove_btn.setProperty("btn-type", "tool-item") - layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) @@ -52,32 +49,10 @@ class ListItem(QtWidgets.QWidget): self.ignore_input_changes = entity_widget.ignore_input_changes - char_up = qtawesome.charmap("fa.angle-up") - char_down = qtawesome.charmap("fa.angle-down") - - add_btn = QtWidgets.QPushButton("+") - remove_btn = QtWidgets.QPushButton("-") - up_btn = QtWidgets.QPushButton(char_up) - down_btn = QtWidgets.QPushButton(char_down) - - font_up_down = qtawesome.font("fa", 13) - up_btn.setFont(font_up_down) - down_btn.setFont(font_up_down) - - add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - up_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - down_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - - add_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - remove_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - up_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - down_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - - add_btn.setProperty("btn-type", "tool-item") - remove_btn.setProperty("btn-type", "tool-item") - up_btn.setProperty("btn-type", "tool-item") - down_btn.setProperty("btn-type", "tool-item") + add_btn = create_add_btn(self) + remove_btn = create_remove_btn(self) + up_btn = create_up_btn(self) + down_btn = create_down_btn(self) add_btn.clicked.connect(self._on_add_clicked) remove_btn.clicked.connect(self._on_remove_clicked) diff --git a/openpype/tools/settings/settings/style/__init__.py b/openpype/tools/settings/settings/style/__init__.py deleted file mode 100644 index f1d9829a04..0000000000 --- a/openpype/tools/settings/settings/style/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import os -from openpype import resources - - -def load_stylesheet(): - style_path = os.path.join(os.path.dirname(__file__), "style.css") - with open(style_path, "r") as style_file: - stylesheet = style_file.read() - return stylesheet - - -def app_icon_path(): - return resources.get_openpype_icon_filepath() diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css deleted file mode 100644 index b77b575204..0000000000 --- a/openpype/tools/settings/settings/style/style.css +++ /dev/null @@ -1,453 +0,0 @@ -/* :root { - --border-color-: #464b54; -} - */ - - -QWidget { - color: #bfccd6; - background-color: #282C34; - font-size: 12px; - border-radius: 0px; -} - -QMenu { - border: 1px solid #555555; - background-color: #21252B; -} - -QMenu::item { - padding: 5px 10px 5px 10px; - border-left: 5px solid #313131; -} - -QMenu::item:selected { - border-left-color: #61839e; - background-color: #222d37; -} -QCheckBox { - spacing: 0px; -} -QCheckBox::indicator {} -QCheckBox::indicator:focus {} - -QLineEdit, QSpinBox, QDoubleSpinBox, QPlainTextEdit, QTextEdit { - border: 1px solid #464b54; - border-radius: 3px; - background-color: #21252B; -} - -QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QPlainTextEdit:disabled, QTextEdit:disabled, QPushButton:disabled { - background-color: #464b54; -} - -QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus, QTextEdit:focus { - border: 1px solid #839caf; -} - -QComboBox { - border: 1px solid #464b54; - border-radius: 3px; - padding: 2px 2px 4px 4px; - background: #21252B; -} - -QComboBox QAbstractItemView::item { - padding: 3px; -} - -QToolButton { - background: transparent; -} - -QLabel { - background: transparent; - color: #969b9e; -} -QLabel:hover {color: #b8c1c5;} - -QLabel[state="studio"] {color: #73C990;} -QLabel[state="studio"]:hover {color: #ffffff;} -QLabel[state="modified"] {color: #189aea;} -QLabel[state="modified"]:hover {color: #46b1f3;} -QLabel[state="overriden-modified"] {color: #189aea;} -QLabel[state="overriden-modified"]:hover {color: #46b1f3;} -QLabel[state="overriden"] {color: #ff8c1a;} -QLabel[state="overriden"]:hover {color: #ffa64d;} -QLabel[state="invalid"] {color: #ad2e2e;} -QLabel[state="invalid"]:hover {color: #ad2e2e;} - - -QWidget[input-state="studio"] {border-color: #858a94;} -QWidget[input-state="modified"] {border-color: #189aea;} -QWidget[input-state="overriden-modified"] {border-color: #189aea;} -QWidget[input-state="overriden"] {border-color: #ff8c1a;} -QWidget[input-state="invalid"] {border-color: #ad2e2e;} - -QPushButton { - border: 1px solid #aaaaaa; - border-radius: 3px; - padding: 5px; -} -QPushButton:hover { - background-color: #333840; - border: 1px solid #fff; - color: #fff; -} -QPushButton[btn-type="tool-item"] { - border: 1px solid #bfccd6; - border-radius: 10px; -} - -QPushButton[btn-type="tool-item"]:hover { - border-color: #189aea; - color: #46b1f3; - background-color: transparent; -} - -QPushButton[btn-type="tool-item-icon"] { - border: 0px solid #bfccd6; - background-color: transparent; -} - -QPushButton[btn-type="expand-toggle"] { - background: #21252B; -} - -/* SLider */ -QSlider::groove { - border: 1px solid #464b54; - border-radius: 0.3em; -} -QSlider::groove:horizontal { - height: 8px; -} -QSlider::groove:vertical { - width: 8px; -} -QSlider::handle { - width: 10px; - height: 10px; - - border-radius: 5px; -} -QSlider::handle:horizontal { - margin: -2px 0; -} -QSlider::handle:vertical { - margin: 0 -2px; -} - -#GroupWidget { - border-bottom: 1px solid #21252B; -} - -#ProjectListWidget QListView { - border: 1px solid #464b54; - background: #21252B; -} - -#ProjectListWidget QListView:disabled { - background: #282C34; -} - -#ProjectListWidget QListView::item:disabled { - color: #4e5254; -} - -#ProjectListWidget QLabel { - background: transparent; - font-weight: bold; -} - -#MultiSelectionComboBox { - font-size: 12px; -} - -#DictKey[state="studio"] {border-color: #464b54;} -#DictKey[state="modified"] {border-color: #189aea;} -#DictKey[state="overriden"] {border-color: #00f;} -#DictKey[state="overriden-modified"] {border-color: #0f0;} -#DictKey[state="invalid"] {border-color: #ad2e2e;} - -#DictLabel { - font-weight: bold; -} - -#ContentWidget { - background-color: transparent; -} -#ContentWidget[content_state="hightlighted"] { - background-color: rgba(19, 26, 32, 15%); -} - -#SideLineWidget { - background-color: #333942; - border-style: solid; - border-color: #4e5254; - border-left-width: 3px; - border-bottom-width: 0px; - border-right-width: 0px; - border-top-width: 0px; -} - -#SideLineWidget:hover { - border-color: #7d8386; -} - -#SideLineWidget[state="child-studio"] {border-color: #56a06f;} -#SideLineWidget[state="child-studio"]:hover {border-color: #73C990;} - -#SideLineWidget[state="child-modified"] {border-color: #106aa2;} -#SideLineWidget[state="child-modified"]:hover {border-color: #189aea;} - -#SideLineWidget[state="child-invalid"] {border-color: #ad2e2e;} -#SideLineWidget[state="child-invalid"]:hover {border-color: #c93636;} - -#SideLineWidget[state="child-overriden"] {border-color: #e67300;} -#SideLineWidget[state="child-overriden"]:hover {border-color: #ff8c1a;} - -#SideLineWidget[state="child-overriden-modified"] {border-color: #106aa2;} -#SideLineWidget[state="child-overriden-modified"]:hover {border-color: #189aea;} - -#MainWidget { - background: #141a1f; -} - -#DictAsWidgetBody { - background: transparent; -} -#DictAsWidgetBody[show_borders="1"] { - border: 1px solid #4e5254; - border-radius: 5px; -} - -#SplitterItem { - background-color: #21252B; -} - -#ShadowWidget { - font-size: 36pt; -} -QTabWidget::pane { - border-top-style: none; -} - -QTabBar { - background: transparent; -} - -QTabBar::tab { - border-top-left-radius: 4px; - border-top-right-radius: 4px; - padding: 5px; -} - -QTabBar::tab:selected { - background: #282C34; - border-color: #9B9B9B; - border-bottom-color: #C2C7CB; -} - -QTabBar::tab:!selected { - margin-top: 2px; - background: #21252B; -} - -QTabBar::tab:!selected:hover { - background: #333840; -} - -QTabBar::tab:first:selected { - margin-left: 0; -} - -QTabBar::tab:last:selected { - margin-right: 0; -} - -QTabBar::tab:only-one { - margin: 0; -} - -QScrollBar:horizontal { - height: 15px; - margin: 3px 15px 3px 15px; - border: 1px transparent #21252B; - border-radius: 4px; - background-color: #21252B; -} - -QScrollBar::handle:horizontal { - background-color: #4B5362; - min-width: 5px; - border-radius: 4px; -} - -QScrollBar::add-line:horizontal { - margin: 0px 3px 0px 3px; - border-image: url(:/qss_icons/rc/right_arrow_disabled.png); - width: 10px; - height: 10px; - subcontrol-position: right; - subcontrol-origin: margin; -} - -QScrollBar::sub-line:horizontal { - margin: 0px 3px 0px 3px; - border-image: url(:/qss_icons/rc/left_arrow_disabled.png); - height: 10px; - width: 10px; - subcontrol-position: left; - subcontrol-origin: margin; -} - -QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on { - border-image: url(:/qss_icons/rc/right_arrow.png); - height: 10px; - width: 10px; - subcontrol-position: right; - subcontrol-origin: margin; -} - -QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { - border-image: url(:/qss_icons/rc/left_arrow.png); - height: 10px; - width: 10px; - subcontrol-position: left; - subcontrol-origin: margin; -} - -QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { - background: none; -} - -QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { - background: none; -} - -QScrollBar:vertical { - background-color: #21252B; - width: 15px; - margin: 15px 3px 15px 3px; - border: 1px transparent #21252B; - border-radius: 4px; -} - -QScrollBar::handle:vertical { - background-color: #4B5362; - min-height: 5px; - border-radius: 4px; -} - -QScrollBar::sub-line:vertical { - margin: 3px 0px 3px 0px; - border-image: url(:/qss_icons/rc/up_arrow_disabled.png); - height: 10px; - width: 10px; - subcontrol-position: top; - subcontrol-origin: margin; -} - -QScrollBar::add-line:vertical { - margin: 3px 0px 3px 0px; - border-image: url(:/qss_icons/rc/down_arrow_disabled.png); - height: 10px; - width: 10px; - subcontrol-position: bottom; - subcontrol-origin: margin; -} - -QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on { - - border-image: url(:/qss_icons/rc/up_arrow.png); - height: 10px; - width: 10px; - subcontrol-position: top; - subcontrol-origin: margin; -} - - -QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { - border-image: url(:/qss_icons/rc/down_arrow.png); - height: 10px; - width: 10px; - subcontrol-position: bottom; - subcontrol-origin: margin; -} - -QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { - background: none; -} - - -QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { - background: none; -} - -QTableView -{ - border: 1px solid #444; - gridline-color: #6c6c6c; - background-color: #201F1F; - alternate-background-color:#21252B; -} - -QHeaderView -{ - border: 1px transparent; - border-radius: 2px; - margin: 0px; - padding: 0px; -} - -QHeaderView::section { - background-color: #21252B; - /*color: silver;*/ - padding: 4px; - border: 1px solid #6c6c6c; - border-radius: 0px; - text-align: center; - color: #969b9e; - font-weight: bold; -} - -QAbstractItemView::item:pressed { - background: #78879b; - color: #FFFFFF; -} - -QAbstractItemView::item:selected:active { - background: #3d8ec9; -} -QAbstractItemView::item:selected:!active { - background: #3d8ec9; -} - -#BreadcrumbsPathInput { - padding: 2px; - font-size: 9pt; -} - -#BreadcrumbsButton { - padding-right: 12px; - font-size: 9pt; -} - -#BreadcrumbsButton[empty="1"] { - padding-right: 0px; -} - -#BreadcrumbsButton::menu-button { - width: 12px; - background: rgba(127, 127, 127, 60); -} -#BreadcrumbsButton::menu-button:hover { - background: rgba(127, 127, 127, 90); -} - -#BreadcrumbsPanel { - border: 1px solid #4e5254; - border-radius: 5px; - background: #21252B;; -} diff --git a/openpype/tools/settings/settings/widgets.py b/openpype/tools/settings/settings/widgets.py index 710884e9e5..7a7213fa66 100644 --- a/openpype/tools/settings/settings/widgets.py +++ b/openpype/tools/settings/settings/widgets.py @@ -6,7 +6,16 @@ from avalon.mongodb import ( AvalonMongoDB ) +from openpype.style import get_objected_colors +from openpype.tools.utils.widgets import ImageButton +from openpype.tools.utils.lib import paint_image_with_color + +from openpype.widgets.nice_checkbox import NiceCheckbox from openpype.settings.lib import get_system_settings +from .images import ( + get_pixmap, + get_image +) from .constants import ( DEFAULT_PROJECT_LABEL, PROJECT_NAME_ROLE, @@ -31,6 +40,78 @@ class SettingsPlainTextEdit(QtWidgets.QPlainTextEdit): self.focused_in.emit() +class SettingsToolBtn(ImageButton): + _mask_pixmap = None + _cached_icons = {} + + def __init__(self, btn_type, parent): + super(SettingsToolBtn, self).__init__(parent) + + icon, hover_icon = self._get_icon_type(btn_type) + + self.setIcon(icon) + + self._icon = icon + self._hover_icon = hover_icon + + @classmethod + def _get_icon_type(cls, btn_type): + if btn_type not in cls._cached_icons: + settings_colors = get_objected_colors()["settings"] + normal_color = settings_colors["image-btn"].get_qcolor() + hover_color = settings_colors["image-btn-hover"].get_qcolor() + disabled_color = settings_colors["image-btn-disabled"].get_qcolor() + + image = get_image("{}.png".format(btn_type)) + + pixmap = paint_image_with_color(image, normal_color) + hover_pixmap = paint_image_with_color(image, hover_color) + disabled_pixmap = paint_image_with_color(image, disabled_color) + + icon = QtGui.QIcon(pixmap) + hover_icon = QtGui.QIcon(hover_pixmap) + icon.addPixmap( + disabled_pixmap, QtGui.QIcon.Disabled, QtGui.QIcon.On + ) + icon.addPixmap( + disabled_pixmap, QtGui.QIcon.Disabled, QtGui.QIcon.Off + ) + hover_icon.addPixmap( + disabled_pixmap, QtGui.QIcon.Disabled, QtGui.QIcon.On + ) + hover_icon.addPixmap( + disabled_pixmap, QtGui.QIcon.Disabled, QtGui.QIcon.Off + ) + cls._cached_icons[btn_type] = icon, hover_icon + return cls._cached_icons[btn_type] + + def enterEvent(self, event): + self.setIcon(self._hover_icon) + super(SettingsToolBtn, self).enterEvent(event) + + def leaveEvent(self, event): + self.setIcon(self._icon) + super(SettingsToolBtn, self).leaveEvent(event) + + @classmethod + def _get_mask_pixmap(cls): + if cls._mask_pixmap is None: + mask_pixmap = get_pixmap("mask.png") + cls._mask_pixmap = mask_pixmap + return cls._mask_pixmap + + def _change_size(self): + super(SettingsToolBtn, self)._change_size() + size = self.iconSize() + scaled = self._get_mask_pixmap().scaled( + size.width(), + size.height(), + QtCore.Qt.IgnoreAspectRatio, + QtCore.Qt.SmoothTransformation + ) + self.setMask(scaled.mask()) + + class ShadowWidget(QtWidgets.QWidget): def __init__(self, message, parent): super(ShadowWidget, self).__init__(parent) @@ -132,9 +213,14 @@ class SettingsComboBox(QtWidgets.QComboBox): def __init__(self, *args, **kwargs): super(SettingsComboBox, self).__init__(*args, **kwargs) + delegate = QtWidgets.QStyledItemDelegate() + self.setItemDelegate(delegate) + self.currentIndexChanged.connect(self._on_change) self.setFocusPolicy(QtCore.Qt.StrongFocus) + self._delegate = delegate + def wheelEvent(self, event): if self.hasFocus(): return super(SettingsComboBox, self).wheelEvent(event) @@ -180,14 +266,14 @@ class ExpandingWidget(QtWidgets.QWidget): button_size = QtCore.QSize(5, 5) button_toggle = QtWidgets.QToolButton(parent=side_line_widget) - button_toggle.setProperty("btn-type", "expand-toggle") + button_toggle.setObjectName("ExpandToggleBtn") button_toggle.setIconSize(button_size) button_toggle.setArrowType(QtCore.Qt.RightArrow) button_toggle.setCheckable(True) button_toggle.setChecked(False) label_widget = QtWidgets.QLabel(label, parent=side_line_widget) - label_widget.setObjectName("DictLabel") + label_widget.setObjectName("ExpandLabel") before_label_widget = QtWidgets.QWidget(side_line_widget) before_label_layout = QtWidgets.QHBoxLayout(before_label_widget) @@ -381,6 +467,7 @@ class GridLabelWidget(QtWidgets.QWidget): self.properties = {} label_widget = QtWidgets.QLabel(label, self) + label_widget.setObjectName("SettingsLabel") label_proxy_layout = QtWidgets.QHBoxLayout() label_proxy_layout.setContentsMargins(0, 0, 0, 0) @@ -415,197 +502,12 @@ class GridLabelWidget(QtWidgets.QWidget): return super(GridLabelWidget, self).mouseReleaseEvent(event) -class NiceCheckboxMoveWidget(QtWidgets.QFrame): - def __init__(self, height, border_width, parent): - super(NiceCheckboxMoveWidget, self).__init__(parent=parent) - - self.checkstate = False - - self.half_size = int(height / 2) - self.full_size = self.half_size * 2 - self.border_width = border_width - self.setFixedHeight(self.full_size) - self.setFixedWidth(self.full_size) - - self.setStyleSheet(( - "background: #444444;border-style: none;" - "border-radius: {};border-width:{}px;" - ).format(self.half_size, self.border_width)) - - def update_position(self): - parent_rect = self.parent().rect() - if self.checkstate is True: - pos_x = ( - parent_rect.x() - + parent_rect.width() - - self.full_size - - self.border_width - ) - else: - pos_x = parent_rect.x() + self.border_width - - pos_y = parent_rect.y() + int( - parent_rect.height() / 2 - self.half_size - ) - self.setGeometry(pos_x, pos_y, self.width(), self.height()) - - def state_offset(self): - diff_x = ( - self.parent().rect().width() - - self.full_size - - (2 * self.border_width) - ) - return QtCore.QPoint(diff_x, 0) - - def change_position(self, checkstate): - self.checkstate = checkstate - - self.update_position() - - def resizeEvent(self, event): - super().resizeEvent(event) - self.update_position() - - -class NiceCheckbox(QtWidgets.QFrame): - stateChanged = QtCore.Signal(int) - checked_bg_color = QtGui.QColor(69, 128, 86) - unchecked_bg_color = QtGui.QColor(170, 80, 80) +class SettingsNiceCheckbox(NiceCheckbox): focused_in = QtCore.Signal() - def set_bg_color(self, color): - self._bg_color = color - self.setStyleSheet(self._stylesheet_template.format( - color.red(), color.green(), color.blue() - )) - - def bg_color(self): - return self._bg_color - - bgcolor = QtCore.Property(QtGui.QColor, bg_color, set_bg_color) - - def __init__(self, checked=True, height=30, *args, **kwargs): - super(NiceCheckbox, self).__init__(*args, **kwargs) - - self._checkstate = checked - if checked: - bg_color = self.checked_bg_color - else: - bg_color = self.unchecked_bg_color - - self.half_height = int(height / 2) - height = self.half_height * 2 - tenth_height = int(height / 10) - - self.setFixedHeight(height) - self.setFixedWidth((height - tenth_height) * 2) - - move_item_size = height - (2 * tenth_height) - - self.move_item = NiceCheckboxMoveWidget( - move_item_size, tenth_height, self - ) - self.move_item.change_position(self._checkstate) - - self._stylesheet_template = ( - "border-radius: {}px;" - "border-width: {}px;" - "background: #333333;" - "border-style: solid;" - "border-color: #555555;" - ).format(self.half_height, tenth_height) - self._stylesheet_template += "background: rgb({},{},{});" - - self.set_bg_color(bg_color) - - def resizeEvent(self, event): - super(NiceCheckbox, self).resizeEvent(event) - self.move_item.update_position() - - def show(self, *args, **kwargs): - super(NiceCheckbox, self).show(*args, **kwargs) - self.move_item.update_position() - - def checkState(self): - if self._checkstate: - return QtCore.Qt.Checked - else: - return QtCore.Qt.Unchecked - - def _on_checkstate_change(self): - self.stateChanged.emit(self.checkState()) - - move_start_value = self.move_item.pos() - offset = self.move_item.state_offset() - if self._checkstate is True: - move_end_value = move_start_value + offset - else: - move_end_value = move_start_value - offset - move_animation = QtCore.QPropertyAnimation( - self.move_item, b"pos", self - ) - move_animation.setDuration(150) - move_animation.setEasingCurve(QtCore.QEasingCurve.OutQuad) - move_animation.setStartValue(move_start_value) - move_animation.setEndValue(move_end_value) - - color_animation = QtCore.QPropertyAnimation( - self, b"bgcolor" - ) - color_animation.setDuration(150) - if self._checkstate is True: - color_animation.setStartValue(self.unchecked_bg_color) - color_animation.setEndValue(self.checked_bg_color) - else: - color_animation.setStartValue(self.checked_bg_color) - color_animation.setEndValue(self.unchecked_bg_color) - - anim_group = QtCore.QParallelAnimationGroup(self) - anim_group.addAnimation(move_animation) - anim_group.addAnimation(color_animation) - - def _finished(): - self.move_item.change_position(self._checkstate) - - anim_group.finished.connect(_finished) - anim_group.start() - - def isChecked(self): - return self._checkstate - - def setChecked(self, checked): - if checked == self._checkstate: - return - self._checkstate = checked - self._on_checkstate_change() - - def setCheckState(self, state=None): - if state is None: - checkstate = not self._checkstate - elif state == QtCore.Qt.Checked: - checkstate = True - elif state == QtCore.Qt.Unchecked: - checkstate = False - else: - return - - if checkstate == self._checkstate: - return - - self._checkstate = checkstate - - self._on_checkstate_change() - def mousePressEvent(self, event): self.focused_in.emit() - super(NiceCheckbox, self).mousePressEvent(event) - - def mouseReleaseEvent(self, event): - if event.button() == QtCore.Qt.LeftButton: - self.setCheckState() - event.accept() - return - return super(NiceCheckbox, self).mouseReleaseEvent(event) + super(SettingsNiceCheckbox, self).mousePressEvent(event) class ProjectModel(QtGui.QStandardItemModel): diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index 4e88301349..fd0cd1d7cd 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -5,7 +5,7 @@ from .categories import ( ProjectWidget ) from .widgets import ShadowWidget, RestartDialog -from . import style +from openpype import style from openpype.lib import is_admin_password_required from openpype.widgets import PasswordDialog @@ -25,7 +25,7 @@ class MainWidget(QtWidgets.QWidget): self._password_dialog = None - self.setObjectName("MainWidget") + self.setObjectName("SettingsMainWidget") self.setWindowTitle("OpenPype Settings") self.resize(self.widget_width, self.widget_height) diff --git a/openpype/tools/utils/lib.py b/openpype/tools/utils/lib.py index 8246d606b7..6742df8557 100644 --- a/openpype/tools/utils/lib.py +++ b/openpype/tools/utils/lib.py @@ -25,6 +25,34 @@ def center_window(window): window.move(geo.topLeft()) +def paint_image_with_color(image, color): + """Redraw image with single color using it's alpha. + + It is expected that input image is singlecolor image with alpha. + + Args: + image (QImage): Loaded image with alpha. + color (QColor): Color that will be used to paint image. + """ + width = image.width() + height = image.height() + + alpha_mask = image.createAlphaMask() + alpha_region = QtGui.QRegion(QtGui.QBitmap.fromImage(alpha_mask)) + + pixmap = QtGui.QPixmap(width, height) + pixmap.fill(QtCore.Qt.transparent) + + painter = QtGui.QPainter(pixmap) + painter.setClipRegion(alpha_region) + painter.setPen(QtCore.Qt.NoPen) + painter.setBrush(color) + painter.drawRect(QtCore.QRect(0, 0, width, height)) + painter.end() + + return pixmap + + def format_version(value, hero_version=False): """Formats integer to displayable version name""" label = "v{0:03d}".format(value) diff --git a/openpype/tools/utils/widgets.py b/openpype/tools/utils/widgets.py index ea80636d1a..009c1dc506 100644 --- a/openpype/tools/utils/widgets.py +++ b/openpype/tools/utils/widgets.py @@ -30,6 +30,32 @@ class PlaceholderLineEdit(QtWidgets.QLineEdit): self.setPalette(filter_palette) +class ImageButton(QtWidgets.QPushButton): + """PushButton with icon and size of font. + + Using font metrics height as icon size reference. + + TODO: + - handle changes of screen (different resolution) + """ + + def __init__(self, *args, **kwargs): + super(ImageButton, self).__init__(*args, **kwargs) + self.setObjectName("ImageButton") + + def _change_size(self): + font_height = self.fontMetrics().height() + self.setIconSize(QtCore.QSize(font_height, font_height)) + + def showEvent(self, event): + super(ImageButton, self).showEvent(event) + + self._change_size() + + def sizeHint(self): + return self.iconSize() + + class OptionalMenu(QtWidgets.QMenu): """A subclass of `QtWidgets.QMenu` to work with `OptionalAction` diff --git a/openpype/widgets/nice_checkbox.py b/openpype/widgets/nice_checkbox.py index d550f361ff..ccd079c0fb 100644 --- a/openpype/widgets/nice_checkbox.py +++ b/openpype/widgets/nice_checkbox.py @@ -1,11 +1,18 @@ from math import floor, sqrt, ceil from Qt import QtWidgets, QtCore, QtGui +from openpype.style import get_objected_colors + class NiceCheckbox(QtWidgets.QFrame): stateChanged = QtCore.Signal(int) clicked = QtCore.Signal() + _checked_bg_color = None + _unchecked_bg_color = None + _checker_color = None + _checker_hover_color = None + def __init__(self, checked=False, draw_icons=False, parent=None): super(NiceCheckbox, self).__init__(parent) @@ -41,12 +48,6 @@ class NiceCheckbox(QtWidgets.QFrame): self._pressed = False self._under_mouse = False - self.checked_bg_color = QtGui.QColor(67, 181, 129) - self.unchecked_bg_color = QtGui.QColor(79, 79, 79) - - self.checker_checked_color = QtGui.QColor(255, 255, 255) - self.checker_unchecked_color = self.checker_checked_color - self.icon_scale_factor = sqrt(2) / 2 icon_path_stroker = QtGui.QPainterPathStroker() @@ -58,6 +59,37 @@ class NiceCheckbox(QtWidgets.QFrame): self._animation_timer.timeout.connect(self._on_animation_timeout) self._base_size = QtCore.QSize(90, 50) + self._load_colors() + + @classmethod + def _load_colors(cls): + if cls._checked_bg_color is not None: + return + + colors_data = get_objected_colors() + colors_info = colors_data["nice-checkbox"] + + cls._checked_bg_color = colors_info["bg-checked"].get_qcolor() + cls._unchecked_bg_color = colors_info["bg-unchecked"].get_qcolor() + + cls._checker_color = colors_info["bg-checker"].get_qcolor() + cls._checker_hover_color = colors_info["bg-checker-hover"].get_qcolor() + + @property + def checked_bg_color(self): + return self._checked_bg_color + + @property + def unchecked_bg_color(self): + return self._unchecked_bg_color + + @property + def checker_color(self): + return self._checker_color + + @property + def checker_hover_color(self): + return self._checker_hover_color def setTristate(self, tristate=True): if self._is_tristate != tristate: @@ -73,15 +105,6 @@ class NiceCheckbox(QtWidgets.QFrame): self._draw_icons = draw_icons self.repaint() - def _checkbox_size_hint(self): - checkbox_height = self.style().pixelMetric( - QtWidgets.QStyle.PM_IndicatorHeight - ) - checkbox_height += checkbox_height % 2 - width = (2 * checkbox_height) - (checkbox_height / 5) - new_size = QtCore.QSize(width, checkbox_height) - return new_size - def sizeHint(self): height = self.fontMetrics().height() width = self.get_width_hint_by_height(height) @@ -159,7 +182,7 @@ class NiceCheckbox(QtWidgets.QFrame): if self._animation_timer.isActive(): self._animation_timer.stop() - if self.isEnabled(): + if self.isVisible() and self.isEnabled(): # Start animation self._animation_timer.start(self._animation_timeout) else: @@ -235,14 +258,16 @@ class NiceCheckbox(QtWidgets.QFrame): def _on_animation_timeout(self): if self._checkstate == QtCore.Qt.Checked: - self._current_step += 1 if self._current_step == self._steps: self._animation_timer.stop() + return + self._current_step += 1 elif self._checkstate == QtCore.Qt.Unchecked: - self._current_step -= 1 if self._current_step == 0: self._animation_timer.stop() + return + self._current_step -= 1 else: if self._current_step < self._middle_step: @@ -291,11 +316,9 @@ class NiceCheckbox(QtWidgets.QFrame): # Draw inner background if self._current_step == self._steps: bg_color = self.checked_bg_color - checker_color = self.checker_checked_color elif self._current_step == 0: bg_color = self.unchecked_bg_color - checker_color = self.checker_unchecked_color else: offset_ratio = self._current_step / self._steps @@ -305,11 +328,6 @@ class NiceCheckbox(QtWidgets.QFrame): self.unchecked_bg_color, offset_ratio ) - checker_color = self.steped_color( - self.checker_checked_color, - self.checker_unchecked_color, - offset_ratio - ) margins_ratio = self._checker_margins_divider if margins_ratio > 0: @@ -359,52 +377,14 @@ class NiceCheckbox(QtWidgets.QFrame): checker_rect = QtCore.QRect(pos_x, pos_y, checker_size, checker_size) under_mouse = self.isEnabled() and self._under_mouse - - shadow_x = checker_rect.x() - shadow_y = checker_rect.y() + margin_size_c - shadow_size = min( - frame_rect.right() - shadow_x, - frame_rect.bottom() - shadow_y, - checker_size + (2 * margin_size_c) - ) - shadow_rect = QtCore.QRect( - checker_rect.x(), - shadow_y, - shadow_size, - shadow_size - ) - - shadow_brush = QtGui.QRadialGradient( - shadow_rect.center(), - shadow_rect.height() / 2 - ) - shadow_brush.setColorAt(0.6, QtCore.Qt.black) - shadow_brush.setColorAt(1, QtCore.Qt.transparent) - - painter.setPen(QtCore.Qt.transparent) - painter.setBrush(shadow_brush) - painter.drawEllipse(shadow_rect) + if under_mouse: + checker_color = self.checker_hover_color + else: + checker_color = self.checker_color painter.setBrush(checker_color) painter.drawEllipse(checker_rect) - if under_mouse: - adjust = margin_size_c - if adjust < 1 and checker_rect.height() > 4: - adjust = 1 - - smaller_checker_rect = checker_rect.adjusted( - adjust, adjust, -adjust, -adjust - ) - gradient = QtGui.QLinearGradient( - smaller_checker_rect.bottomRight(), - smaller_checker_rect.topLeft() - ) - gradient.setColorAt(0, checker_color) - gradient.setColorAt(1, checker_color.darker(155)) - painter.setBrush(gradient) - painter.drawEllipse(smaller_checker_rect) - if self._draw_icons: painter.setBrush(bg_color) icon_path = self._get_icon_path(painter, checker_rect)