├── PySideLayoutTool ├── Plugins │ ├── __init__.py │ └── TestingWidgetPlugin │ │ ├── __init__.py │ │ ├── Common │ │ ├── __init__.py │ │ └── WidgetTestClass.py │ │ └── TestingWidgetPlugin.uiplugin ├── resources │ ├── __init__.py │ ├── data │ │ ├── __init__.py │ │ ├── PySideLayoutTool.uiproject │ │ └── CHANGELOG.md │ ├── Icons │ │ ├── checkerPattern.png │ │ ├── checkerPatternAlpha.png │ │ ├── solid_line.svg │ │ ├── border_style_solid_sep.svg │ │ ├── chevron_arrow_right.svg │ │ ├── border_style_dashed_sep.svg │ │ ├── chevron_arrow_down.svg │ │ ├── arrow_chevron_up.svg │ │ ├── comment.svg │ │ ├── arrow_chevron_down.svg │ │ ├── move_right_arrow.svg │ │ ├── move_left_arrow.svg │ │ ├── checkbox_unchecked.svg │ │ ├── checkbox_unchecked_disable.svg │ │ ├── add_file.svg │ │ ├── lock_unlocked.svg │ │ ├── checkbox_checked.svg │ │ ├── vertical_alt.svg │ │ ├── arrow_down_box.svg │ │ ├── arrow_left_box.svg │ │ ├── lock_locked.svg │ │ ├── normal_close.svg │ │ ├── normal_close_pressed.svg │ │ ├── normal_folder.svg │ │ ├── folder_minus.svg │ │ ├── folder_plus.svg │ │ ├── eye_view.svg │ │ ├── menu_list_display.svg │ │ ├── zoom_out.svg │ │ ├── zoom_in.svg │ │ ├── arrow_exchange_v.svg │ │ ├── splitter_vertical_alt_2.svg │ │ ├── color_picker.svg │ │ ├── arrow_exchange_alt.svg │ │ └── setting_gear_icon.svg │ └── pysidelayouticons.qrc ├── saved │ └── __init__.py ├── UIEditorLib │ ├── __init__.py │ ├── UIFunctions.py │ ├── EditorDataManger.py │ ├── RootWidget.py │ ├── UIEditorIconFactory.py │ ├── StringValidatorClass.py │ ├── UIEditorFactory.py │ ├── UIEditorWrapper.py │ ├── WindowsModule.py │ ├── boilerplate_class.py │ ├── TreeItemInterface.py │ ├── LayoutConstructorClass.py │ ├── UIEditorProperty.py │ ├── TemplateDisplayUI.py │ └── TemplateBuildClass.py ├── UIEditorTemplates │ ├── __init__.py │ ├── Common │ │ ├── __init__.py │ │ ├── ButtonTemplate │ │ │ ├── __init__.py │ │ │ ├── ButtonClass.py │ │ │ └── ButtonWidgetClass.py │ │ ├── ColorTemplate │ │ │ ├── __init__.py │ │ │ └── ColorClass.py │ │ ├── FileTemplate │ │ │ ├── __init__.py │ │ │ ├── FileClass.py │ │ │ └── FileWidgetClsss.py │ │ ├── LabelTemplate │ │ │ ├── __init__.py │ │ │ ├── LabelClass.py │ │ │ └── LabelSwitchWidget.py │ │ ├── RampTemplate │ │ │ ├── __init__.py │ │ │ └── RampClass.py │ │ ├── SliderTemplate │ │ │ ├── __init__.py │ │ │ ├── SliderWidgetClass.py │ │ │ └── SliderClass.py │ │ ├── CheckBoxTemplate │ │ │ ├── __init__.py │ │ │ ├── CheckboxWidgetClass.py │ │ │ ├── CheckboxProperty.py │ │ │ └── CheckboxClass.py │ │ ├── ClampRangeTemplate │ │ │ ├── __init__.py │ │ │ ├── ClampRangeWidgetClass.py │ │ │ ├── ClampRangeProperty.py │ │ │ └── ClampRangeClass.py │ │ ├── ComboBoxTemplate │ │ │ ├── __init__.py │ │ │ ├── ComboBoxWidgetClass.py │ │ │ ├── ComboBoxClass.py │ │ │ └── ComboBoxProperty.py │ │ ├── DictionaryTemplate │ │ │ ├── __init__.py │ │ │ ├── DictionaryClass.py │ │ │ ├── DictionaryWidgetProperty.py │ │ │ └── DictionaryWidgetClass.py │ │ ├── LineEditTemplate │ │ │ └── __init__.py │ │ ├── SeparatorTemplate │ │ │ ├── __init__.py │ │ │ ├── SeparatorWidgetClass.py │ │ │ └── SeparatorClass.py │ │ └── StringEditTemplate │ │ │ ├── __init__.py │ │ │ ├── StringEditProperty.py │ │ │ ├── StringEditClass.py │ │ │ └── StringEditWidgetClass.py │ ├── Folder │ │ ├── __init__.py │ │ ├── TabFolderTemplate │ │ │ ├── __init__.py │ │ │ └── FolderTabClasses.py │ │ ├── SimpleFolderTemplate │ │ │ ├── __init__.py │ │ │ └── SimpleFolderClass.py │ │ └── CollapisbleFolderTemplate │ │ │ ├── __init__.py │ │ │ └── CollapisbleFolderClass.py │ ├── Layout │ │ ├── __init__.py │ │ └── CustomFormLayout.py │ ├── UIEditorTemplates.uiplugin │ └── IconRegistration.py ├── UIEditorWindows │ ├── __init__.py │ ├── NotificationSetup.py │ ├── MainLayoutWindow.py │ ├── InitWindow.py │ └── TabScript.py └── main.py ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── CHANGELOG.md ├── setup.py └── LICENSE.md /PySideLayoutTool/Plugins/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/saved/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorLib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/data/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorWindows/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Folder/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Layout/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/checkerPattern.png: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/Plugins/TestingWidgetPlugin/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/checkerPatternAlpha.png: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/Plugins/TestingWidgetPlugin/Common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ButtonTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ColorTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/FileTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/LabelTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/RampTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/SliderTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/CheckBoxTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ClampRangeTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ComboBoxTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/DictionaryTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/LineEditTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/SeparatorTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/StringEditTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Folder/TabFolderTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Folder/SimpleFolderTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Folder/CollapisbleFolderTemplate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: JonathanCortez 4 | 5 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/solid_line.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/border_style_solid_sep.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/Plugins/TestingWidgetPlugin/TestingWidgetPlugin.uiplugin: -------------------------------------------------------------------------------- 1 | { 2 | "Categories": 3 | [ 4 | { 5 | "Name": "Common", 6 | "Modules": 7 | [ 8 | "WidgetTestClass" 9 | ] 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/data/PySideLayoutTool.uiproject: -------------------------------------------------------------------------------- 1 | { 2 | "Version": 0.1, 3 | "Modules": [ 4 | { 5 | "Name": "UIEditorTemplates" 6 | } 7 | ], 8 | "Plugins": [ 9 | { 10 | "Name": "TestingWidgetPlugin", 11 | "Enable": false 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/chevron_arrow_right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorLib/UIFunctions.py: -------------------------------------------------------------------------------- 1 | from . import WindowsModule 2 | 3 | 4 | def editor(name: str, category: str): 5 | return UIWindowManger.WindowsManger.get_Stack(name, category)[name + '_editor'] 6 | 7 | 8 | def layout(name: str, category: str): 9 | return UIWindowManger.WindowsManger.get_Stack(name, category)[name + '_layout'] 10 | 11 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/border_style_dashed_sep.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/chevron_arrow_down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/CheckBoxTemplate/CheckboxWidgetClass.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets, QtCore 2 | 3 | class CheckBoxWidget(QtWidgets.QCheckBox): 4 | 5 | def __init__(self,checkstate=False): 6 | super(CheckBoxWidget, self).__init__() 7 | self.setMinimumHeight(30) 8 | self.setMaximumHeight(30) 9 | self.setChecked(checkstate) 10 | 11 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_chevron_up.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/comment.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_chevron_down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/move_right_arrow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/move_left_arrow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/checkbox_unchecked.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/checkbox_unchecked_disable.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorLib/EditorDataManger.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List, Any 2 | 3 | #TODO: Intergrate this module to work with the whole process of the tool as are reflecting system. 4 | 5 | class DataManager: 6 | 7 | __data : Dict[str, Any] = {} 8 | 9 | @classmethod 10 | def add_data(cls, key_name : str, value : Any): 11 | cls.__data[key_name] = value 12 | 13 | @classmethod 14 | def get_data(cls, name : str): 15 | return cls.__data[name] 16 | 17 | @classmethod 18 | def get_all_registered_data(cls) -> List[str]: 19 | return list(cls.__data.keys()) -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/add_file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/lock_unlocked.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: BUG 5 | labels: bug 6 | assignees: JonathanCortez 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Screenshot of Editor Layout and Window Layout. 16 | 2. Screenshot if any error from log. 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If applicable, add screenshots to help explain your problem. 23 | 24 | **Additional context** 25 | Add any other context about the problem here. 26 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/checkbox_checked.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/vertical_alt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_down_box.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_left_box.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/lock_locked.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/normal_close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: EXTEND 5 | labels: documentation, enhancement 6 | assignees: JonathanCortez 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/normal_close_pressed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/normal_folder.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorLib/RootWidget.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets 2 | 3 | class RootWidget(QtWidgets.QWidget): 4 | """ 5 | Root Widget when display on Layout UI Constructed view. 6 | """ 7 | def __init__(self): 8 | super(RootWidget, self).__init__() 9 | self._text = QtWidgets.QTextEdit() 10 | self._text.setText('To make your custom UI layout,' 11 | ' just drag from Template Supported and drop on to Layout tree. ' 12 | 'If you need any help about certain inputs or how to make your own Template widget,' 13 | ' go to tab Help > Documentation.') 14 | 15 | 16 | self._layout = QtWidgets.QVBoxLayout() 17 | self._layout.addWidget(self._text) 18 | 19 | self.setLayout(self._layout) -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/folder_minus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/folder_plus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/eye_view.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/menu_list_display.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/zoom_out.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/zoom_in.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_exchange_v.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from PySideLayoutTool.UIEditorLib import SetupTools 4 | from PySide2 import QtWidgets 5 | 6 | 7 | def maya_main_window(): 8 | import maya.OpenMayaUI as mayaUI 9 | import shiboken2 10 | main_window_ptr = mayaUI.MQtUtil_mainWindow() 11 | return shiboken2.wrapInstance(long(main_window_ptr), QtWidgets.QWidget) # type: ignore 12 | 13 | 14 | def houdini_main_window(): 15 | import hou 16 | return hou.ui.mainQtWindow() 17 | 18 | 19 | def DisplayWindow(): 20 | # SetupTools.set_custom_plugin_loader(r'C:\Users\heata\PycharmProjects\PySideLayoutTool\PySideLayoutTool\Plugins') 21 | SetupTools.enable_notification(False) 22 | SetupTools.PreInitialize(None) 23 | SetupTools.Setup_Init() 24 | 25 | if __name__ == '__main__': 26 | app = QtWidgets.QApplication(sys.argv) 27 | 28 | # with importlib.resources.open_text("resources.data", "LayoutToolBaseStyle.qss") as file: 29 | # app.setStyleSheet(file.read()) 30 | 31 | DisplayWindow() 32 | sys.exit(app.exec_()) 33 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/splitter_vertical_alt_2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/color_picker.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_exchange_alt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorLib/UIEditorIconFactory.py: -------------------------------------------------------------------------------- 1 | from typing import Callable, Dict, List, Any 2 | 3 | class IconEditorFactory: 4 | 5 | iconloc_str: Dict[str, Any] = {} 6 | 7 | @classmethod 8 | def register(cls, icon_name: str, icon_obj) -> None: 9 | """Register a widget layout type.""" 10 | if icon_name not in cls.iconloc_str: 11 | cls.iconloc_str[icon_name] = icon_obj 12 | 13 | @classmethod 14 | def unregister(self,character_type: str) -> None: 15 | """Unregister a widget layout type.""" 16 | self.iconloc_str.pop(character_type, None) 17 | 18 | @classmethod 19 | def create(cls,icon_name: str): 20 | """Create a widget of a specific type, given JSON data.""" 21 | try: 22 | icon_obj = cls.iconloc_str[icon_name] 23 | except KeyError: 24 | raise ValueError(f"unknown icon type {icon_name!r}, not registered") from None 25 | return icon_obj 26 | 27 | @classmethod 28 | def registered(cls) -> iconloc_str: 29 | """ Get all registered parameter types""" 30 | return cls.iconloc_str 31 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/LabelTemplate/LabelClass.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory 2 | from PySide2 import QtWidgets,QtCore 3 | 4 | class LabelSetupClass(LayoutTemplate.ParmSetup): 5 | 6 | def __init__(self,parent): 7 | super(LabelSetupClass, self).__init__(parent) 8 | self._label_widget = QtWidgets.QLabel(text='None') 9 | self._label_widget.setAlignment(QtCore.Qt.AlignLeft) 10 | self._layout.addWidget(self._label_widget) 11 | 12 | 13 | def PostUpdate(self): 14 | if self.default_value() != '': 15 | self._label_widget.setText(self.default_value()) 16 | 17 | def eval(self): 18 | return self._label_widget.text() 19 | 20 | def set_value(self, value, override=False): 21 | self._label_widget.setText(str(value)) 22 | 23 | 24 | 25 | class LabelBuildClass(TemplateBuildClass.ParameterBuild): 26 | 27 | def widgetClass(self): 28 | return LabelSetupClass 29 | 30 | 31 | 32 | def register(): 33 | UIEditorFactory.WidgetFactory.register('Label', LabelBuildClass) 34 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorWindows/NotificationSetup.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets, QtCore, QtGui 2 | import markdown 3 | 4 | import importlib 5 | from importlib import resources, util 6 | 7 | 8 | class NotificationWindow(QtWidgets.QDialog): 9 | def __init__(self, parent=None): 10 | super(NotificationWindow, self).__init__(parent) 11 | self.setWindowTitle('Notification Changes') 12 | 13 | size = QtCore.QSize(800, 500) 14 | self.setMinimumSize(size) 15 | 16 | self._layout = QtWidgets.QVBoxLayout() 17 | self._text_editor = QtWidgets.QTextEdit() 18 | self._text_editor.setReadOnly(True) 19 | self._text_editor.setProperty('class','markdown_display') 20 | 21 | self._text = None 22 | with importlib.resources.path("PySideLayoutTool.resources.data", "CHANGELOG.md") as path: 23 | with open(path, 'r') as file: 24 | self._text = markdown.markdown(file.read(), extensions=['extra']) 25 | 26 | self._text_editor.setHtml(self._text) 27 | self._layout.addWidget(self._text_editor) 28 | self.setLayout(self._layout) 29 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/CheckBoxTemplate/CheckboxProperty.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UICProperty, PropertyFactory, IWidgetProperties 2 | from . import CheckboxWidgetClass 3 | 4 | @PropertyFactory.register('CheckProperty') 5 | class CheckProperty(IWidgetProperties): 6 | 7 | def __init__(self): 8 | super(CheckProperty, self).__init__() 9 | self._markState = False 10 | 11 | self._checkbox = CheckboxWidgetClass.CheckBoxWidget() 12 | self._layout.addWidget(self._checkbox) 13 | 14 | self._checkbox.stateChanged.connect(self.checkState) 15 | 16 | def override_default(self, defaults: tuple): 17 | self._markState = defaults[0] 18 | self._checkbox.setChecked(self._markState) 19 | 20 | def checkState(self, arg): 21 | self._markState = True if arg == 2 else False 22 | 23 | def setValue(self,value): 24 | self._checkbox.setChecked(bool(value)) 25 | 26 | def value(self) -> bool: 27 | return self._checkbox.isChecked() 28 | 29 | 30 | @UICProperty 31 | def mark(self): 32 | return self._markState 33 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/FileTemplate/FileClass.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory 2 | from . import FileWidgetClsss 3 | 4 | class FileWidgetSetupClass(LayoutTemplate.ParmSetup): 5 | 6 | def __init__(self,parent): 7 | super(FileWidgetSetupClass, self).__init__(parent) 8 | self._file_widget = FileWidgetClsss.FileWidgetLayout() 9 | self._file_value = '' 10 | 11 | self._layout.addWidget(self._file_widget) 12 | self._file_widget.file_widget_line().editingFinished.connect(self._file_change) 13 | 14 | def _file_change(self): 15 | self._file_value = self._file_widget.file_widget_line().text() 16 | self.notify_expressions() 17 | 18 | def PostUpdate(self): 19 | pass 20 | 21 | def eval(self): 22 | return self._file_value 23 | 24 | def set_value(self, value, override=False): 25 | self._file_value = value 26 | self._file_widget.set_text_value(value) 27 | 28 | 29 | 30 | class FileWidgetBuildClass(TemplateBuildClass.ParameterBuild): 31 | 32 | def widgetClass(self): 33 | return FileWidgetSetupClass 34 | 35 | 36 | def register(): 37 | UIEditorFactory.WidgetFactory.register('File', FileWidgetBuildClass) -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/CheckBoxTemplate/CheckboxClass.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib.UIEditorFactory import WidgetFactory 2 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass 3 | from PySide2 import QtWidgets 4 | from . import CheckboxWidgetClass 5 | 6 | 7 | class CheckClass(LayoutTemplate.ParmSetup): 8 | 9 | def __init__(self, parent): 10 | super(CheckClass, self).__init__(parent) 11 | self._checkbox = CheckboxWidgetClass.CheckBoxWidget() 12 | self._checkbox.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) 13 | self._state = 0 14 | 15 | self._layout.addWidget(self._checkbox) 16 | self._checkbox.stateChanged.connect(self.checkState) 17 | 18 | def checkState(self,state): 19 | self._state = state 20 | self.notify_expressions() 21 | 22 | def set_value(self, value, override=False): 23 | self._state = value 24 | self._checkbox.setChecked(bool(value)) 25 | 26 | def eval(self): 27 | return self._checkbox.isChecked() 28 | 29 | 30 | class CheckboxBuild(TemplateBuildClass.ParameterBuild): 31 | 32 | def widgetClass(self): 33 | return CheckClass 34 | 35 | 36 | def register(): 37 | WidgetFactory.register('Toggle', CheckboxBuild) -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/UIEditorTemplates.uiplugin: -------------------------------------------------------------------------------- 1 | { 2 | "Icons": "IconRegistration", 3 | "Properties": 4 | [ 5 | "Common.CheckBoxTemplate.CheckboxProperty", 6 | "Common.ComboBoxTemplate.ComboBoxProperty", 7 | "Common.StringEditTemplate.StringEditProperty", 8 | "Common.ClampRangeTemplate.ClampRangeProperty", 9 | "Common.DictionaryTemplate.DictionaryWidgetProperty" 10 | 11 | ], 12 | "Categories": 13 | [ 14 | { 15 | "Name": "Common", 16 | "Modules": 17 | [ 18 | "CheckBoxTemplate.CheckboxClass", 19 | "SeparatorTemplate.SeparatorClass", 20 | "SliderTemplate.SliderClass", 21 | "StringEditTemplate.StringEditClass", 22 | "ClampRangeTemplate.ClampRangeClass", 23 | "LineEditTemplate.MultiLineEditClasses", 24 | "DictionaryTemplate.DictionaryClass", 25 | "ComboBoxTemplate.ComboBoxClass", 26 | "LabelTemplate.LabelClass", 27 | "ButtonTemplate.ButtonClass", 28 | "FileTemplate.FileClass", 29 | "ColorTemplate.ColorClass", 30 | "RampTemplate.RampClass" 31 | ] 32 | }, 33 | { 34 | "Name": "Folder", 35 | "Modules": 36 | [ 37 | "SimpleFolderTemplate.SimpleFolderClass", 38 | "CollapisbleFolderTemplate.CollapisbleFolderClass", 39 | "TabFolderTemplate.FolderTabClasses" 40 | ] 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/DictionaryTemplate/DictionaryClass.py: -------------------------------------------------------------------------------- 1 | from . import DictionaryWidgetClass 2 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory 3 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty 4 | 5 | class DictionarySetupClass(LayoutTemplate.ParmSetup): 6 | 7 | def __init__(self, parent): 8 | super(DictionarySetupClass, self).__init__(parent) 9 | self._dict_widget = DictionaryWidgetClass.DictWidgetClass() 10 | self._row_change = 0 11 | self._column_change = 0 12 | 13 | self._layout.addWidget(self._dict_widget) 14 | self._dict_widget.table_widget.cellChanged.connect(self._dict_changed) 15 | 16 | 17 | @UIProperty(metaWidget='DictionaryProperty', label='Values', category='Combo/Menu Items') 18 | def dict_keyValue(self): 19 | pass 20 | 21 | 22 | def _dict_changed(self,row, column): 23 | self._row_change = row 24 | self._column_change = column 25 | self.notify_expressions() 26 | 27 | 28 | def eval(self): 29 | return self._row_change, self._column_change 30 | 31 | def PostUpdate(self): 32 | pass 33 | 34 | 35 | 36 | class DictionaryBuildClass(TemplateBuildClass.ParameterBuild): 37 | 38 | def widgetClass(self): 39 | return DictionarySetupClass 40 | 41 | 42 | def register(): 43 | UIEditorFactory.WidgetFactory.register('Key-Value Dictionary', DictionaryBuildClass) 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/setting_gear_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/SeparatorTemplate/SeparatorWidgetClass.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets 2 | 3 | class SeparatorHWidget(QtWidgets.QWidget): 4 | def __init__(self,parent=None): 5 | super(SeparatorHWidget, self).__init__(parent) 6 | self.setFixedHeight(20) 7 | self._layout = QtWidgets.QVBoxLayout() 8 | self._layout.setSpacing(0) 9 | self._layout.setContentsMargins(0, 0, 0, 0) 10 | 11 | self._line = QtWidgets.QFrame() 12 | self._line.setFrameShape(QtWidgets.QFrame.HLine) 13 | self._line.setLineWidth(1) 14 | self._line.setStyleSheet("QFrame{" 15 | "color: rgb(80, 80, 80);}") 16 | 17 | self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) 18 | self._layout.addWidget(self._line) 19 | self.setLayout(self._layout) 20 | 21 | 22 | class SeparatorVWidget(QtWidgets.QWidget): 23 | def __init__(self): 24 | super(SeparatorVWidget, self).__init__() 25 | self.setFixedWidth(20) 26 | self._layout = QtWidgets.QVBoxLayout() 27 | self._layout.setSpacing(0) 28 | self._layout.setContentsMargins(0, 0, 0, 0) 29 | 30 | self._line = QtWidgets.QFrame() 31 | self._line.setFrameShape(QtWidgets.QFrame.VLine) 32 | self._line.setLineWidth(1) 33 | self._line.setStyleSheet("QFrame{" 34 | "color: rgb(80, 80, 80);}") 35 | 36 | self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding) 37 | self._layout.addWidget(self._line) 38 | self.setLayout(self._layout) -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ComboBoxTemplate/ComboBoxWidgetClass.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets, QtCore 2 | from typing import List 3 | 4 | class ComboBoxWidget(QtWidgets.QWidget): 5 | 6 | def __init__(self): 7 | super(ComboBoxWidget, self).__init__() 8 | self.setMinimumHeight(40) 9 | self.setMaximumHeight(40) 10 | self._layout = QtWidgets.QVBoxLayout() 11 | self._layout.setSpacing(0) 12 | self._layout.setContentsMargins(0, 0, 0, 0) 13 | 14 | horizontal_Layout = QtWidgets.QHBoxLayout() 15 | horizontal_Layout.setSpacing(0) 16 | horizontal_Layout.setContentsMargins(0,0,0,0) 17 | 18 | self._combo_box = QtWidgets.QComboBox() 19 | self._combo_box.setEditable(False) 20 | self._combo_box.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) 21 | self._combo_box.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLengthWithIcon) 22 | 23 | horizontal_Layout.addWidget(self._combo_box) 24 | # horizontal_Layout.addSpacerItem(QtWidgets.QSpacerItem(20,20,QtWidgets.QSizePolicy.Expanding,QtWidgets.QSizePolicy.Fixed)) 25 | 26 | self._layout.addLayout(horizontal_Layout) 27 | self.setLayout(self._layout) 28 | 29 | def combo_widget(self): 30 | return self._combo_box 31 | 32 | def addItems(self, items: List[str]): 33 | self._combo_box.addItems(items) 34 | # TODO resize combo box to the longest string in items 35 | 36 | def addItem(self, item: str): 37 | self._combo_box.addItem(item) 38 | 39 | def setItem(self, index): 40 | self._combo_box.setCurrentIndex(index) -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Folder/SimpleFolderTemplate/SimpleFolderClass.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets 2 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory, TemplateDataClass 3 | 4 | 5 | class SimpleFolderWidget(LayoutTemplate.FolderSetup): 6 | """ Simple Folder is good for keeping widgets together 7 | and with a label and frame around it. 8 | """ 9 | def __init__(self,parent): 10 | super(SimpleFolderWidget, self).__init__(parent) 11 | self._folder_widget = QtWidgets.QGroupBox(title=self.label()) 12 | self._folder_layout.addWidget(self._childWidgets) 13 | self._folder_widget.setLayout(self._folder_layout) 14 | 15 | self._layout.addWidget(self._folder_widget) 16 | 17 | def eval(self) -> int or float: 18 | return None 19 | 20 | def clearLayout(self): 21 | if self._folder_widget.layout() is not None: 22 | for i in range(0, self._folder_widget.layout().count()): 23 | item_layout = self._folder_widget.layout().itemAt(i) 24 | item_layout.widget().deleteLater() 25 | 26 | self._childWidgets = TemplateDataClass.TemplateGroup() 27 | self._folder_layout.addWidget(self._childWidgets) 28 | self._folder_widget.setLayout(self._folder_layout) 29 | 30 | def PostUpdate(self): 31 | self._folder_widget.setTitle(self.label()) 32 | 33 | 34 | 35 | 36 | class SimpleFolder(TemplateBuildClass.FolderBuild): 37 | 38 | def widgetClass(self): 39 | return SimpleFolderWidget 40 | 41 | 42 | 43 | def register() -> None: 44 | UIEditorFactory.WidgetFactory.register('Simple', SimpleFolder) -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ComboBoxTemplate/ComboBoxClass.py: -------------------------------------------------------------------------------- 1 | from . import ComboBoxWidgetClass 2 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty 3 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory 4 | 5 | class ComboBoxSetupClass(LayoutTemplate.ParmSetup): 6 | 7 | def __init__(self, parent): 8 | super(ComboBoxSetupClass, self).__init__(parent) 9 | self._combo_widget = ComboBoxWidgetClass.ComboBoxWidget() 10 | self._current_index = 0 11 | 12 | self._layout.addWidget(self._combo_widget) 13 | self._combo_widget.combo_widget().activated.connect(self._combo_changed) 14 | 15 | @UIProperty(metaWidget='CheckProperty',label='Use Value as return value ',category='Combo Items', use_separator=True) 16 | def bItemValue(self): 17 | pass 18 | 19 | @UIProperty(metaWidget='DictionaryProperty',label='Values',category='Combo/Menu Items') 20 | def dict_keyValue(self): 21 | pass 22 | 23 | def _combo_changed(self, arg__1): 24 | self._current_index = arg__1 25 | self.notify_expressions() 26 | 27 | def eval(self): 28 | return self._current_index 29 | 30 | def set_value(self, value, override=False): 31 | self._combo_widget.setItem(int(value)) 32 | 33 | def PostUpdate(self): 34 | items = self.dict_keyValue().keys 35 | self._combo_widget.addItems(items) 36 | 37 | 38 | class ComboBoxBuildClass(TemplateBuildClass.ParameterBuild): 39 | 40 | def widgetClass(self): 41 | return ComboBoxSetupClass 42 | 43 | 44 | 45 | def register(): 46 | UIEditorFactory.WidgetFactory.register('Ordered Combo/Menu', ComboBoxBuildClass) 47 | 48 | 49 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorLib/StringValidatorClass.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | _specialChars = re.compile('[{};:?/|!~`$%@^&*()\[\]\-+=.\><,"\']') 4 | 5 | def checkString(string: str) -> str: 6 | if _specialChars.search(string) is None: 7 | newstring = string.replace(' ','') 8 | return newstring 9 | else: 10 | result = [m.start(0) for m in re.finditer(_specialChars, string)] 11 | for index in result: 12 | string = string.replace(string[index],'_') 13 | 14 | return checkString(string) 15 | 16 | 17 | def check_prefix_name(check_string: str): 18 | if _specialChars.search(check_string) is not None: 19 | raise TypeError(f'Prefix name ({check_string}) can only contain [chars, numbers, _ , #]') 20 | 21 | return check_string 22 | 23 | def check_names(name: str, check_item) -> str: 24 | """ 25 | 26 | :param name: string that is being evaluated. 27 | :param check_item: data that is being evaluated against. 28 | :return: get new name. 29 | """ 30 | if name in check_item: 31 | str_lenght = len(name)-1 32 | if name[str_lenght].isdigit(): 33 | str_num = str(int(name[str_lenght]) + 1) 34 | name = name.replace(name[str_lenght], str_num) 35 | else: 36 | name += '1' 37 | 38 | return check_names(name,check_item) 39 | 40 | return name 41 | 42 | 43 | def check_string_len(string: str, max_length:int = 10): 44 | 45 | if len(string) > max_length: 46 | string = string.replace(string[10-3:],'...') 47 | 48 | return string 49 | 50 | 51 | def hash_char_to_index(string: str): 52 | update_string = '' 53 | return update_string 54 | 55 | def check_similarName(string: str) -> str: 56 | pass 57 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Layout/CustomFormLayout.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets, QtCore, QtGui 2 | from typing import Dict 3 | 4 | class CustomForm(QtWidgets.QVBoxLayout): 5 | 6 | def __init__(self): 7 | super(CustomForm, self).__init__() 8 | self.setSpacing(0) 9 | self.setContentsMargins(10 ,0 ,10 ,10) 10 | self.setAlignment(QtCore.Qt.AlignTop) 11 | 12 | self._label_widgets = {} 13 | 14 | def labels(self, widget): 15 | return self._label_widgets[widget] 16 | 17 | def new_Row(self, label :str,name:str, widget: QtWidgets.QWidget, spacing=15, apply_to_main=True): 18 | setup_layout = QtWidgets.QHBoxLayout() 19 | setup_layout.setContentsMargins(0 ,10 ,0 ,0) 20 | setup_layout.setSpacing(0) 21 | 22 | self._label_widget = QtWidgets.QLabel(text=label) 23 | self._label_widget.setMinimumHeight(30) 24 | self._label_widget.setMaximumHeight(30) 25 | 26 | if name is not None: 27 | self._label_widget.setToolTip(f"
Parameter: {name}
") 28 | self._label_widget.setStyleSheet("QToolTip { color: #ffffff; background-color: #484848; border: 0px;}") 29 | 30 | setup_layout.addWidget(self._label_widget ,alignment=QtCore.Qt.AlignLeft) 31 | setup_layout.addSpacing(spacing) 32 | setup_layout.addWidget(widget) 33 | 34 | if apply_to_main: 35 | self.addLayout(setup_layout) 36 | 37 | self._label_widgets[widget] = self._label_widget 38 | return setup_layout 39 | 40 | def add_Layout(self, layout_item): 41 | self.addLayout(layout_item) 42 | 43 | def add_Custom(self, widget: QtWidgets.QWidget): 44 | self.addWidget(widget) 45 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/StringEditTemplate/StringEditProperty.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UICProperty, PropertyFactory, IWidgetProperties 2 | from . import StringEditWidgetClass 3 | 4 | @PropertyFactory.register('LineEditProperty') 5 | class StringProperty(IWidgetProperties): 6 | 7 | def __init__(self): 8 | super(StringProperty,self).__init__() 9 | self._strText: str = '' 10 | self._val_func = None 11 | self._verify_func = None 12 | 13 | self._textbox = StringEditWidgetClass.BasicStringWidget(self._strText) 14 | self._layout.addWidget(self._textbox) 15 | 16 | self._textbox._str_widget.textChanged.connect(self.checkText) 17 | self._textbox._str_widget.editingFinished.connect(self.strUpdate) 18 | 19 | 20 | def override_default(self, defaults: tuple): 21 | self._textbox.validator = self._textbox.validater_type(defaults[0]) 22 | self._textbox.validator_level = defaults[1] 23 | self._textbox._str_widget.setValidator(self._textbox.validator) 24 | self._textbox._str_widget.setText(defaults[2]) 25 | self._val_func = defaults[3] 26 | 27 | def setText(self, new_text): 28 | self._textbox._str_widget.setText(new_text) 29 | 30 | def checkText(self, arg__1): 31 | if self._val_func is not None: 32 | self._textbox._str_widget.setText(self._val_func(arg__1)) 33 | 34 | self._strText = self._textbox._str_widget.text() 35 | 36 | def strUpdate(self): 37 | self._strText = self._textbox._str_widget.text() 38 | self.setFocus() 39 | 40 | def setValue(self, value): 41 | self._textbox._str_widget.setText(value) 42 | 43 | def value(self): 44 | return self._textbox._str_widget.text() 45 | 46 | 47 | @UICProperty 48 | def strText(self): 49 | return self._strText 50 | 51 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorWindows/MainLayoutWindow.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib import WindowsModule 2 | from PySide2 import QtCore, QtWidgets 3 | 4 | 5 | class MainWindowLayout(QtWidgets.QMainWindow): 6 | def __init__(self, window_name: str): 7 | super(MainWindowLayout, self).__init__() 8 | self.setWindowTitle(f'{window_name} Layout') 9 | 10 | size = QtCore.QSize(450, 450) 11 | self.setMinimumSize(size) 12 | 13 | self._dock = QtWidgets.QDockWidget() 14 | self._dock.setFeatures(QtWidgets.QDockWidget.NoDockWidgetFeatures) 15 | self._layout_name = window_name 16 | self._serialization_obj = None 17 | 18 | self._layout_widget_data = {} 19 | 20 | self._widget_ptr = QtWidgets.QWidget() 21 | self._scrollArea = QtWidgets.QScrollArea() 22 | self._scrollArea.setWidgetResizable(True) 23 | self._scrollArea.setStyleSheet("QScrollArea{ border: 0px;}") 24 | 25 | self._dock.setWidget(self._scrollArea) 26 | 27 | self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self._dock) 28 | 29 | def widget_layout(self): 30 | return self._layout_widget_data 31 | 32 | def closeEvent(self, event) -> None: 33 | self._serialization_obj.write_commonData() 34 | self._serialization_obj.save_data(force_save=True) 35 | 36 | def UpdateLayout(self, new_widget: QtWidgets.QWidget): 37 | self._widget_ptr.deleteLater() 38 | self._widget_ptr = new_widget 39 | self._scrollArea.setWidget(self._widget_ptr) 40 | self.update() 41 | 42 | def parm(self, name: str): 43 | return self._layout_widget_data[name] 44 | 45 | def templateLayout(self): 46 | return self._widget_ptr 47 | 48 | def layout_name(self): 49 | return self._layout_name 50 | 51 | def display(self): 52 | WindowsModule.WindowsManger.window_show(self) 53 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/LabelTemplate/LabelSwitchWidget.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets, QtGui, QtCore 2 | 3 | 4 | class SwitchLabelWidget(QtWidgets.QStackedWidget): 5 | 6 | def __init__(self, name: str, base_widget): 7 | super(SwitchLabelWidget, self).__init__() 8 | self._hint_label = name 9 | self._main_widget = base_widget 10 | 11 | self._switch_index = 0 12 | 13 | self._hint_label = LabelActionSwitch(name, self.switch_widgets) 14 | self._child_widget = None 15 | self.addWidget(self._main_widget) 16 | 17 | def add_switch_widget(self, widget): 18 | self._child_widget = widget 19 | self.addWidget(self._child_widget) 20 | self._main_widget.base_widget().valueChanged.connect(self._child_widget.set_slider_value) 21 | 22 | def switch_widgets(self): 23 | if self._switch_index == 0: 24 | self.setCurrentIndex(1) 25 | self._switch_index = 1 26 | else: 27 | self.setCurrentIndex(0) 28 | self._switch_index = 0 29 | 30 | def child_widget(self): 31 | return self._child_widget 32 | 33 | def base_widget(self): 34 | return self._main_widget 35 | 36 | def set_label_text(self, text: str): 37 | self._hint_label.setText(text) 38 | 39 | def label_widget(self): 40 | return self._hint_label 41 | 42 | 43 | class LabelActionSwitch(QtWidgets.QLabel): 44 | 45 | def __init__(self, name: str, func): 46 | super(LabelActionSwitch, self).__init__() 47 | self._func = func 48 | 49 | self.setText(name) 50 | self.setAlignment(QtCore.Qt.AlignCenter) 51 | self.setContentsMargins(0, 0, 0, 2) 52 | self.setMinimumHeight(18) 53 | self.setMaximumHeight(18) 54 | self.setMinimumWidth(12) 55 | self.setMaximumWidth(12) 56 | self.setProperty('class', 'base_hint') 57 | 58 | def mousePressEvent(self, event) -> None: 59 | self._func() 60 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/DictionaryTemplate/DictionaryWidgetProperty.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UICProperty, PropertyFactory, IWidgetProperties 2 | from . import DictionaryWidgetClass 3 | 4 | @PropertyFactory.register('DictionaryProperty') 5 | class DictionaryProperty(IWidgetProperties): 6 | 7 | def __init__(self): 8 | super(DictionaryProperty, self).__init__() 9 | self._keys = [] 10 | self._values = [] 11 | self._dict_widget = DictionaryWidgetClass.DictWidgetClass() 12 | self._layout.addWidget(self._dict_widget) 13 | 14 | self._dict_widget.table_widget.cellChanged.connect(self.updateValues) 15 | 16 | def override_default(self, defaults: tuple): 17 | pass 18 | 19 | def setValue(self, value): 20 | if len(value) == 2: 21 | for i in enumerate(value[0]): 22 | if i[0]+1 > self._dict_widget.count(): 23 | self._dict_widget.addDict() 24 | self._dict_widget.setkeyText(i[0],i[1]) 25 | 26 | for i in enumerate(value[1]): 27 | if i[0]+1 > self._dict_widget.count(): 28 | self._dict_widget.addDict() 29 | self._dict_widget.setvalueText(i[0],i[1]) 30 | else: 31 | for i in enumerate(value[0]): 32 | if i[0]+1 > self._dict_widget.count(): 33 | self._dict_widget.addDict() 34 | self._dict_widget.setkeyText(i[0],i[1]) 35 | self._dict_widget.setvalueText(i[0],str(i[0])) 36 | 37 | 38 | def value(self): 39 | return list(self._keys), list(self._values) 40 | 41 | def updateValues(self): 42 | self._keys = self._dict_widget.DictionaryKeys() 43 | self._values = self._dict_widget.DictionaryValues() 44 | 45 | @UICProperty 46 | def keys(self): 47 | return self._keys 48 | 49 | @UICProperty 50 | def values(self): 51 | return self._values 52 | 53 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Folder/CollapisbleFolderTemplate/CollapisbleFolderClass.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib import TemplateDataClass 2 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty 3 | from PySideLayoutTool.UIEditorLib.UIEditorFactory import WidgetFactory 4 | from PySideLayoutTool.UIEditorLib.LayoutTemplate import FolderSetup 5 | from PySideLayoutTool.UIEditorLib.TemplateBuildClass import FolderBuild 6 | from . import CollapisbleFolderWidgetClass 7 | 8 | 9 | class CollapisbleFolderClass(FolderSetup): 10 | 11 | def __init__(self,parent): 12 | super(CollapisbleFolderClass, self).__init__(parent) 13 | self._parent = parent 14 | self._folder_widget = CollapisbleFolderWidgetClass.CollapsibleFolderWidget(self._childWidgets) 15 | self._layout.addWidget(self._folder_widget) 16 | 17 | 18 | @UIProperty(metaWidget='CheckProperty', label='Open on Start',category='Setting') 19 | def bOpen(self): 20 | pass 21 | 22 | def eval(self): 23 | return None 24 | 25 | 26 | def clearLayout(self): 27 | if self._folder_widget.collapisble_layout() is not None: 28 | for i in range(0, self._folder_widget.collapisble_layout().count()): 29 | item_layout = self._folder_widget.collapisble_layout().itemAt(i) 30 | widget = item_layout.widget() 31 | widget.deleteLater() 32 | 33 | self._childWidgets = TemplateDataClass.TemplateGroup() 34 | self._folder_widget.new_frame(self._childWidgets) 35 | 36 | 37 | def PostUpdate(self): 38 | self._folder_widget.folder_title(self.label()) 39 | # self._folder_widget.setContentLayout(self._folder_layout) 40 | # self._folder_widget.updateSize(0,10) 41 | # self._folder_widget.force_close() 42 | 43 | 44 | class CollapisbleFolderBuild(FolderBuild): 45 | 46 | def widgetClass(self): 47 | return CollapisbleFolderClass 48 | 49 | 50 | 51 | 52 | def register(): 53 | WidgetFactory.register('Collapsible', CollapisbleFolderBuild) -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/SeparatorTemplate/SeparatorClass.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorIconFactory 2 | from PySideLayoutTool.UIEditorLib.UIEditorFactory import WidgetFactory 3 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty 4 | from PySide2 import QtWidgets 5 | from . import SeparatorWidgetClass 6 | 7 | class SeparatorClass(LayoutTemplate.ParmSetup): 8 | def __init__(self,parent): 9 | super(SeparatorClass, self).__init__(parent) 10 | self._sep = SeparatorWidgetClass.SeparatorHWidget() 11 | self._textLabel = QtWidgets.QLabel(text='None') 12 | self._textLabel.setVisible(self.bUseLabel()) 13 | 14 | self._Hlayout = QtWidgets.QHBoxLayout() 15 | self._sep.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) 16 | 17 | self._Hlayout.addWidget(self._textLabel) 18 | self._Hlayout.addSpacing(5) 19 | self._Hlayout.addWidget(self._sep) 20 | self._Hlayout.setContentsMargins(0, 0, 0, 0) 21 | self._layout.addLayout(self._Hlayout) 22 | 23 | 24 | def PostUpdate(self): 25 | self._textLabel.setVisible(self.bUseLabel()) 26 | if self.bUseLabel(): 27 | self._textLabel.setText(self.label()) 28 | 29 | @UIProperty(metaWidget='CheckProperty', label='Use Label', category='Setting') 30 | def bUseLabel(self): 31 | pass 32 | 33 | def bLabel(self): 34 | return False 35 | 36 | def eval(self): 37 | return None 38 | 39 | 40 | class SeparatorBase(TemplateBuildClass.ParameterBuild): 41 | 42 | def prefixStart_name(self) -> str: 43 | return 'sepparm' 44 | 45 | def prefixStart_label(self) -> str: 46 | return 'Separator' 47 | 48 | def widgetClass(self): 49 | return SeparatorClass 50 | 51 | def set_icon(self) -> None: 52 | return UIEditorIconFactory.IconEditorFactory.create('separtor_v1') 53 | 54 | def register() -> None: 55 | WidgetFactory.register('Separator', SeparatorBase) 56 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/StringEditTemplate/StringEditClass.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib.UIEditorFactory import WidgetFactory 2 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass 3 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty 4 | from . import StringEditWidgetClass 5 | 6 | 7 | class StringClass(LayoutTemplate.ParmSetup): 8 | 9 | def __init__(self,parent): 10 | super(StringClass, self).__init__(parent) 11 | self._textbox = None 12 | 13 | 14 | @UIProperty(metaWidget='CheckProperty', label='Multi-line String', category='Setting') 15 | def is_multi_line_string(self): 16 | pass 17 | 18 | @UIProperty(metaWidget='ComboProperty', label='Language', category='Setting', defaults=['None', 'Python']) 19 | def language_type(self): 20 | pass 21 | 22 | def bLabel(self) -> bool: 23 | return not self.is_multi_line_string() 24 | 25 | def PreUpdate(self): 26 | if self._textbox: 27 | self._textbox.deleteLater() 28 | 29 | def PostUpdate(self): 30 | if self.is_multi_line_string(): 31 | self._textbox = StringEditWidgetClass.MultiStringWidget(bool(self.language_type().currentItem_index)) 32 | self._textbox.set_label_text(self.label()) 33 | else: 34 | self._textbox = StringEditWidgetClass.BasicStringWidget('') 35 | self._textbox.string_widget().editingFinished.connect(self._str_changed) 36 | 37 | self._layout.addWidget(self._textbox) 38 | 39 | 40 | def _str_changed(self): 41 | self.notify_expressions() 42 | 43 | def eval(self): 44 | if self.is_multi_line_string(): 45 | return self._textbox.text() 46 | 47 | return self._textbox.string_widget().text() 48 | 49 | def set_value(self, value, override=False): 50 | if self.is_multi_line_string(): 51 | self._textbox.insertPlainText(str(value)) 52 | else: 53 | self._textbox.string_widget().setText(str(value)) 54 | 55 | 56 | 57 | class StringEditBuild(TemplateBuildClass.ParameterBuild): 58 | 59 | def widgetClass(self): 60 | return StringClass 61 | 62 | 63 | 64 | def register(): 65 | WidgetFactory.register('String', StringEditBuild) -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ComboBoxTemplate/ComboBoxProperty.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UICProperty, PropertyFactory, IWidgetProperties 2 | from . import ComboBoxWidgetClass 3 | 4 | @PropertyFactory.register('ComboProperty') 5 | class ComboBoxProperty(IWidgetProperties): 6 | 7 | def __init__(self): 8 | super(ComboBoxProperty, self).__init__() 9 | self._current_item_name = None 10 | self._current_item_index = -1 11 | self._combo_widget = ComboBoxWidgetClass.ComboBoxWidget() 12 | self._layout.addWidget(self._combo_widget) 13 | self._items = None 14 | 15 | self._combo_widget._combo_box.activated.connect(self._comboChanged) 16 | 17 | def override_default(self, defaults: tuple): 18 | self.setItems(defaults) 19 | self._current_item_index = self.currentItemIndex() 20 | self._current_item_name = self._combo_widget._combo_box.currentText() 21 | 22 | def setValue(self, value): 23 | self.setItems(value['general_values']) 24 | self.setCurrentItem(value['current_value']) 25 | self._current_item_name = value['current_value'] 26 | self._current_item_index = self.currentItemIndex() 27 | 28 | def value(self): 29 | return {'current_value': self._combo_widget._combo_box.currentText(), 'general_values': self._items} 30 | 31 | def setCurrentItem(self, text): 32 | self._combo_widget._combo_box.setCurrentText(text) 33 | self._current_item_name = self._combo_widget._combo_box.currentText() 34 | self._current_item_index = self.currentItemIndex() 35 | 36 | def setItems(self, items): 37 | self._items = items 38 | self._combo_widget._combo_box.clear() 39 | self._combo_widget._combo_box.addItems(items) 40 | 41 | def _comboChanged(self, arg__1): 42 | self._current_item_name = self._combo_widget._combo_box.currentText() 43 | self._current_item_index = self.currentItemIndex() 44 | 45 | def propertyWidget(self): 46 | return self._combo_widget._combo_box 47 | 48 | def currentItemIndex(self): 49 | return self._combo_widget._combo_box.currentIndex() 50 | 51 | @UICProperty 52 | def currentItem_name(self): 53 | return self._current_item_name 54 | 55 | @UICProperty 56 | def currentItem_index(self): 57 | return self._current_item_index -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/RampTemplate/RampClass.py: -------------------------------------------------------------------------------- 1 | import ast 2 | 3 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty 4 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory 5 | from . import RampWidgetClass, RampColorWidgetClass 6 | 7 | class RampSetupClass(LayoutTemplate.ParmSetup): 8 | 9 | def __init__(self,parent): 10 | super(RampSetupClass, self).__init__(parent) 11 | self._ramp_widget = RampWidgetClass.RampWidgetSetup(self) 12 | self._layout.addWidget(self._ramp_widget) 13 | 14 | @UIProperty(metaWidget='ComboProperty',label='Def Interpolation',category='Default', 15 | defaults=['Constant','Linear','Catmull-Rom','Monotone Cubic', 'Bezier', 'B-Spline', 'Hermit']) 16 | def default_interp(self): 17 | pass 18 | 19 | def bLabel(self) -> bool: 20 | return False 21 | 22 | def PostUpdate(self): 23 | self._ramp_widget.label(self.label()) 24 | 25 | def set_value(self, value, override=False): 26 | value = ast.literal_eval(value) 27 | positions = list(map(int, list(value['positions']))) 28 | values = list(map(int, list(value['values']))) 29 | interpolations = list(map(int, list(value['interpolations']))) 30 | self._ramp_widget.setRamp(positions,values,interpolations) 31 | 32 | def eval(self): 33 | return self._ramp_widget.get_ramp() 34 | 35 | 36 | 37 | 38 | class RampColorSetupClass(LayoutTemplate.ParmSetup): 39 | 40 | def __init__(self,parent): 41 | super(RampColorSetupClass, self).__init__(parent) 42 | self._ramp_widget = RampColorWidgetClass.RampColorWidgetSetup(self) 43 | self._layout.addWidget(self._ramp_widget) 44 | 45 | def bLabel(self) -> bool: 46 | return False 47 | 48 | def PostUpdate(self): 49 | self._ramp_widget.label(self.label()) 50 | 51 | 52 | 53 | class RampBuildClass(TemplateBuildClass.ParameterBuild): 54 | 55 | def widgetClass(self): 56 | return RampSetupClass 57 | 58 | 59 | class RampColorBuildClass(TemplateBuildClass.ParameterBuild): 60 | 61 | def widgetClass(self): 62 | return RampColorSetupClass 63 | 64 | 65 | 66 | def register(): 67 | UIEditorFactory.WidgetFactory.register('Ramp (Float)', RampBuildClass) 68 | UIEditorFactory.WidgetFactory.register('Ramp (Color)', RampColorBuildClass) -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/FileTemplate/FileWidgetClsss.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets, QtCore 2 | from PySideLayoutTool.UIEditorLib import UIEditorIconFactory, WindowsModule 3 | 4 | 5 | class FileWidgetLayout(QtWidgets.QWidget): 6 | 7 | def __init__(self): 8 | super(FileWidgetLayout, self).__init__() 9 | self._layout = QtWidgets.QVBoxLayout() 10 | self._layout.setSpacing(0) 11 | self._layout.setContentsMargins(0,0,0,0) 12 | 13 | self._hor_layout = QtWidgets.QHBoxLayout() 14 | self._hor_layout.setSpacing(0) 15 | self._hor_layout.setContentsMargins(0,2,0,2) 16 | self._hor_layout.setAlignment(QtCore.Qt.AlignLeft) 17 | 18 | 19 | self._geo_filter = ('*.abc *.ai *.bgeo *.bgeo.bz2 *.bgeo.gz *bgeo.lzma *.bgeo.sc *.bgeogz *.bgeosc *bhclassic *.bhclassic.bz2' 20 | '*.bhclassic.gz *.bhclassic.lzma *.bhclassic.sc *.bhclassicgz *.bhclassicsc *.bjson *.bjson.gz *.bjson.sc *.bjsongz *.bjsonsc' 21 | '*.bpoly *.bstl *.d *.dxf *.eps *.exr *.fbx *.flt *.geo *.geo.bz2 *.geo.gz *.geo.lzma *.geo.sc *.geogz *.geosc *.GoZ *.hclassic') 22 | self._image_filter = ('*.jpg *.png') 23 | 24 | self._file_dialog = QtWidgets.QFileDialog() 25 | self._text_box = QtWidgets.QLineEdit() 26 | 27 | self._button_widget = QtWidgets.QPushButton() 28 | self._button_widget.setMinimumWidth(30) 29 | self._button_widget.setMaximumWidth(30) 30 | # icon = QtGui.QIcon(UIEditorIconFactory.IconEditorFactory.create('add_file')) 31 | self._button_widget.setIcon(UIEditorIconFactory.IconEditorFactory.create('add_file')) 32 | 33 | self._hor_layout.addWidget(self._text_box) 34 | self._hor_layout.addSpacing(5) 35 | self._hor_layout.addWidget(self._button_widget) 36 | 37 | self._layout.addLayout(self._hor_layout) 38 | self.setLayout(self._layout) 39 | 40 | self._button_widget.pressed.connect(self.openFilePath) 41 | 42 | 43 | def set_text_value(self, path_str: str): 44 | self._text_box.setText(path_str) 45 | 46 | def file_widget_line(self): 47 | return self._text_box 48 | 49 | def openFilePath(self): 50 | file_name = self._file_dialog.getSaveFileName(self,'File Path', UIWindowManger.WindowsManger.root_save(), '*.') 51 | self._text_box.setText(file_name[0]) 52 | 53 | def fileType(self, index: int): 54 | pass 55 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/StringEditTemplate/StringEditWidgetClass.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets, QtGui 2 | from PySideLayoutTool.UIEditorLib.StringValidatorClass import checkString 3 | from PySideLayoutTool.UIEditorLib import UIEditorScript 4 | 5 | class BasicStringWidget(QtWidgets.QWidget): 6 | 7 | def __init__(self, default_text, validator=2, validators_lvl=0): 8 | super(BasicStringWidget, self).__init__() 9 | self.validator = self.validater_type(validator) 10 | self.validator_level = validators_lvl 11 | self.setMinimumHeight(40) 12 | self.setMaximumHeight(40) 13 | 14 | self._layout = QtWidgets.QVBoxLayout() 15 | self._layout.setSpacing(0) 16 | self._layout.setContentsMargins(0, 0, 0, 0) 17 | 18 | self._str_widget = QtWidgets.QLineEdit() 19 | self._str_widget.setValidator(self.validator) 20 | self._str_widget.setText(default_text) 21 | 22 | self._layout.addWidget(self._str_widget) 23 | self.setLayout(self._layout) 24 | 25 | self._str_widget.textChanged.connect(self.updateText) 26 | 27 | def string_widget(self): 28 | return self._str_widget 29 | 30 | def updateText(self, arg__1): 31 | if self.validator == QtGui.QRegExpValidator and self.validator_level == 1: 32 | self._str_widget.setText(checkString(arg__1)) 33 | 34 | def validater_type(self, index: int): 35 | return [ 36 | QtGui.QIntValidator(), 37 | QtGui.QDoubleValidator(), 38 | QtGui.QRegExpValidator() 39 | ][index] 40 | 41 | 42 | class MultiStringWidget(QtWidgets.QWidget): 43 | 44 | def __init__(self, use_color_text: bool): 45 | super(MultiStringWidget, self).__init__() 46 | self._layout = QtWidgets.QVBoxLayout() 47 | self._layout.setSpacing(0) 48 | self._layout.setContentsMargins(0,10,0,0) 49 | 50 | self._label_widget = QtWidgets.QLabel('None') 51 | 52 | self._multiline_text_widget = UIEditorScript.ScriptEditor() if use_color_text else QtWidgets.QPlainTextEdit() 53 | 54 | self._layout.addWidget(self._label_widget) 55 | self._layout.addSpacing(5) 56 | self._layout.addWidget(self._multiline_text_widget) 57 | 58 | self.setLayout(self._layout) 59 | 60 | def text_window_lines(self, min , max): 61 | pass 62 | 63 | 64 | def set_label_text(self, text: str): 65 | self._label_widget.setText(text) 66 | 67 | def text(self): 68 | return self._multiline_text_widget.document().toPlainText() -------------------------------------------------------------------------------- /PySideLayoutTool/resources/pysidelayouticons.qrc: -------------------------------------------------------------------------------- 1 | 2 |Parameter: {self.name() + '_min'}
{self.tooltip()} " if self.tooltip() != '' else f"Parameter: {self.name() + '_min'}
") 27 | self._range_widget.minEdit_widget.setStyleSheet("QToolTip { color: #ffffff; background-color: #484848; border: 0px;}") 28 | 29 | self._range_widget.maxEdit_widget.setToolTip(f"Parameter: {self.name() + '_max'}
{self.tooltip()} " if self.tooltip() != '' else f"Parameter: {self.name() + '_max'}
") 30 | self._range_widget.maxEdit_widget.setStyleSheet("QToolTip { color: #ffffff; background-color: #484848; border: 0px;}") 31 | 32 | self._range_widget.minEdit_widget.setRange(self.clampRange().min if self.clampRange().minLock else -1000000,self.clampRange().max if self.clampRange().maxLock else 1000000) 33 | self._range_widget.maxEdit_widget.setRange(self.clampRange().min if self.clampRange().minLock else -1000000,self.clampRange().max if self.clampRange().maxLock else 1000000) 34 | 35 | self._range_widget.minEdit_widget.setValue(self.clampRange().min) 36 | self._range_widget.maxEdit_widget.setValue(self.clampRange().max) 37 | self._range_widget.minLock_widget.setChecked(self.clampRange().minLock) 38 | self._range_widget.maxLock_widget.setChecked(self.clampRange().maxLock) 39 | 40 | self._parent._widgets[self.name() + '_min'] = self._range_widget.minEdit_widget 41 | self._parent._widgets[self.name() + '_max'] = self._range_widget.minEdit_widget 42 | 43 | 44 | def eval(self): 45 | return self._range_widget.minEdit_widget.value(), self._range_widget.maxEdit_widget.value(), self._range_widget.minLock_widget.isChecked(), self._range_widget.maxLock_widget.isChecked() 46 | 47 | 48 | 49 | class FloatRangeWidgetSetup(RangeWidgetSetup): 50 | 51 | def __init__(self,parent): 52 | super(FloatRangeWidgetSetup, self).__init__(parent, False) 53 | 54 | 55 | 56 | class IntRangeWidgetBuildClass(TemplateBuildClass.ParameterBuild): 57 | 58 | def widgetClass(self): 59 | return RangeWidgetSetup 60 | 61 | class FloatRangeWidgetBuildClass(TemplateBuildClass.ParameterBuild): 62 | 63 | def widgetClass(self): 64 | return FloatRangeWidgetSetup 65 | 66 | 67 | 68 | def register(): 69 | UIEditorFactory.WidgetFactory.register('Min/Max Integer', IntRangeWidgetBuildClass) 70 | UIEditorFactory.WidgetFactory.register('Min/Max Float', FloatRangeWidgetBuildClass) -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ColorTemplate/ColorClass.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets, QtCore 2 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory 3 | from . import ColorWidgetClass 4 | from ..LineEditTemplate import LineEditWidgets 5 | 6 | 7 | class ColorSetupClass(LayoutTemplate.ParmSetup): 8 | 9 | def __init__(self, parent, useAlpha=False): 10 | super(ColorSetupClass, self).__init__(parent) 11 | self._hor_layout = QtWidgets.QHBoxLayout() 12 | self._hor_layout.setSpacing(3) 13 | self._hor_layout.setContentsMargins(0, 0, 0, 0) 14 | self._hor_layout.setAlignment(QtCore.Qt.AlignLeft) 15 | 16 | self._r = LineEditWidgets.LineEditFloatWidgetClass(parent=self, steps=0.1) 17 | self._r.setRange(0, 1) 18 | r_hint_widget = self._r.addHint('R') 19 | r_hint_widget.setProperty('class', 'x_property') 20 | 21 | self._g = LineEditWidgets.LineEditFloatWidgetClass(parent=self, steps=0.1) 22 | self._g.setRange(0, 1) 23 | g_hint_widget = self._g.addHint('G') 24 | g_hint_widget.setProperty('class', 'y_property') 25 | 26 | self._b = LineEditWidgets.LineEditFloatWidgetClass(parent=self, steps=0.1) 27 | self._b.setRange(0, 1) 28 | b_hint_widget = self._b.addHint('B') 29 | b_hint_widget.setProperty('class', 'z_property') 30 | 31 | self._alpha = None 32 | 33 | if useAlpha: 34 | self._alpha = LineEditWidgets.LineEditFloatWidgetClass(parent=self, steps=0.1) 35 | self._alpha.addHint('A') 36 | 37 | self._color_button = ColorWidgetClass.ColorButtonWidget(self, bAlpha=useAlpha) 38 | 39 | self._hor_layout.addWidget(self._color_button) 40 | self._hor_layout.addWidget(self._r) 41 | self._hor_layout.addWidget(self._g) 42 | self._hor_layout.addWidget(self._b) 43 | 44 | self._r.base_widget().valueChanged.connect(self._color_button.colorPickerWidget()._colorEdited) 45 | self._g.base_widget().valueChanged.connect(self._color_button.colorPickerWidget()._colorEdited) 46 | self._b.base_widget().valueChanged.connect(self._color_button.colorPickerWidget()._colorEdited) 47 | 48 | self._r.base_widget().valueChanged.connect(self._color_changed) 49 | self._g.base_widget().valueChanged.connect(self._color_changed) 50 | self._b.base_widget().valueChanged.connect(self._color_changed) 51 | 52 | if self._alpha: 53 | self._alpha.base_widget().valueChanged.connect(self._color_button.colorPickerWidget()._colorEdited) 54 | self._alpha.base_widget().valueChanged.connect(self._color_changed) 55 | self._hor_layout.addWidget(self._alpha) 56 | 57 | self._layout.addLayout(self._hor_layout) 58 | 59 | def _color_changed(self, arg): 60 | self.notify_expressions() 61 | 62 | def setValue(self, value): 63 | value = list(value) 64 | self._r.setValue(float(value[0])) 65 | self._g.setValue(float(value[1])) 66 | self._b.setValue(float(value[2])) 67 | 68 | def PostUpdate(self): 69 | pass 70 | 71 | def eval(self): 72 | return self._r.value(), self._g.value(), self._b.value() 73 | 74 | 75 | class ColorAlphaSetupClass(ColorSetupClass): 76 | 77 | def __init__(self, parent): 78 | super(ColorAlphaSetupClass, self).__init__(parent, useAlpha=True) 79 | 80 | def setValue(self, value): 81 | super(ColorAlphaSetupClass, self).setValue(value) 82 | self._alpha.setValue(value[3]) 83 | 84 | def eval(self): 85 | return self._r.value(), self._g.value(), self._b.value(), self._alpha.value() 86 | 87 | 88 | class ColorBuildClass(TemplateBuildClass.ParameterBuild): 89 | 90 | def widgetClass(self): 91 | return ColorSetupClass 92 | 93 | 94 | class ColorAlphaBuildClass(TemplateBuildClass.ParameterBuild): 95 | 96 | def widgetClass(self): 97 | return ColorAlphaSetupClass 98 | 99 | 100 | def register(): 101 | UIEditorFactory.WidgetFactory.register('Color', ColorBuildClass) 102 | UIEditorFactory.WidgetFactory.register('Color-Alpha', ColorAlphaBuildClass) 103 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/IconRegistration.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib.UIEditorIconFactory import IconEditorFactory 2 | from PySide2.QtGui import QIcon, QPixmap 3 | 4 | 5 | def register() -> None: 6 | resource_path = ':/resources/Icons' 7 | 8 | IconEditorFactory.register('folder_nor', QIcon(QPixmap(f'{resource_path}/normal_folder.svg'))) 9 | IconEditorFactory.register('folder_add', QIcon(QPixmap(f'{resource_path}/folder_add.svg'))) 10 | IconEditorFactory.register('folder_sub', QIcon(QPixmap(f'{resource_path}/folder_minus.svg'))) 11 | 12 | IconEditorFactory.register('lock_open', QIcon(QPixmap(f'{resource_path}/lock_unlocked.svg'))) 13 | IconEditorFactory.register('lock_closed', QIcon(QPixmap(f'{resource_path}/lock_locked.svg'))) 14 | 15 | IconEditorFactory.register('splitter_v1', QIcon(QPixmap(f'{resource_path}/vertical_alt.svg'))) 16 | IconEditorFactory.register('splitter_v2', QIcon(QPixmap(f'{resource_path}/splitter_vertical_alt_2.svg'))) 17 | 18 | IconEditorFactory.register('separtor_v1', QIcon(QPixmap(f'{resource_path}/border_style_dashed_sep.svg'))) 19 | IconEditorFactory.register('separtor_v2', QIcon(QPixmap(f'{resource_path}/border_style_solid_sep.svg'))) 20 | 21 | IconEditorFactory.register('arrow_v1_right', QIcon(QPixmap(f'{resource_path}/chevron_arrow_right.svg'))) 22 | IconEditorFactory.register('arrow_v1_down', QIcon(QPixmap(f'{resource_path}/chevron_arrow_down.svg'))) 23 | 24 | IconEditorFactory.register('unchecked', QIcon(QPixmap(f'{resource_path}/checkbox_unchecked.svg'))) 25 | IconEditorFactory.register('checked', QIcon(QPixmap(f'{resource_path}/checkbox_checked.svg'))) 26 | 27 | IconEditorFactory.register('eye_v1', QIcon(QPixmap(f'{resource_path}/eye_view.svg'))) 28 | 29 | IconEditorFactory.register('move_right', QIcon(QPixmap(f'{resource_path}/move_right_arrow.svg'))) 30 | IconEditorFactory.register('move_left', QIcon(QPixmap(f'{resource_path}/move_left_arrow.svg'))) 31 | 32 | IconEditorFactory.register('comment', QIcon(QPixmap(f'{resource_path}/comment.svg'))) 33 | 34 | IconEditorFactory.register('zoom_In',QIcon(QPixmap(f'{resource_path}/zoom_in.svg'))) 35 | IconEditorFactory.register('zoom_Out', QIcon(QPixmap(f'{resource_path}/zoom_out.svg'))) 36 | 37 | IconEditorFactory.register('add_file', QIcon(QPixmap(f'{resource_path}/add_file.svg'))) 38 | 39 | IconEditorFactory.register('arrow_exchange_alt', QIcon(QPixmap(f'{resource_path}/arrow_exchange_alt.svg'))) 40 | IconEditorFactory.register('arrow_exchange_v', QIcon(QPixmap(f'{resource_path}/arrow_exchange_v.svg'))) 41 | 42 | IconEditorFactory.register('arrow_open', QIcon(QPixmap(f'{resource_path}/arrow_chevron_up.svg'))) 43 | IconEditorFactory.register('arrow_close', QIcon(QPixmap(f'{resource_path}/arrow_chevron_down.svg'))) 44 | 45 | IconEditorFactory.register('menu_list', QIcon(QPixmap(f'{resource_path}/menu_list_display.svg'))) 46 | 47 | def unregister() -> None: 48 | IconEditorFactory.unregister('folder_nor') 49 | IconEditorFactory.unregister('folder_add') 50 | IconEditorFactory.unregister('folder_sub') 51 | 52 | IconEditorFactory.unregister('lock_open') 53 | IconEditorFactory.unregister('lock_closed') 54 | 55 | IconEditorFactory.unregister('splitter_v1') 56 | IconEditorFactory.unregister('splitter_v2') 57 | 58 | IconEditorFactory.unregister('separtor_v1') 59 | IconEditorFactory.unregister('separtor_v2') 60 | 61 | IconEditorFactory.unregister('arrow_v1_right') 62 | IconEditorFactory.unregister('arrow_v1_down') 63 | 64 | IconEditorFactory.unregister('unchecked') 65 | IconEditorFactory.unregister('checked') 66 | 67 | IconEditorFactory.unregister('eye_v1') 68 | 69 | IconEditorFactory.unregister('move_right') 70 | IconEditorFactory.unregister('move_left') 71 | 72 | IconEditorFactory.unregister('comment') 73 | 74 | IconEditorFactory.unregister('zoom_In') 75 | IconEditorFactory.unregister('zoom_Out') 76 | 77 | IconEditorFactory.unregister('add_file') 78 | 79 | IconEditorFactory.unregister('arrow_exchange_alt') 80 | IconEditorFactory.unregister('arrow_exchange_v') 81 | 82 | IconEditorFactory.unregister('arrow_open') 83 | IconEditorFactory.unregister('arrow_close') 84 | 85 | IconEditorFactory.unregister('menu_list') -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorLib/WindowsModule.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Callable, Any, List 2 | from PySideLayoutTool.UIEditorWindows import MainEditorWindow 3 | from PySideLayoutTool.UIEditorWindows import MainLayoutWindow 4 | from PySideLayoutTool.UIEditorLib import UIEditorMediators 5 | 6 | 7 | class WindowsManger: 8 | 9 | UI_Wins_Names: Dict[str, List[str]] = {} 10 | UI_Wins: Dict[str, Dict[str, Dict[str,Any]]] = {} 11 | UI_Wins_Names_Category: Dict[str, Dict[str, List[str]]] = {} 12 | 13 | plugins_found: Dict[str, Dict[str, Any]] = {} 14 | 15 | DCC_parent_func: Callable[..., Any] = None 16 | Save_Path = '' 17 | Plugin_Path = '' 18 | 19 | #TODO: Refactor this function. 20 | @classmethod 21 | def add_to_stack(cls, main_name_given: str, editor_obj: Any, layout_obj: Any, win_category) -> None: 22 | editor_name = main_name_given + '_editor' 23 | temp_editor_dict = {} 24 | temp_editor_dict[editor_name] = editor_obj 25 | 26 | layout_name = main_name_given + '_layout' 27 | temp_layout_dict = {} 28 | temp_layout_dict[layout_name] = layout_obj 29 | 30 | temp_editor_dict.update(temp_layout_dict) 31 | temp_UI_Win = {} 32 | temp_UI_Win[main_name_given] = temp_editor_dict 33 | 34 | cls.UI_Wins_Names[main_name_given] = [editor_name, layout_name] 35 | 36 | if win_category in cls.UI_Wins: 37 | cls.UI_Wins[win_category].update(temp_UI_Win) 38 | else: 39 | cls.UI_Wins[win_category] = temp_UI_Win 40 | 41 | temp_UI_Win_Names = {} 42 | temp_UI_Win_Names[main_name_given] = [editor_name, layout_name] 43 | cls.UI_Wins_Names_Category[win_category] = temp_UI_Win_Names 44 | 45 | @classmethod 46 | def add_plugin(cls, name : str, enabled : bool, path: str): 47 | cls.plugins_found[name] = {} 48 | cls.plugins_found[name]['Enabled'] = enabled 49 | cls.plugins_found[name]['Path'] = path 50 | 51 | @classmethod 52 | def get_plugins(cls): 53 | return cls.plugins_found 54 | 55 | @classmethod 56 | def set_plugin_path(cls, path: str): 57 | cls.Plugin_Path = path 58 | 59 | @classmethod 60 | def get_plugin_path(cls): 61 | return cls.Plugin_Path 62 | 63 | @classmethod 64 | def root_save(cls): 65 | return cls.Save_Path 66 | 67 | @classmethod 68 | def set_root_save(cls, path: str): 69 | cls.Save_Path = path 70 | 71 | @classmethod 72 | def setParentDCC(cls, func: Callable[..., Any]): 73 | cls.DCC_parent_func = func 74 | 75 | @classmethod 76 | def get_Stack(cls, find_name: str, category_name: str): 77 | if category_name in cls.UI_Wins: 78 | if find_name in cls.UI_Wins[category_name]: 79 | return cls.UI_Wins[category_name][find_name] 80 | else: 81 | ValueError('Category name not in stack') 82 | 83 | return None 84 | 85 | @classmethod 86 | def window_names(cls): 87 | return cls.UI_Wins_Names.keys() 88 | 89 | @classmethod 90 | def category_names(cls): 91 | return cls.UI_Wins_Names_Category.keys() 92 | 93 | @classmethod 94 | def isNameInCategory(cls, find_name: str, category_name: str): 95 | if category_name in cls.UI_Wins: 96 | if find_name in cls.UI_Wins[category_name]: 97 | return True 98 | else: 99 | return False 100 | return False 101 | 102 | @classmethod 103 | def initilize_windows(cls, win_name: str, path_save: str, win_category='User'): 104 | new_editor = MainEditorWindow.EditorWindow(win_name, path_save, win_category) 105 | new_layout = MainLayoutWindow.MainWindowLayout(win_name) 106 | meditor = UIEditorMediators.EditorsMediator(new_editor, new_layout) 107 | meditor.notify_full_serialization() 108 | cls.add_to_stack(win_name, new_editor, new_layout, win_category) 109 | 110 | 111 | @classmethod 112 | def window_show(cls, instance): 113 | if cls.DCC_parent_func: 114 | instance.show() 115 | cls.DCC_parent_func(instance) 116 | else: 117 | instance.show() 118 | 119 | 120 | @classmethod 121 | def restoreState(cls,data): 122 | win_instance_editor = cls.get_Stack(data['Name'],data['Category'])[data['Name'] + '_editor'] 123 | win_instance_editor.restoreUIState(data) 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorWindows/InitWindow.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets, QtCore, QtGui 2 | from PySideLayoutTool.UIEditorLib import StringValidatorClass, WindowsModule 3 | from PySideLayoutTool.UIEditorTemplates.Common.SeparatorTemplate import SeparatorWidgetClass 4 | from . import NotificationSetup 5 | 6 | 7 | class UISetupWin(QtWidgets.QDialog): 8 | 9 | def __init__(self,notify_state: bool, settings_win, parent=None): 10 | super(UISetupWin, self).__init__(parent) 11 | self.setWindowTitle('Create Layout') 12 | size = QtCore.QSize(450, 150) 13 | self.setMinimumSize(size) 14 | self.setMaximumHeight(150) 15 | 16 | self._save_path = '' 17 | 18 | self._layout = QtWidgets.QVBoxLayout() 19 | self._form_layout = QtWidgets.QFormLayout() 20 | self._hor_layout = QtWidgets.QHBoxLayout() 21 | 22 | self._UI_name = QtWidgets.QLineEdit() 23 | self._path_str = QtWidgets.QLineEdit() 24 | self._category_str = QtWidgets.QLineEdit() 25 | self._category_str.setText('User') 26 | 27 | self._path_str.setText(WindowsModule.WindowsManger.root_save() + '/') 28 | self._notification_win = NotificationSetup.NotificationWindow() 29 | self._setting_win = settings_win 30 | 31 | self._button_file_browser = QtWidgets.QPushButton() 32 | self._file_dialog = QtWidgets.QFileDialog() 33 | self._create_button = QtWidgets.QPushButton('Create') 34 | 35 | self._setting_button = QtWidgets.QPushButton() 36 | self._setting_button.setFixedHeight(15) 37 | self._setting_button.setIcon(QtGui.QIcon(':/icons/setting_icon')) 38 | self._setting_button.setProperty('class', 'setting_button') 39 | self._setting_button.setToolTip(f" Setting")
40 | self._setting_button.setStyleSheet("QToolTip { color: #ffffff; background-color: #484848; border: 0px;}")
41 |
42 | self._hor_layout.addWidget(self._path_str)
43 | self._hor_layout.addWidget(self._button_file_browser)
44 |
45 | self._form_layout.addRow('UI Name : ', self._UI_name)
46 | self._form_layout.addRow('UI Path : ', self._hor_layout)
47 | self._form_layout.addRow('Category : ', self._category_str)
48 |
49 | self._layout.addLayout(self._form_layout)
50 | self._layout.addWidget(SeparatorWidgetClass.SeparatorHWidget())
51 | self._layout.addWidget(self._create_button)
52 | self._layout.addWidget(self._setting_button)
53 |
54 | self.setLayout(self._layout)
55 |
56 | if notify_state:
57 | WindowsModule.WindowsManger.window_show(self._notification_win)
58 |
59 | self._UI_name.textChanged.connect(self.check_name)
60 | self._button_file_browser.pressed.connect(self.open_browser)
61 | self._create_button.pressed.connect(self.new_ui)
62 |
63 | self._setting_button.pressed.connect(self._display_setting)
64 |
65 | def closeEvent(self, event):
66 | self._notification_win.close()
67 | self._setting_win.close()
68 |
69 | def event(self, event) -> bool:
70 | if event.type() == QtCore.QEvent.EnterWhatsThisMode:
71 | WindowsModule.WindowsManger.window_show(self._notification_win)
72 |
73 | return QtWidgets.QDialog.event(self, event)
74 |
75 | def _display_setting(self):
76 | WindowsModule.WindowsManger.window_show(self._setting_win)
77 |
78 |
79 | def check_name(self):
80 | new_name = StringValidatorClass.checkString(self._UI_name.text())
81 | self._UI_name.setText(new_name)
82 | full_name_path = WindowsModule.WindowsManger.root_save() + f'/{new_name}.qui'
83 | self._path_str.setText(full_name_path)
84 | self._save_path = full_name_path
85 |
86 | def open_browser(self):
87 | file_name = self._file_dialog.getSaveFileName(self, 'Save Path', WindowsModule.WindowsManger.root_save(),
88 | '.qui')
89 | self._save_path = file_name[0]
90 | self._path_str.setText(self._save_path)
91 |
92 | def new_ui(self):
93 | if self._UI_name.text() == '':
94 | return
95 |
96 | WindowsModule.WindowsManger.initilize_windows(self._UI_name.text(), self._save_path, self._category_str.text())
97 | WindowsModule.WindowsManger.window_show(
98 | WindowsModule.WindowsManger.get_Stack(self._UI_name.text(), self._category_str.text())[
99 | self._UI_name.text() + '_editor'])
100 | self.close()
101 | self._notification_win.close()
102 | self._setting_win.close()
103 |
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorTemplates/Folder/TabFolderTemplate/FolderTabClasses.py:
--------------------------------------------------------------------------------
1 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory, TemplateDataClass
2 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty
3 | from . import FolderTabWidgetClass
4 |
5 | class FolderListClass(LayoutTemplate.FolderSetup):
6 |
7 | def __init__(self,parent=None):
8 | super(FolderListClass, self).__init__(parent)
9 |
10 | @UIProperty(metaWidget='CheckProperty', label='End Tab Group', category='Setting')
11 | def endGroup(self):
12 | pass
13 |
14 | def clearLayout(self):
15 | self._childWidgets.deleteLater()
16 | self._childWidgets = TemplateDataClass.TemplateGroup()
17 |
18 | def setParentTab(self, arg: bool):
19 | if arg:
20 | if self._folder_widget:
21 | self._folder_widget.deleteLater()
22 |
23 | self._folder_widget = FolderTabWidgetClass.FolderTabList(self, self._childWidgets)
24 | self._layout.addWidget(self._folder_widget)
25 |
26 | def bisFolderList(self):
27 | return True
28 |
29 |
30 |
31 | class FolderMultiTabClass(LayoutTemplate.FolderSetup):
32 |
33 | def __init__(self,parent=None):
34 | super(FolderMultiTabClass, self).__init__(parent)
35 | self._folder_widget = FolderTabWidgetClass.FolderMultiTabWidget(self._childWidgets, parent=self)
36 | self._layout.addWidget(self._folder_widget)
37 |
38 | self._folder_widget.tabWidget.tabBarClicked.connect(self._new_tab_change)
39 | self._folder_widget.tabWidget.tabBar().tabCloseRequested.connect(self._close_tab_change) # type: ignore
40 |
41 | @UIProperty(metaWidget='ComboProperty', label='Tab Placements', category='Setting', defaults=['Top','Left','Right'])
42 | def tabPlacement(self):
43 | pass
44 |
45 |
46 | def _new_tab_change(self,index ):
47 | if self._folder_widget.tabWidget.tabText(index) == "+":
48 | self.notify_expressions()
49 |
50 | def eval(self) -> int or float:
51 | return self._folder_widget.tabWidget.count()
52 |
53 |
54 | def clearLayout(self):
55 | count = self._folder_widget.count()
56 | if count >= 1:
57 | for i in range(0, count):
58 | widget_template = self._folder_widget.tabWidget.widget(i)
59 | widget_template.deleteLater()
60 |
61 | self._folder_widget.clear_tabwidget_data()
62 |
63 | for i in range(0,count):
64 | self._folder_widget.insert_tab(i)
65 |
66 |
67 |
68 | def PostUpdate(self):
69 | self._folder_widget.setPlacement(self.tabPlacement().currentItem_index)
70 |
71 |
72 |
73 | class FolderMultiListWidgetClass(LayoutTemplate.FolderSetup):
74 |
75 | def __init__(self, scroll_enable=False, parent=None):
76 | super(FolderMultiListWidgetClass, self).__init__(parent)
77 | self._folder_widget = FolderTabWidgetClass.FolderMultiTabList(self._childWidgets, scroll_enable, parent=self)
78 | self._layout.addWidget(self._folder_widget)
79 |
80 | self._folder_widget.add_button_widget().clicked.connect(self._new_widget)
81 | self._folder_widget.clear_button_widget().clicked.connect(self._close_tab_change)
82 |
83 | def _new_widget(self):
84 | self.notify_conditions()
85 |
86 | def eval(self) -> int or float:
87 | return self._folder_widget.count()
88 |
89 | def clearLayout(self):
90 | count = self._folder_widget.count()
91 | if count >= 1:
92 | self._folder_widget.clearWidgets()
93 |
94 | for i in range(0, count):
95 | self._folder_widget.new_widget()
96 |
97 |
98 | def PostUpdate(self):
99 | self._folder_widget.setName(self.label())
100 |
101 |
102 | class FolderMultiListScrollWidgetClass(FolderMultiListWidgetClass):
103 |
104 | def __init__(self, parent=None):
105 | super(FolderMultiListScrollWidgetClass, self).__init__(scroll_enable=True, parent=parent)
106 |
107 |
108 |
109 |
110 | class FolderListTab(TemplateBuildClass.FolderBuild):
111 |
112 | def widgetClass(self):
113 | return FolderListClass
114 |
115 |
116 |
117 | class MultiTabFolder(TemplateBuildClass.FolderBuild):
118 |
119 | def widgetClass(self):
120 | return FolderMultiTabClass
121 |
122 |
123 | class MultiListWidgetFolder(TemplateBuildClass.FolderBuild):
124 |
125 | def widgetClass(self):
126 | return FolderMultiListWidgetClass
127 |
128 |
129 | class MultiListScrollWidgetFolder(TemplateBuildClass.FolderBuild):
130 |
131 | def widgetClass(self):
132 | return FolderMultiListScrollWidgetClass
133 |
134 |
135 | def register() -> None:
136 | UIEditorFactory.WidgetFactory.register('Tabs', FolderListTab)
137 | UIEditorFactory.WidgetFactory.register('Multiparm Block (Tabs)', MultiTabFolder)
138 | UIEditorFactory.WidgetFactory.register('Multiparm Block (List)', MultiListWidgetFolder)
139 | UIEditorFactory.WidgetFactory.register('Multiparm Block (Scroll)', MultiListScrollWidgetFolder)
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorLib/boilerplate_class.py:
--------------------------------------------------------------------------------
1 | from PySideLayoutTool.UIEditorLib.UIEditorFactory import WidgetFactory
2 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty
3 | import PySideLayoutTool.UIEditorLib.TemplateBuildClass as TemplateBuildClass
4 | import PySideLayoutTool.UIEditorLib.LayoutTemplate as LayoutTemplate
5 |
6 | # Base widget class template
7 | """
8 | LayoutTemplate.ParmSetup : is for most common parameters.
9 | LayoutTemplate.FolderSetup : is good for folder type templates.
10 |
11 | """
12 |
13 |
14 | class NAMEClass(LayoutTemplate.SETUPTYPE):
15 |
16 | def __init__(self, parent=None):
17 | super(NAMEClass, self).__init__(parent)
18 | self._widget = NAMELayout.NAMELayoutClass() # NAMELayoutClass is the layout class for your widget.
19 | self._layout.addWidget(self._widget) # Add your widget to the layout.
20 |
21 | """
22 | UIProperty decorator which will add a widget info filler
23 | for the widget description.
24 |
25 | Current Widget Properties supported:
26 | - CheckProperty
27 | - ClampProperty
28 | - ComboProperty
29 | - DictionaryProperty
30 | - LineEditProperty
31 |
32 | example:
33 | @UIProperty(metaWidget='CheckProperty',label='Check Demo', category='Solo')
34 | def demo_check(self):
35 | pass
36 |
37 | functions with UIProperty decorator will be added to the widget properties.
38 | Keep noted functions with UIProperty decorator must have a pass statement. (No code)
39 |
40 | Can also make your own Property Widget and register to the system.
41 |
42 | """
43 | def PostUpdate(self):
44 | super(NAMEClass, self).PostUpdate()
45 | # Add any post update code here.
46 |
47 | def PreUpdate(self):
48 | pass
49 | # Before widget is added to the layout and values are given to it.
50 |
51 |
52 | # Class for properly building the widget with the application.
53 | """
54 | TemplateBuildClass.ParameterBuild: for most common parameters.
55 | TempalteBuildClass.FolderBuild: good for folder types, handling items within items
56 |
57 | """
58 |
59 |
60 | class NAMEBuild(TemplateBuildClass.BUILDTYPE):
61 |
62 | def widgetClass(self):
63 | return NAMEClass
64 |
65 |
66 | """
67 | register() and unregister() are required for the plugin widget to be loaded.
68 | """
69 |
70 | """
71 | Register widget to be shown in supported templates.
72 | """
73 |
74 |
75 | def register():
76 | WidgetFactory.register('WIDGET LABEL', NAMEBuild)
77 |
78 |
79 | def unregister():
80 | WidgetFactory.unregister('WIDGET LABEL')
81 |
82 |
83 | #------------------------------
84 |
85 | import PySide2.QtWidgets as QtWidgets
86 |
87 |
88 | # Class to layout your widgets
89 | class NAMELayoutClass(QtWidgets.QWidget):
90 |
91 | def __init__(self):
92 | super(NAMELayoutClass, self).__init__()
93 | self._base_layout = QtWidgets.QVBoxLayout()
94 | self._base_layout.setSpacing(0)
95 | self._base_layout.setContentsMargins(0, 0, 0, 0)
96 |
97 | self._hbox_layout = QtWidgets.QHBoxLayout()
98 | self._hbox_layout.setSpacing(0)
99 | self._hbox_layout.setContentsMargins(0, 0, 0, 0)
100 |
101 | self._line_widget = QtWidgets.QLineEdit('Testing')
102 | self._button_widget = QtWidgets.QPushButton("Push")
103 |
104 | self._hbox_layout.addWidget(self._line_widget)
105 | self._hbox_layout.addWidget(self._button_widget)
106 |
107 | self._base_layout.addLayout(self._hbox_layout)
108 | self.setLayout(self._base_layout)
109 |
110 |
111 | #------------------------------
112 |
113 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UICProperty, PropertyFactory, IWidgetProperties
114 |
115 | @PropertyFactory.register('NAMEProperty')
116 | class NAMEProperty(IWidgetProperties):
117 |
118 | def __init__(self):
119 | super(NAMEProperty, self).__init__()
120 | self._widget = None # Add custom Widget here, this is the widget that will be added to the layout.
121 | self._layout.addWidget(self._widget)
122 |
123 | def override_default(self, defaults: tuple):
124 | pass
125 |
126 | def setValue(self, value):
127 | pass
128 |
129 | def value(self):
130 | return None
131 | """
132 | Add @UICProperty decorator to any function that you want to be a property value
133 | that can be accessed by Widget setup.
134 |
135 | example:
136 | Base WidgetSetup class has a property called invisible.
137 |
138 | @UIProperty(metaWidget='CheckProperty', label='Invisible', category='Setting')
139 | def invisible(self):
140 | pass
141 |
142 | And in PostUpdate() function we call the invisible() function to get the value.
143 |
144 | def PostUpdate(self):
145 | super(ExampleClass, self).PostUpdate()
146 | self.invisible().mark
147 |
148 | This will return a bool value of the invisible property which mark has the decorator @UICProperty.
149 |
150 | @UICProperty
151 | def example(self):
152 | return self._state
153 | """
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorTemplates/Common/DictionaryTemplate/DictionaryWidgetClass.py:
--------------------------------------------------------------------------------
1 | from PySide2 import QtWidgets, QtCore
2 |
3 |
4 | class DictWidgetClass(QtWidgets.QWidget):
5 |
6 | def __init__(self):
7 | super(DictWidgetClass, self).__init__()
8 | self._layout = QtWidgets.QVBoxLayout()
9 | self._layout.setSpacing(0)
10 | self._layout.setContentsMargins(0,0,0,0)
11 | self._layout.setAlignment(QtCore.Qt.AlignTop)
12 |
13 | self._dict_key_value = {}
14 |
15 | self.table_widget = QtWidgets.QTableWidget(1, 2)
16 | self.table_widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
17 | self._table_size = 62
18 | self._table_height = 30
19 |
20 | hor_header = self.table_widget.horizontalHeader()
21 | hor_header.setSectionResizeMode(0, QtWidgets.QHeaderView.Interactive)
22 | hor_header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
23 |
24 | vert_header = self.table_widget.verticalHeader()
25 | vert_header.setProperty('class','side_HeaderView')
26 | vert_header.setSectionResizeMode(0,QtWidgets.QHeaderView.Fixed)
27 |
28 | self.table_widget.setMinimumHeight(self._table_size)
29 | self.table_widget.setMaximumHeight(self._table_size)
30 |
31 | self.table_widget.setHorizontalHeaderLabels(['Key', 'Value'])
32 |
33 | hor_layout = QtWidgets.QHBoxLayout()
34 | hor_layout.setSpacing(3)
35 | hor_layout.setContentsMargins(0,0,0,0)
36 | hor_layout.setAlignment(QtCore.Qt.AlignLeft)
37 |
38 | self.add_button = QtWidgets.QPushButton('+')
39 | self.add_button.setMinimumWidth(25)
40 | self.add_button.setMaximumWidth(25)
41 | self.add_button.setProperty('class', 'add_press')
42 |
43 | self.sub_button = QtWidgets.QPushButton('-')
44 | self.sub_button.setMinimumWidth(25)
45 | self.sub_button.setMaximumWidth(25)
46 | self.sub_button.setProperty('class', 'red_press')
47 |
48 |
49 | hor_layout.addWidget(self.add_button)
50 | hor_layout.addWidget(self.sub_button)
51 |
52 | self._layout.addWidget(self.table_widget)
53 | self._layout.addSpacing(2)
54 | self._layout.addLayout(hor_layout)
55 |
56 | self.setLayout(self._layout)
57 |
58 | self.add_button.clicked.connect(self.addDict)
59 | self.sub_button.clicked.connect(self.removeDict)
60 |
61 | self.table_widget.cellChanged.connect(self.cellText)
62 |
63 | def base_table_height(self):
64 | return self._table_height
65 |
66 | def count(self):
67 | return self.table_widget.rowCount()
68 |
69 | def addDict(self):
70 | count = self.table_widget.rowCount()
71 | self.table_widget.insertRow(count)
72 |
73 | if count < 5:
74 | self._table_size += self._table_height
75 |
76 | self.table_widget.setMinimumHeight(self._table_size)
77 | self.table_widget.setMaximumHeight(self._table_size)
78 | vert_header = self.table_widget.verticalHeader()
79 | vert_header.setSectionResizeMode(count, QtWidgets.QHeaderView.Fixed)
80 |
81 | def removeDict(self):
82 | count = self.table_widget.rowCount()
83 | if count > 1:
84 | self.table_widget.removeRow(count - 1)
85 | if count <= 5:
86 | self._table_size -= self._table_height
87 |
88 | self.table_widget.setMinimumHeight(self._table_size)
89 | self.table_widget.setMaximumHeight(self._table_size)
90 | self.table_widget.resize(self.table_widget.sizeHint().width(), self.table_widget.sizeHint().height())
91 |
92 |
93 | def setkeyText(self, row: int, text: str):
94 | item = self.table_widget.item(row, 0)
95 | if not item:
96 | self.table_widget.setItem(row,0,QtWidgets.QTableWidgetItem(text))
97 | else:
98 | item.setText(text)
99 |
100 | def setvalueText(self,row: int, text: str):
101 | item = self.table_widget.item(row, 1)
102 | if not item:
103 | self.table_widget.setItem(row,1,QtWidgets.QTableWidgetItem(text))
104 | else:
105 | item.setText(text)
106 |
107 | def DictionaryKeys(self):
108 | return self._dict_key_value.keys()
109 |
110 | def DictionaryValues(self):
111 | return self._dict_key_value.values()
112 |
113 | def cellText(self,row, column):
114 | current_item = self.table_widget.item(row, column)
115 | current_item_text = current_item.text()
116 | if column == 1:
117 | key_item = self.table_widget.item(row, 0)
118 | key_text = str(row)
119 | if key_item is not None:
120 | key_text = key_item.text()
121 |
122 | if key_text in self._dict_key_value or str(row) in self._dict_key_value:
123 | self._dict_key_value[key_text] = current_item_text
124 | else:
125 | self._dict_key_value[str(row)] = current_item_text
126 | else:
127 | value_item = self.table_widget.item(row, 0)
128 | if value_item is not None:
129 | value_text = value_item.text()
130 | else:
131 | value_text = ''
132 | self._dict_key_value[current_item_text] = value_text
133 |
134 |
135 | def sizeHint(self):
136 | return QtCore.QSize(400,self._table_size)
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorTemplates/Common/SliderTemplate/SliderWidgetClass.py:
--------------------------------------------------------------------------------
1 | from PySide2 import QtWidgets, QtCore
2 | from PySideLayoutTool.UIEditorTemplates.Common.LineEditTemplate import LineEditWidgets
3 |
4 |
5 | class SliderWidget(QtWidgets.QWidget):
6 | def __init__(self):
7 | super(SliderWidget, self).__init__()
8 | self.setMaximumHeight(50)
9 | self.setMinimumHeight(50)
10 |
11 | self._layout = QtWidgets.QVBoxLayout()
12 | self._layout.setSpacing(0)
13 | self._layout.setContentsMargins(0, 0, 0, 0)
14 |
15 | self.slider = QtWidgets.QSlider()
16 | self.slider.setOrientation(QtCore.Qt.Horizontal)
17 | self._value = 0
18 |
19 | self._min = 0
20 | self._max = 1
21 |
22 | self._slider_block = True
23 | self._boxedit_block = True
24 |
25 | self._hor_layout = QtWidgets.QHBoxLayout()
26 | self._hor_layout.setContentsMargins(0, 0, 0, 0)
27 | self._hor_layout.setAlignment(QtCore.Qt.AlignLeft)
28 |
29 | self._hor_layout.addSpacing(5)
30 | self._hor_layout.addWidget(self.slider)
31 |
32 | self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
33 |
34 | self._layout.addLayout(self._hor_layout)
35 | self.setLayout(self._layout)
36 |
37 | def setRange(self,minValue,maxValue):
38 | self._min = minValue
39 | self._max = maxValue
40 | self.slider.setRange(minValue, maxValue)
41 |
42 | def clamp(self, num, min_value, max_value):
43 | return max(min(num,max_value),min_value)
44 |
45 | def value(self):
46 | return self._value
47 |
48 |
49 | class FloatSliderWidget(SliderWidget):
50 |
51 | def __init__(self):
52 | super(FloatSliderWidget, self).__init__()
53 | self.boxEdit = LineEditWidgets.LineEditFloatWidgetClass(parent=self, steps=0.1)
54 | self.boxEdit.setMinimumWidth(35)
55 | self.boxEdit.setMaximumWidth(35)
56 |
57 | self._hor_layout.insertWidget(0,self.boxEdit)
58 |
59 | self.slider.valueChanged.connect(self._set_slider_value)
60 | self.boxEdit._digital_widget.editingFinished.connect(self._set_box_value)
61 | self.boxEdit._digital_widget.valueChanged.connect(self._wheel_set_box_value)
62 |
63 |
64 | def set_slider_value(self, value):
65 | self.slider.setValue(int(1000000.0 * value))
66 |
67 | def setValue(self, value):
68 | self.boxEdit.setValue(value)
69 | self.slider.setValue(int(value * self._max))
70 |
71 |
72 | def _set_slider_value(self, value, override=False):
73 | if self._slider_block:
74 | if self._value != value:
75 | self._boxedit_block = False
76 | self._value = float(self.clamp(value, int(self._min * 1000000.0), int(self._max * 1000000.0)) / 1000000.0)
77 | self.boxEdit.setValue(round(self._value, 3))
78 | self._boxedit_block = True
79 |
80 |
81 | def _set_box_value(self):
82 | if self._boxedit_block:
83 | self._slider_block = False
84 | self._value = self.boxEdit.value()
85 | self.slider.setValue(int(1000000.0 * self._value))
86 | self.setFocus()
87 | self._slider_block = True
88 |
89 |
90 | def _wheel_set_box_value(self):
91 | if self.boxEdit.wheelState():
92 | self._value = self.boxEdit.value()
93 | self.slider.setValue(int(1000000.0 * self._value))
94 |
95 |
96 |
97 |
98 |
99 | class IntSliderWidget(SliderWidget):
100 | def __init__(self):
101 | super(IntSliderWidget, self).__init__()
102 | self.boxEdit = LineEditWidgets.LineEditIntWidgetClass(parent=self)
103 | self.boxEdit.setMaximumWidth(60)
104 |
105 | self._hor_layout.insertWidget(0, self.boxEdit)
106 |
107 | self.slider.valueChanged.connect(self._set_slider_value)
108 | self.boxEdit._digital_widget.editingFinished.connect(self._set_box_value)
109 | self.boxEdit._digital_widget.valueChanged.connect(self._wheel_set_box_value)
110 |
111 | def set_slider_value(self, value):
112 | self.slider.setValue(value)
113 |
114 | def setValue(self, value):
115 | self.boxEdit.setValue(value)
116 | self.slider.setValue(int(value))
117 |
118 |
119 | def _set_slider_value(self, value, override=False):
120 | if self._slider_block:
121 | if self._value != value:
122 | self._boxedit_block = False
123 | self._value = value
124 | self.boxEdit.setValue(value)
125 | self._boxedit_block = True
126 |
127 | def _set_box_value(self):
128 | if self._boxedit_block:
129 | self._slider_block = False
130 | self._value = self.boxEdit.value()
131 | self.slider.setValue(self._value)
132 | self.setFocus()
133 | self._slider_block = True
134 |
135 | def _wheel_set_box_value(self):
136 | if self.boxEdit.wheelState():
137 | self._value = self.boxEdit.value()
138 | self.slider.setValue(self._value)
139 | # if self.boxEdit.wheelState():
140 | # self._slider_block = False
141 | # self._boxedit_block = False
142 | # self._value = self._slider_widget.boxEdit.value()
143 | # self.slider.setValue(self._value)
144 | # self._slider_block = True
145 | # self._boxedit_block = True
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorLib/TreeItemInterface.py:
--------------------------------------------------------------------------------
1 | from PySide2 import QtCore, QtWidgets, QtGui
2 | from abc import abstractmethod
3 | from . import UIEditorMediators
4 |
5 | """
6 | (QtCore.Qt.ItemFlag)
7 | This enum describes the properties of an item:
8 |
9 | Constant Description
10 |
11 | Qt.NoItemFlags - It does not have any properties set.
12 | Qt.ItemIsSelectable - It can be selected.
13 | Qt.ItemIsEditable - It can be edited.
14 | Qt.ItemIsDragEnabled - It can be dragged.
15 | Qt.ItemIsDropEnabled - It can be used as a drop target.
16 | Qt.ItemIsUserCheckable - It can be checked or unchecked by the user.
17 | Qt.ItemIsEnabled - The user can interact with the item.
18 |
19 | Qt.ItemIsAutoTristate - The item’s state depends on the state of its children.
20 | This enables automatic management of the state of parent items
21 | in QTreeWidget (checked if all children are checked, unchecked
22 | if all children are unchecked, or partially checked if only some children are checked).
23 |
24 | Qt.ItemIsTristate - This enum value is deprecated. Use instead.
25 | Qt.ItemNeverHasChildren - The item never has child items. This is used for optimization purposes only.
26 | Qt.ItemIsUserTristate - The user can cycle through three separate states. This value was added in Qt 5.5.
27 |
28 | """
29 |
30 | class TreeItem(QtWidgets.QTreeWidgetItem, UIEditorMediators.BaseComponent):
31 | def __init__(self,parent):
32 | super(TreeItem, self).__init__(parent)
33 | self._itemIn = parent
34 | self._display_index = -1
35 | self.setText(0, 'None')
36 | self._item_name = ''
37 | self._item_label = ''
38 | self._type = None
39 |
40 |
41 | def itemParent(self):
42 | return self._itemIn
43 |
44 | def setItem(self, item_In):
45 | if item_In.bOnItem():
46 | self._itemIn = item_In
47 | else:
48 | self._itemIn = item_In.itemParent()
49 |
50 | # print('parent : ', self._itemIn)
51 |
52 | def updateItem(self):
53 | self.setText(0, f'{self._item_label}({self._item_name})')
54 |
55 | def name(self):
56 | return self._item_name
57 |
58 | def setName(self, name: str):
59 | self._item_name = name
60 | self.updateItem()
61 |
62 | def label(self):
63 | return self._item_label
64 |
65 | def setLabel(self, label_str: str):
66 | self._item_label = label_str
67 | self.updateItem()
68 | self.mediator.notify_display_label(label_str)
69 |
70 | @property
71 | def stackIndex(self) -> int:
72 | return self._display_index
73 |
74 | @stackIndex.setter
75 | def stackIndex(self, index: int):
76 | self._display_index = index
77 |
78 | @property
79 | def type_str(self) -> str:
80 | return self._type
81 |
82 | @type_str.setter
83 | def type_str(self, type: str):
84 | self._type = type
85 |
86 | @abstractmethod
87 | def bMoveable(self) -> bool:
88 | """ Allow item to be move around layout tree items."""
89 | return True
90 |
91 | @abstractmethod
92 | def bOnItem(self) -> bool:
93 | """ Allow item to have children items. """
94 | return True
95 |
96 | @abstractmethod
97 | def itemHandling(self,item_adding, position):
98 | """ Override this method to handle how item is going to
99 | be added and moved in the layout tree.
100 |
101 | :param item_adding: new item being added to a QTreeWidgetItem or self.
102 | :param position: the last position item was dropped on.
103 |
104 | """
105 |
106 |
107 |
108 | class RootItem(TreeItem):
109 | def __init__(self,parent):
110 | super(RootItem, self).__init__(parent)
111 | self.setText(0,'Root')
112 | self._font = QtGui.QFont()
113 | self._font.setBold(True)
114 | self.setFont(0, self._font)
115 | self.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDropEnabled)
116 |
117 | def setItem(self, item_In):
118 | pass
119 |
120 | def bMoveable(self) -> bool:
121 | return False
122 |
123 | def itemHandling(self,item_adding, position):
124 | if not isinstance(item_adding, QtWidgets.QTreeWidget):
125 | self.addChild(item_adding)
126 |
127 |
128 |
129 |
130 | class ParmItem(TreeItem):
131 | def __init__(self):
132 | super(ParmItem, self).__init__(None)
133 |
134 | def bOnItem(self) -> bool:
135 | return False
136 |
137 | def itemHandling(self, item_adding, position):
138 | index = self.itemParent().indexOfChild(self)
139 | if position == QtWidgets.QAbstractItemView.BelowItem:
140 | index += 1
141 |
142 | self.itemParent().insertChild(index, item_adding)
143 |
144 |
145 |
146 |
147 | class FolderItem(TreeItem):
148 | def __init__(self):
149 | super(FolderItem, self).__init__(None)
150 | self._font = QtGui.QFont()
151 | self._font.setItalic(True)
152 | self.setFont(0, self._font)
153 |
154 | def itemHandling(self, item_adding, position):
155 | if position == QtWidgets.QAbstractItemView.AboveItem:
156 | index = self.itemParent().indexOfChild(self)
157 | self.itemParent().insertChild(index, item_adding)
158 | return
159 |
160 | self.addChild(item_adding)
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorTemplates/Common/ButtonTemplate/ButtonClass.py:
--------------------------------------------------------------------------------
1 | from PySide2 import QtWidgets, QtCore
2 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty
3 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory
4 | from . import ButtonWidgetClass
5 |
6 | # TODO: Need to fix to work properly when buttons/button is set to join horizontal
7 |
8 | class SimpleButtonSetupClass(LayoutTemplate.ParmSetup):
9 |
10 | def __init__(self, parent):
11 | super(SimpleButtonSetupClass, self).__init__(parent)
12 | horizontal_Layout = QtWidgets.QHBoxLayout()
13 | horizontal_Layout.setSpacing(0)
14 | horizontal_Layout.setContentsMargins(0,2,0,2)
15 | horizontal_Layout.setAlignment(QtCore.Qt.AlignLeft)
16 |
17 | self._button_widget = ButtonWidgetClass.ButtonWidget()
18 |
19 | horizontal_Layout.addSpacing(55)
20 | horizontal_Layout.addWidget(self._button_widget)
21 |
22 | self._layout.addLayout(horizontal_Layout)
23 |
24 | self._button_widget.pressed.connect(self.button_action)
25 |
26 |
27 | def bLabel(self):
28 | return False
29 |
30 | def button_action(self):
31 | self.notify_expressions()
32 |
33 | def PostUpdate(self):
34 | super(SimpleButtonSetupClass, self).PostUpdate()
35 | self._button_widget.changeText(self.label())
36 |
37 | def eval(self):
38 | return None
39 |
40 |
41 |
42 |
43 | class ButtonStripSetupClass(LayoutTemplate.ParmSetup):
44 |
45 | def __init__(self,parent):
46 | super(ButtonStripSetupClass, self).__init__(parent)
47 | self._button_widget = ButtonWidgetClass.ButtonStripWidget()
48 | self._bLabel = True
49 |
50 | self._layout.addWidget(self._button_widget)
51 |
52 | @UIProperty(metaWidget='ComboProperty',label='Button Type',category='Combo/Menu Items',
53 | defaults=['Normal (Menu Only, Single Selection)','Normal Mini (Mini Menu Only, Single Selection)' ,'Toggle (Field + Multiple Selection)'])
54 | def button_type(self):
55 | pass
56 |
57 | @UIProperty(metaWidget='DictionaryProperty',label='Items',category='Combo/Menu Items')
58 | def dict_keyValue(self):
59 | pass
60 |
61 | def bLabel(self):
62 | return self._bLabel
63 |
64 | def PreUpdate(self):
65 | if self.button_type().currentItem_index == 1:
66 | self._bLabel = False
67 |
68 | self._button_widget.typeStrip(self.button_type().currentItem_index)
69 |
70 | def PostUpdate(self):
71 | super(ButtonStripSetupClass, self).PostUpdate()
72 | if self._button_widget.layout().itemAt(0).count() > 0:
73 | for i in range(0,self._button_widget.layout().itemAt(0).count()):
74 | item_layout = self._button_widget.layout().itemAt(0).itemAt(i)
75 | widget = item_layout.widget()
76 | widget.deleteLater()
77 |
78 | self._button_widget.clearButtons()
79 |
80 | if self.button_type().currentItem_index != 1 and self.dict_keyValue().keys:
81 | if len(self.dict_keyValue().keys) > 0:
82 | self._button_widget.addButtons(self.dict_keyValue().keys)
83 |
84 | def eval(self):
85 | if self.button_type().currentItem_index == 2:
86 | return self._button_widget.checked_buttons()
87 | else:
88 | return self._button_widget.lastSelected()
89 |
90 |
91 | class RGBAButtonWidgetSetup(LayoutTemplate.ParmSetup):
92 |
93 | def __init__(self, parent):
94 | super(RGBAButtonWidgetSetup, self).__init__(parent)
95 | self._button_widget = ButtonWidgetClass.RGBAButtonWidget()
96 | self._layout.addWidget(self._button_widget)
97 |
98 | def eval(self):
99 | return self._button_widget.rgb_button_state(), self._button_widget.red_button_state(), self._button_widget.green_button_state(), self._button_widget.blue_button_state(), self._button_widget.alpha_button_state()
100 |
101 | def PostUpdate(self):
102 | self._button_widget._rgb_button_widget.setToolTip('Toggle RGB')
103 | self._button_widget._rgb_button_widget.setStyleSheet("QToolTip { color: #ffffff; background-color: #484848; border: 0px;}")
104 |
105 | self._button_widget._r_button_widget.setToolTip('Red')
106 | self._button_widget._r_button_widget.setStyleSheet("QToolTip { color: #ffffff; background-color: #484848; border: 0px;}")
107 |
108 | self._button_widget._g_button_widget.setToolTip('Green')
109 | self._button_widget._g_button_widget.setStyleSheet("QToolTip { color: #ffffff; background-color: #484848; border: 0px;}")
110 |
111 | self._button_widget._b_button_widget.setToolTip('Blue')
112 | self._button_widget._b_button_widget.setStyleSheet("QToolTip { color: #ffffff; background-color: #484848; border: 0px;}")
113 |
114 | self._button_widget._a_button_widget.setToolTip('Alpha')
115 | self._button_widget._a_button_widget.setStyleSheet("QToolTip { color: #ffffff; background-color: #484848; border: 0px;}")
116 |
117 | def set_value(self, value, override=False):
118 | pass
119 |
120 |
121 |
122 |
123 | class SimpleButtonBuildClass(TemplateBuildClass.ParameterBuild):
124 |
125 | def widgetClass(self):
126 | return SimpleButtonSetupClass
127 |
128 |
129 | class ButtonStripBuildClass(TemplateBuildClass.ParameterBuild):
130 |
131 | def widgetClass(self):
132 | return ButtonStripSetupClass
133 |
134 |
135 | class ButtonRGBABuildClass(TemplateBuildClass.ParameterBuild):
136 |
137 | def widgetClass(self):
138 | return RGBAButtonWidgetSetup
139 |
140 |
141 | def register():
142 | UIEditorFactory.WidgetFactory.register('Button', SimpleButtonBuildClass)
143 | UIEditorFactory.WidgetFactory.register('Button Strip', ButtonStripBuildClass)
144 | UIEditorFactory.WidgetFactory.register('RGBA Mask', ButtonRGBABuildClass)
145 |
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorTemplates/Common/ButtonTemplate/ButtonWidgetClass.py:
--------------------------------------------------------------------------------
1 | from PySide2 import QtWidgets, QtCore, QtGui
2 |
3 |
4 | class ButtonWidget(QtWidgets.QPushButton):
5 |
6 | def __init__(self, bState = False):
7 | super(ButtonWidget, self).__init__()
8 | self.setSizePolicy(QtWidgets.QSizePolicy.Preferred,QtWidgets.QSizePolicy.Fixed)
9 | self.setFlat(bState)
10 | self.setCheckable(bState)
11 |
12 | def changeText(self, text: str):
13 | self.setText(text)
14 | font = QtGui.QFont(text)
15 | font_metrics = QtGui.QFontMetrics(font)
16 | val = font_metrics.width(text)/4
17 | self.setMinimumWidth((24 - int(val)) + font_metrics.width(text))
18 | self.setMaximumWidth((24 - int(val)) + font_metrics.width(text))
19 |
20 |
21 |
22 |
23 | class ButtonStripWidget(QtWidgets.QWidget):
24 |
25 | def __init__(self):
26 | super(ButtonStripWidget, self).__init__()
27 | self._layout = QtWidgets.QVBoxLayout()
28 | self._layout.setSpacing(0)
29 | self._layout.setContentsMargins(0,2,0,2)
30 |
31 | self._hor_layout = QtWidgets.QHBoxLayout()
32 | self._hor_layout.setSpacing(1)
33 | self._hor_layout.setContentsMargins(0,0,0,0)
34 | self._hor_layout.setAlignment(QtCore.Qt.AlignLeft)
35 |
36 | self._button_list = []
37 | self._last_selected = None
38 | self._last_button = None
39 | self._type = 0
40 |
41 | self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
42 |
43 | self._layout.addLayout(self._hor_layout)
44 | self.setLayout(self._layout)
45 |
46 | def addButton(self, text):
47 | button = ButtonWidget(True)
48 | button.changeText(text)
49 | self._hor_layout.addWidget(button)
50 | self._button_list.append(button)
51 |
52 | button.pressed.connect(lambda pass_obj=button: self.updateSelected(pass_obj))
53 |
54 | return button
55 |
56 |
57 | def addButtons(self,texts: list):
58 | count = len(texts)
59 | for i in enumerate(texts):
60 | new_button = self.addButton(i[1])
61 | if i[0] == 0:
62 | new_button.setProperty('class','first_button')
63 | elif i[0] == count-1:
64 | new_button.setProperty('class','last_button')
65 |
66 |
67 | def updateSelected(self, button_pressed):
68 | for i in enumerate(self._button_list):
69 | if i[1] == button_pressed:
70 | self._last_selected = i[0]
71 | self._last_button = i[1]
72 | break
73 |
74 | if self._type != 2:
75 | for i in enumerate(self._button_list):
76 | if i[0] != self._last_selected:
77 | i[1].setChecked(False)
78 |
79 | def typeStrip(self, index: int):
80 | self._type = index
81 |
82 | def clearButtons(self):
83 | self._button_list.clear()
84 | self._last_button = None
85 |
86 | def lastSelected(self):
87 | return self._last_selected, self._last_button
88 |
89 | def checked_buttons(self):
90 | buttons_checked = []
91 | for i in enumerate(self._button_list):
92 | if i[1].isChecked():
93 | buttons_checked.append(i)
94 |
95 | return buttons_checked
96 |
97 |
98 | class RGBAButtonWidget(QtWidgets.QWidget):
99 |
100 | def __init__(self):
101 | super(RGBAButtonWidget, self).__init__()
102 | self._hor_layout = QtWidgets.QHBoxLayout()
103 | self._hor_layout.setSpacing(1)
104 | self._hor_layout.setContentsMargins(0, 0, 0, 0)
105 | self._hor_layout.setAlignment(QtCore.Qt.AlignLeft)
106 |
107 | self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
108 |
109 | self._rgb_button_widget = QtWidgets.QPushButton('RGB')
110 | self._flip_flop = True
111 |
112 | self._r_button_widget = QtWidgets.QPushButton('R')
113 | self._r_button_widget.setFlat(True)
114 | self._r_button_widget.setCheckable(True)
115 |
116 | self._g_button_widget = QtWidgets.QPushButton('G')
117 | self._g_button_widget.setFlat(True)
118 | self._g_button_widget.setCheckable(True)
119 |
120 | self._b_button_widget = QtWidgets.QPushButton('B')
121 | self._b_button_widget.setFlat(True)
122 | self._b_button_widget.setCheckable(True)
123 |
124 | self._a_button_widget = QtWidgets.QPushButton('A')
125 | self._a_button_widget.setFlat(True)
126 | self._a_button_widget.setCheckable(True)
127 |
128 | self._hor_layout.addWidget(self._rgb_button_widget)
129 | self._hor_layout.addWidget(self._r_button_widget)
130 | self._hor_layout.addWidget(self._g_button_widget)
131 | self._hor_layout.addWidget(self._b_button_widget)
132 | self._hor_layout.addWidget(self._a_button_widget)
133 |
134 | self.setLayout(self._hor_layout)
135 |
136 | self._rgb_button_widget.clicked.connect(self._rgb_pressed)
137 |
138 | def _rgb_pressed(self):
139 | self._r_button_widget.setChecked(self._flip_flop)
140 | self._g_button_widget.setChecked(self._flip_flop)
141 | self._b_button_widget.setChecked(self._flip_flop)
142 |
143 | if self._flip_flop:
144 | self._flip_flop = False
145 | else:
146 | self._flip_flop = True
147 |
148 |
149 | def rgb_button_state(self):
150 | return self._rgb_button_widget.isChecked()
151 |
152 | def red_button_state(self):
153 | return self._r_button_widget.isChecked()
154 |
155 | def green_button_state(self):
156 | return self._g_button_widget.isChecked()
157 |
158 | def blue_button_state(self):
159 | return self._b_button_widget.isChecked()
160 |
161 | def alpha_button_state(self):
162 | return self._a_button_widget.isChecked()
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorWindows/TabScript.py:
--------------------------------------------------------------------------------
1 | from PySide2 import QtWidgets, QtCore
2 |
3 | from PySideLayoutTool.UIEditorLib import UIEditorIconFactory, UIEditorScript
4 |
5 |
6 | class ScriptTab(QtWidgets.QMainWindow):
7 |
8 | def __init__(self, parent):
9 | super(ScriptTab, self).__init__()
10 | self._parent = parent
11 | self._editor_dock = QtWidgets.QDockWidget(self)
12 | self._editor_dock.setWindowTitle('Python Editor')
13 | self._editor_dock.setAllowedAreas(QtCore.Qt.TopDockWidgetArea)
14 |
15 | self._editor_layout = EditorLayout()
16 | self._editor_dock.setWidget(self._editor_layout)
17 | self._editor_dock.setFeatures(QtWidgets.QDockWidget.DockWidgetFloatable | QtWidgets.QDockWidget.DockWidgetMovable)
18 | self.addDockWidget(QtCore.Qt.BottomDockWidgetArea,self._editor_dock)
19 |
20 | def getPyModules(self):
21 | return self._editor_layout
22 |
23 | def pyModules_count(self):
24 | return self._editor_layout.module_count()
25 |
26 | def pyModule_editor(self):
27 | return self._editor_layout
28 |
29 |
30 | class EditorLayout(QtWidgets.QWidget):
31 |
32 | def __init__(self):
33 | super(EditorLayout, self).__init__()
34 | self._layout = QtWidgets.QVBoxLayout()
35 | self._layout.setSpacing(0)
36 | self._layout.setContentsMargins(0,0,0,0)
37 |
38 | self._top_toolbar = QtWidgets.QToolBar()
39 | self._bottom_toolbar = QtWidgets.QToolBar()
40 | self._pyModules = {}
41 |
42 | self._left_move_action = self._top_toolbar.addAction(UIEditorIconFactory.IconEditorFactory.create('move_left'), 'Line Left Move')
43 | self._right_move_action = self._top_toolbar.addAction(
44 | UIEditorIconFactory.IconEditorFactory.create('move_right'), 'Line Right Move')
45 |
46 | self._top_toolbar.addSeparator()
47 |
48 | self._comment_action = self._top_toolbar.addAction(UIEditorIconFactory.IconEditorFactory.create('comment'), 'Comment In/Out')
49 | self._top_toolbar.addSeparator()
50 |
51 | spacing = QtWidgets.QWidget()
52 | spacing.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
53 | spacing.setStyleSheet('background-color: #0e0e0e;')
54 |
55 | self._bottom_toolbar.addWidget(spacing)
56 | self._bottom_toolbar.addSeparator()
57 | self._zoom_in_action = self._bottom_toolbar.addAction(UIEditorIconFactory.IconEditorFactory.create('zoom_In'), 'Increase Text Size')
58 | self._zoom_out_action = self._bottom_toolbar.addAction(UIEditorIconFactory.IconEditorFactory.create('zoom_Out'), 'Decrease Text Size')
59 |
60 | self._tab_widget = QtWidgets.QTabWidget(self)
61 | self._tab_widget.setProperty('class','editor_pane')
62 | self._tab_widget.setTabsClosable(True)
63 |
64 | self._base_pyModule = UIEditorScript.ScriptEditor()
65 | self._tab_widget.addTab(self._base_pyModule,'PyModule_1')
66 | self._tab_widget.tabBar().tabButton(0,QtWidgets.QTabBar.RightSide).resize(0, 0)
67 | self._pyModules['PyModule_1'] = self._base_pyModule
68 |
69 | self._tab_widget.addTab(QtWidgets.QWidget(), '+' )
70 | self._tab_widget.tabBar().tabButton(1, QtWidgets.QTabBar.RightSide).resize(0, 0)
71 |
72 | self._tab_widget.tabBar().setSelectionBehaviorOnRemove(QtWidgets.QTabBar.SelectLeftTab)
73 |
74 | self._layout.addWidget(self._top_toolbar)
75 | self._layout.addWidget(self._tab_widget)
76 | self._layout.addWidget(self._bottom_toolbar)
77 |
78 | self._left_move_action.triggered.connect(self.move_line_back)
79 | self._right_move_action.triggered.connect(self.move_line_forward)
80 | self._comment_action.triggered.connect(self.comment_action)
81 |
82 | self._zoom_in_action.triggered.connect(self.zoom_in_call)
83 | self._zoom_out_action.triggered.connect(self.zoom_out_call)
84 |
85 | self._tab_widget.tabBarClicked.connect(self.newTab)
86 | self._tab_widget.tabBar().tabCloseRequested.connect(self.closeTab)
87 |
88 | self.setLayout(self._layout)
89 |
90 | def scriptModule(self, name):
91 | if name in self._pyModules:
92 | return self._pyModules[name]
93 |
94 | def module_count(self) -> int:
95 | return len(self._pyModules)
96 |
97 | def modules(self):
98 | return self._pyModules
99 |
100 | def newTab(self, index):
101 | if self._tab_widget.tabText(index) == "+":
102 | new_pyModule = UIEditorScript.ScriptEditor()
103 | self._tab_widget.insertTab(index, new_pyModule, f'PyModule_{index+1}')
104 | self._pyModules[f'PyModule_{index+1}'] = new_pyModule
105 |
106 | def newTabCode(self,index, name, code):
107 | if name not in self._pyModules:
108 | new_pyModule = UIEditorScript.ScriptEditor()
109 | new_pyModule.appendPlainText(code)
110 | self._tab_widget.insertTab(index, new_pyModule, name)
111 | self._pyModules[name] = new_pyModule
112 |
113 | else:
114 | self._pyModules[name].appendPlainText(code)
115 |
116 | def closeTab(self, index):
117 | widget = self._tab_widget.widget(index)
118 | text = self._tab_widget.tabText(index)
119 | self._tab_widget.removeTab(index)
120 | editor_class = self._pyModules.pop(text)
121 | del widget, editor_class
122 |
123 | def move_line_back(self, state):
124 | widget = self._tab_widget.widget(self._tab_widget.currentIndex())
125 | widget.reverse_TabHandling()
126 |
127 | def move_line_forward(self, state):
128 | widget = self._tab_widget.widget(self._tab_widget.currentIndex())
129 | widget.tab_effect()
130 |
131 | def comment_action(self, state):
132 | widget = self._tab_widget.widget(self._tab_widget.currentIndex())
133 | widget.commentHandling()
134 |
135 | def zoom_in_call(self, state):
136 | widget = self._tab_widget.widget(self._tab_widget.currentIndex())
137 | widget.zoom_in()
138 |
139 | def zoom_out_call(self, state):
140 | widget = self._tab_widget.widget(self._tab_widget.currentIndex())
141 | widget.zoom_out()
142 |
143 |
144 |
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorLib/LayoutConstructorClass.py:
--------------------------------------------------------------------------------
1 | import ast
2 | import json
3 | from PySide2 import QtWidgets
4 |
5 | class JsonConstructor:
6 |
7 | _folder_types = ['Simple','Collapisble']
8 | _folderlist_types = ['Tabs','Radio']
9 |
10 | @classmethod
11 | def construct(cls, file, editor_win):
12 | editor_tree = editor_win.parameter_Tab().layout_tree()
13 | data = json.load(file)
14 |
15 | for item in data['Root']:
16 | if item['Type'] in cls._folderlist_types:
17 | for folder in item['Folders']:
18 | folder_build = editor_tree.add_new_obj(folder['Type'], editor_tree.root_item(),QtWidgets.QAbstractItemView.OnItem)
19 | folder_display_widget = folder_build.newDisplay()
20 | folder_item = folder_build.newItem()
21 | editor_tree.setExpanded(editor_tree.indexFromItem(folder_item), True)
22 |
23 | for property_name in folder_display_widget.Properties():
24 | if property_name in folder:
25 | if property_name != 'Type':
26 | folder_display_widget.Properties()[property_name].setValue(folder[property_name])
27 | if property_name == 'Name':
28 | folder_display_widget.mediatorNameCheck()
29 | elif property_name == 'Label':
30 | folder_display_widget.mediatorLabel()
31 |
32 | for parameter in folder['FolderParameters']:
33 | parm_build = editor_tree.add_new_obj(parameter['Type'], folder_item ,QtWidgets.QAbstractItemView.OnItem)
34 | parm_display_widget = parm_build.newDisplay()
35 |
36 | for property_name in parm_display_widget.Properties():
37 | if property_name in parameter:
38 | if property_name != 'Type':
39 | current_value = ''
40 | if property_name == 'Values':
41 | if parameter['Type'] != 'Ramp':
42 | current_value = ast.literal_eval(parameter['Settings']['Values'])
43 | else:
44 | current_value = parameter[property_name]
45 | parm_display_widget.Properties()[property_name].setValue(current_value)
46 | if property_name == 'Name':
47 | parm_display_widget.mediatorNameCheck()
48 | elif property_name == 'Label':
49 | parm_display_widget.mediatorLabel()
50 |
51 | if parameter['Type'] == 'Ramp':
52 | parm_build.newWidget().set_value(parameter['Settings']['Values'])
53 |
54 |
55 | elif item['Type'] in cls._folder_types:
56 | folder_build = editor_tree.add_new_obj(item['Type'], editor_tree.root_item(),QtWidgets.QAbstractItemView.OnItem)
57 | folder_display_widget = folder_build.newDisplay()
58 | folder_item = folder_build.newItem()
59 | editor_tree.setExpanded(editor_tree.indexFromItem(folder_item), True)
60 |
61 |
62 | for property_name in folder_display_widget.Properties():
63 | if property_name in item:
64 | if property_name != 'Type':
65 | folder_display_widget.Properties()[property_name].setValue(item[property_name])
66 | if property_name == 'Name':
67 | folder_display_widget.mediatorNameCheck()
68 | elif property_name == 'Label':
69 | folder_display_widget.mediatorLabel()
70 |
71 |
72 | for parameter in item['FolderParameters']:
73 | parm_build = editor_tree.add_new_obj(parameter['Type'], folder_item,QtWidgets.QAbstractItemView.OnItem)
74 | parm_display_widget = parm_build.newDisplay()
75 |
76 | for property_name in parm_display_widget.Properties():
77 | if property_name in parameter:
78 | if property_name != 'Type':
79 | current_value = ''
80 | if property_name == 'Values':
81 | if parameter['Type'] != 'Ramp':
82 | current_value = ast.literal_eval(parameter['Settings']['Values'])
83 | else:
84 | current_value = parameter[property_name]
85 | parm_display_widget.Properties()[property_name].setValue(current_value)
86 | if property_name == 'Name':
87 | parm_display_widget.mediatorNameCheck()
88 | elif property_name == 'Label':
89 | parm_display_widget.mediatorLabel()
90 |
91 | if parameter['Type'] == 'Ramp':
92 | parm_build.newWidget().set_value(parameter['Settings']['Values'])
93 |
94 | else:
95 | parm_build = editor_tree.add_new_obj(item['Type'], editor_tree.root_item(),QtWidgets.QAbstractItemView.OnItem)
96 | parm_display_widget = parm_build.newDisplay()
97 |
98 | for property_name in parm_display_widget.Properties():
99 | if property_name in item or property_name == 'Values':
100 | if property_name != 'Type':
101 | current_value = ''
102 | if property_name == 'Values':
103 | if item['Type'] != 'Ramp':
104 | current_value = ast.literal_eval(item['Settings']['Values'])
105 | else:
106 | current_value = item[property_name]
107 | parm_display_widget.Properties()[property_name].setValue(current_value)
108 | if property_name == 'Name':
109 | parm_display_widget.mediatorNameCheck()
110 | elif property_name == 'Label':
111 | parm_display_widget.mediatorLabel()
112 |
113 | if item['Type'] == 'Ramp':
114 | parm_build.newWidget().set_value(item['Settings']['Values'])
115 |
116 | editor_tree.setExpanded(editor_tree.indexFromItem(editor_tree.root_item()), True)
117 |
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorLib/UIEditorProperty.py:
--------------------------------------------------------------------------------
1 | import inspect
2 | from abc import abstractmethod
3 | from functools import wraps
4 | from collections import namedtuple
5 | from typing import Callable, Any, Dict
6 | from PySide2 import QtWidgets
7 |
8 |
9 | class IWidgetProperties(QtWidgets.QWidget):
10 |
11 | def __init__(self):
12 | super(IWidgetProperties, self).__init__()
13 | self.setContentsMargins(0,0,0,0)
14 | self._layout = QtWidgets.QVBoxLayout()
15 | self._layout.setSpacing(0)
16 | self._layout.setContentsMargins(0, 0, 0, 0)
17 | self.setLayout(self._layout)
18 |
19 | self._parent = None
20 |
21 |
22 | def addParent(self, parent):
23 | self._parent = parent
24 |
25 | @abstractmethod
26 | def override_default(self, defaults: tuple):
27 | pass
28 |
29 | @abstractmethod
30 | def setValue(self, value):
31 | pass
32 |
33 | @abstractmethod
34 | def value(self):
35 | pass
36 |
37 |
38 | class PropertyFactory:
39 |
40 | registeredUI: Dict[str, Callable[..., Any]] = {}
41 |
42 | @classmethod
43 | def register(cls, name: str) -> Callable:
44 |
45 | def inner_wrapper(wrapped_class):
46 | if not hasattr(wrapped_class, '__UICProperties__'):
47 | TypeError('UIClass must have minimum 1 UICProperty func')
48 |
49 | if name in cls.registeredUI:
50 | TypeError('UIClass with %s already exist. Will replace it', name)
51 | cls.registeredUI[name] = wrapped_class
52 | return wrapped_class
53 |
54 | return inner_wrapper
55 |
56 | @classmethod
57 | def create_property(cls, name: str) -> Any or None:
58 |
59 | if name not in cls.registeredUI:
60 | TypeError ('UIClass %s does not exist in the registry', name)
61 | return None
62 |
63 | exec_class = cls.registeredUI[name]
64 | return exec_class
65 |
66 |
67 | class UICProperty:
68 | def __init__(self, func):
69 | self._cls = None
70 | self._fget = func
71 |
72 | def __get__(self, obj, cls):
73 | if cls is None:
74 | cls = type(obj)
75 | return self._fget.__get__(obj, cls)()
76 |
77 | # def __set__(self, obj, value):
78 | # if not self._fset:
79 | # raise AttributeError("can't set attribute")
80 | # type_ = type(obj)
81 | # return self._fset.__get__(obj, type_)(value)
82 |
83 | def __set_name__(self, owner, name):
84 | self._cls = owner
85 | if hasattr(owner,'__UICProperties__'):
86 | getattr(owner,'__UICProperties__').append(self._fget.__name__)
87 | else:
88 | setattr(owner, '__UICProperties__', [self._fget.__name__])
89 |
90 |
91 |
92 | def UIProperty(metaWidget: str, label:str = None, category:str = None, category_args=(False,300), defaults=None, use_separator:bool=False, neighbor=False):
93 | class PrepareCls:
94 | def __init__(self, func):
95 | self._metaWidget = PropertyFactory.create_property(metaWidget)
96 | self._func = func
97 | self._cls = None
98 | self._value = None
99 | self._names = None
100 | self._new_instanceWidget = None
101 | setattr(self, '__UIProperty__', True)
102 |
103 |
104 | def convert(self, dictionary):
105 | return namedtuple('PropertyValues', dictionary.keys())(**dictionary)
106 |
107 | def _process_instance(self):
108 | self._new_instanceWidget = self._metaWidget()
109 |
110 | if defaults:
111 | self._new_instanceWidget.override_default(defaults)
112 |
113 | self._names = getattr(self._new_instanceWidget, '__UICProperties__')
114 | valueDict = {}
115 | for attribute in dir(self._new_instanceWidget):
116 | # Check that it is callable
117 | if attribute in self._names:
118 | attribute_value = getattr(self._new_instanceWidget, attribute)
119 | valueDict[attribute] = attribute_value
120 |
121 | if len(valueDict) > 1:
122 | self._value = self.convert(valueDict)
123 | else:
124 | self._value = list(valueDict.values())[0]
125 |
126 | self._label = label
127 | if self._label is None:
128 | self._label = self._func.__name__
129 |
130 | return self._new_instanceWidget, self._func.__name__, self._label, category, category_args, use_separator
131 |
132 | def _init_update(self, cls_instance):
133 | new_value_dict = {}
134 | property_instance = cls_instance.__property_instances__[self._func.__name__]
135 | for attribute in property_instance.__class__.__UICProperties__:
136 | if attribute in self._names:
137 | attribute_value = getattr(property_instance, attribute)
138 | new_value_dict[attribute] = attribute_value
139 |
140 | if type(self._value).__name__ == 'PropertyValues':
141 | self._value = self.convert(new_value_dict)
142 | else:
143 | self._value = list(new_value_dict.values())[0]
144 |
145 | if not hasattr(cls_instance, '__property_values__'):
146 | new_dict = {self._func.__name__: self._value}
147 | setattr(cls_instance, '__property_values__', new_dict)
148 | else:
149 | getattr(cls_instance, '__property_values__')[self._func.__name__] = self._value
150 |
151 | # self._func(cls_instance)
152 |
153 |
154 | def __get__(self, instance, owner):
155 | if instance is not None:
156 | if hasattr(instance, '__property_values__'):
157 | self._value = instance.__property_values__[self._func.__name__]
158 |
159 | return self
160 |
161 |
162 | def __set_name__(self, owner, name):
163 | self._cls = owner
164 | if hasattr(owner, '__UIProperties__'):
165 | getattr(owner, '__UIProperties__').append(self._func.__name__)
166 | else:
167 | setattr(owner, '__UIProperties__', [self._func.__name__])
168 |
169 |
170 | def __call__(self):
171 | return self._value
172 |
173 | return PrepareCls
174 |
175 |
176 |
177 | def ProcessUIProperties(func):
178 | @wraps(func)
179 | def wrapper(*args, **kwargs):
180 | cls_mro = []
181 | for i in inspect.getmro(args[0]):
182 | if i.__name__ == 'mainWidget':
183 | cls_mro.append(i)
184 | break
185 | else:
186 | cls_mro.append(i)
187 |
188 | widget_instances = []
189 | cls_mro.reverse()
190 | for cls in cls_mro:
191 | for item in cls.__dict__.values():
192 | if hasattr(item,'__UIProperty__'):
193 | Property_instance = namedtuple('Property_Instance', ['property_widget','func_owner','label','category','category_args','separator'])
194 | widget_instance,func_owner, label_str, category_str,cat_args, bSep = item._process_instance()
195 | new_property = Property_instance(widget_instance, func_owner, label_str, category_str,cat_args, bSep)
196 | widget_instances.append(new_property)
197 |
198 | return widget_instances
199 |
200 | return wrapper
201 |
202 |
203 |
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorLib/TemplateDisplayUI.py:
--------------------------------------------------------------------------------
1 | from PySide2 import QtCore, QtWidgets
2 |
3 | from . import StringValidatorClass as Validator, UIEditorMediators
4 | from ..UIEditorTemplates.Common.SeparatorTemplate import SeparatorWidgetClass
5 | from PySideLayoutTool.UIEditorTemplates.Folder.CollapisbleFolderTemplate import CollapisbleFolderWidgetClass
6 | from ..UIEditorTemplates.Layout import CustomFormLayout
7 | from typing import Dict, Any, List
8 |
9 |
10 | class RootUISetup(QtWidgets.QWidget):
11 | """ This class is parent to all other item in the tree for Parameter layout """
12 | def __init__(self, parent):
13 | super(RootUISetup, self).__init__()
14 | self._parent = parent
15 |
16 | layout = QtWidgets.QFormLayout()
17 | # layout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow)
18 | layout.setHorizontalSpacing(20)
19 |
20 | self._rest_button = QtWidgets.QPushButton('Rest')
21 | layout.addRow("Reset Layout:", self._rest_button)
22 |
23 | self.setLayout(layout)
24 |
25 | self._rest_button.pressed.connect(self._clear_tree)
26 |
27 | def nameState(self) -> bool:
28 | return True
29 |
30 | def _clear_tree(self):
31 | self._parent.clear_layout()
32 |
33 |
34 |
35 | class ItemDisplayUI(QtWidgets.QWidget, UIEditorMediators.BaseComponent):
36 |
37 | def __init__(self):
38 | super(ItemDisplayUI, self).__init__()
39 |
40 | self._category_widgets: Dict[str, QtWidgets.QWidget] = {}
41 | self._category_layout: Dict[str, QtWidgets.QLayout] = {}
42 | self._category_open: Dict[str, bool] = {}
43 |
44 | self._widget_data: Dict[str, QtWidgets.QWidget] = {}
45 | self._layout_list_widgets: Dict[Any,List[Any]] = {}
46 | self._widget_label_data: Dict[str, QtWidgets.QWidget] = {}
47 |
48 | self._name_checked: bool = True
49 | self._type = ''
50 |
51 | self._mainLayout = QtWidgets.QVBoxLayout()
52 | self._mainLayout.setAlignment(QtCore.Qt.AlignTop)
53 |
54 | self.setLayout(self._mainLayout)
55 |
56 |
57 | def construct_display(self, instances, *args):
58 | for i in instances:
59 | current_layout = None
60 | if i.category in self._category_layout:
61 | current_layout = self._category_layout[i.category]
62 | list_widget = self._layout_list_widgets.pop(current_layout)
63 | list_widget.append(i.property_widget)
64 | layout_item = current_layout.new_Row(i.label,None, i.property_widget)
65 | self._widget_label_data[i.label] = layout_item.itemAt(0).widget()
66 |
67 | # self._category_layout[i.category] = current_layout
68 | self._layout_list_widgets[current_layout] = list_widget
69 |
70 | else:
71 | # names = i.category.split('|') #TODO: Handle sub category
72 |
73 | # self._mainLayout.addWidget(current_catergory_folder)
74 | # self._mainLayout.addSpacing(5)
75 | #
76 | # self._category_widgets[i.category] = current_catergory_folder
77 | current_layout = CustomFormLayout.CustomForm()
78 | new_list = [i.property_widget]
79 | self._layout_list_widgets[current_layout] = new_list
80 | self._category_layout[i.category] = current_layout
81 | layout_item = current_layout.new_Row(i.label,'None', i.property_widget)
82 | self._widget_label_data[i.label] = layout_item.itemAt(0).widget()
83 |
84 | # i.property_widget.addParent(current_catergory_folder)
85 |
86 | # Separator handling layout
87 | if i.separator:
88 | sep_widget = SeparatorWidgetClass.SeparatorHWidget()
89 | current_layout.add_Custom(sep_widget)
90 |
91 | if i.category_args[0]:
92 | self._category_open[i.category] = i.category_args[0]
93 |
94 | if i.label in self._widget_data:
95 | new_label = Validator.check_names(i.label, self._widget_data)
96 | self._widget_data[new_label] = i.property_widget
97 | else:
98 | self._widget_data[i.label] = i.property_widget
99 |
100 | if i.label == 'Name':
101 | i.property_widget._textbox._str_widget.editingFinished.connect(self.mediatorName)
102 | i.property_widget._textbox._str_widget.returnPressed.connect(self.mediatorNameCheck)
103 |
104 | if i.label == 'Label':
105 | i.property_widget._textbox._str_widget.editingFinished.connect(self.mediatorLabel)
106 |
107 | if i.label == 'Type':
108 | i.property_widget.setItems(args[0])
109 | i.property_widget.setCurrentItem(args[1])
110 | i.property_widget.propertyWidget().activated.connect(self._changeType)
111 | self._type = args[1]
112 |
113 |
114 | for key in self._category_layout:
115 | widget_layout = self._category_layout[key]
116 | state = False
117 | if key in self._category_open:
118 | state = True
119 |
120 | current_catergory_folder = CollapisbleFolderWidgetClass.CollapsibleFolderWidget(widget_layout)
121 | current_catergory_folder.folder_title(key)
122 | current_catergory_folder.open_folder(state)
123 |
124 | self._mainLayout.addWidget(current_catergory_folder)
125 | self._mainLayout.addSpacing(5)
126 | self._category_widgets[key] = current_catergory_folder
127 |
128 | # for key in self._category_widgets:
129 | # widget_layout = self._category_layout[key]
130 | # state = False
131 | # if key in self._category_open:
132 | # state = True
133 | #
134 | # self._category_widgets[key].setContentLayout(widget_layout.layout(), state)
135 |
136 |
137 | def mediatorName(self):
138 | widget, label = self.findProperty('Name')
139 | self.mediator.update_item_name(widget.strText) #type: ignore
140 | self.setFocus()
141 | self._name_checked = False
142 |
143 | def mediatorNameCheck(self):
144 | widget, label = self.findProperty('Name')
145 | widget.setText(self.mediator.verifyName(widget.strText)) #type: ignore
146 | self.mediator.update_item_name(widget.strText) #type: ignore
147 | self._name_checked = True
148 |
149 |
150 | def mediatorLabel(self):
151 | widget, label = self.findProperty('Label')
152 | self.mediator.notify_item_label(widget.strText) #type: ignore
153 | self.setFocus()
154 |
155 | def nameState(self) -> bool:
156 | """ If name has been checked already """
157 | return self._name_checked
158 |
159 | def _changeType(self, arg__1):
160 | widget, label = self.findProperty('Type')
161 | text = widget.propertyWidget().itemText(arg__1)
162 | if text != self._type:
163 | self.mediator.updateChange(text) #type: ignore
164 |
165 |
166 | def findProperty(self, name: str):
167 | if name not in self._widget_data:
168 | AttributeError(f'{name} not in Display UI or has another name')
169 | else:
170 | return self._widget_data[name], self._widget_label_data[name]
171 |
172 | def type(self):
173 | return self._type
174 |
175 | def Properties(self):
176 | return self._widget_data
177 |
--------------------------------------------------------------------------------
/PySideLayoutTool/UIEditorTemplates/Common/SliderTemplate/SliderClass.py:
--------------------------------------------------------------------------------
1 | from abc import abstractmethod
2 | from typing import Any
3 |
4 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty
5 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory
6 | from PySide2 import QtWidgets
7 | from . import SliderWidgetClass
8 |
9 | class SliderTemplateClass(LayoutTemplate.ParmSetup):
10 |
11 | def __init__(self,parent,bFloat=True):
12 | super(SliderTemplateClass, self).__init__(parent)
13 | self._value = 0
14 | self._slider_widget = SliderWidgetClass.FloatSliderWidget() if bFloat else SliderWidgetClass.IntSliderWidget()
15 | self._layout.addWidget(self._slider_widget)
16 |
17 | self._slider_widget.slider.valueChanged.connect(self._set_slider_value)
18 | self._slider_widget.boxEdit._digital_widget.editingFinished.connect(self._set_box_value)
19 | self._slider_widget.boxEdit._digital_widget.valueChanged.connect(self._wheel_set_box_value)
20 |
21 | def clamp(self, num, min_value, max_value):
22 | return max(min(num,max_value),min_value)
23 |
24 | def eval(self):
25 | return self._value
26 |
27 | @abstractmethod
28 | def set_value(self, value, override=False):
29 | pass
30 |
31 | @abstractmethod
32 | def setting(self, settings: Any):
33 | """ Give parameter set of values. """
34 |
35 | @abstractmethod
36 | def _set_slider_value(self, value, override=False):
37 | """ Set Text to Slider value."""
38 | self.notify_expressions()
39 |
40 | @abstractmethod
41 | def _set_box_value(self):
42 | """ Set Slider value to Text. """
43 | self.notify_expressions()
44 |
45 | @abstractmethod
46 | def _wheel_set_box_value(self):
47 | self.notify_expressions()
48 |
49 |
50 | class IntegerSliderClass(SliderTemplateClass):
51 | def __init__(self,parent):
52 | super(IntegerSliderClass, self).__init__(parent,bFloat=False)
53 | pass
54 |
55 | @UIProperty(metaWidget='ClampProperty', label='Range', category='Setting')
56 | def clampRange(self):
57 | pass
58 |
59 | def set_value(self, value, override=False):
60 | self._value = int(value)
61 | self._set_slider_value(self._value)
62 |
63 | def PostUpdate(self):
64 | super(IntegerSliderClass, self).PostUpdate()
65 | self._value = int(self._value)
66 | self._slider_widget.slider.setRange(self.clampRange().min, self.clampRange().max)
67 | self._slider_widget.slider.setValue(self._value)
68 | self._slider_widget.slider.setTickPosition(QtWidgets.QSlider.TicksBelow)
69 | self._slider_widget.slider.setTickInterval(1)
70 | self._slider_widget.boxEdit.setRange(int(self.clampRange().min) if self.clampRange().minLock else -1000000, int(self.clampRange().max) if self.clampRange().maxLock else 1000000)
71 | self._slider_widget.boxEdit.setValue(self._value)
72 |
73 |
74 | def _set_slider_value(self, value, override=False):
75 | if self._slider_widget._slider_block:
76 | if self._value != value:
77 | self._slider_widget._boxedit_block = False
78 | self._value = self.clamp(value, int(self.clampRange().min * 1000000.0) if self.clampRange().minLock else -100000000, int(self.clampRange().max * 1000000.0) if self.clampRange().maxLock else 100000000)
79 | self._slider_widget.boxEdit.setValue(value)
80 | self._slider_widget._boxedit_block = True
81 | super()._set_slider_value(self._value)
82 |
83 |
84 |
85 | def _set_box_value(self):
86 | if self._slider_widget._boxedit_block:
87 | self._slider_widget._slider_block = False
88 | self._value = self.clamp(self._slider_widget.boxEdit.value(), int(self.clampRange().min * 1000000.0) if self.clampRange().minLock else -100000000,int(self.clampRange().max * 1000000.0) if self.clampRange().maxLock else 100000000)
89 | self._slider_widget.slider.setValue(self._value)
90 | self.setFocus()
91 | self._slider_widget._slider_block = True
92 | super()._set_box_value()
93 |
94 | def _wheel_set_box_value(self):
95 | if self._slider_widget.boxEdit.wheelState():
96 | self._slider_block = False
97 | self._boxedit_block = False
98 | self._value = self._slider_widget.boxEdit.value()
99 | self._slider_widget.slider.setValue(self._value)
100 | self._slider_block = True
101 | self._boxedit_block = True
102 | super()._set_box_value()
103 |
104 |
105 |
106 | class FloatSliderClass(SliderTemplateClass):
107 | def __init__(self,parent):
108 | super(FloatSliderClass, self).__init__(parent)
109 | pass
110 |
111 | @UIProperty(metaWidget='ClampProperty', label='Range', category='Setting', defaults=(0, 10, False, False, False))
112 | def clampRange(self):
113 | pass
114 |
115 | def set_value(self, value, override=False):
116 | self._value = float(value)
117 | self._set_slider_value(self._value)
118 |
119 | def PostUpdate(self):
120 | super(FloatSliderClass, self).PostUpdate()
121 | self._value = float(self._value)
122 | self._slider_widget.slider.setRange(int(self.clampRange().min * 1000000.0),int(self.clampRange().max * 1000000.0))
123 | self._slider_widget.slider.setValue(int(self._value * 1000000.0))
124 | self._slider_widget.boxEdit.setRange(float(self.clampRange().min) if self.clampRange().minLock else -1000000.0, float(self.clampRange().max) if self.clampRange().maxLock else 1000000.0)
125 | self._slider_widget.boxEdit.setValue(float(self._value))
126 |
127 |
128 | def _set_slider_value(self, value, override=False):
129 | if self._slider_widget._slider_block:
130 | if self._value != value:
131 | self._slider_widget._boxedit_block = False
132 | self._value = float(self.clamp(value, int(self.clampRange().min * 1000000.0) if self.clampRange().minLock else -100000000, int(self.clampRange().max * 1000000.0) if self.clampRange().maxLock else 100000000) / 1000000.0)
133 | self._slider_widget.boxEdit.setValue(round(self._value, 3))
134 | self._slider_widget._boxedit_block = True
135 | super()._set_slider_value(self._value)
136 |
137 |
138 | def _set_box_value(self):
139 | if self._slider_widget._boxedit_block:
140 | self._slider_widget._slider_block = False
141 | self._value = self._slider_widget.boxEdit.value() # float(self.clamp(self._slider_widget.boxEdit.value(), int(self.clampRange().min * 1000000.0) if self.clampRange().minLock else -100000000,int(self.clampRange().max * 1000000.0) if self.clampRange().maxLock else 100000000) / 1000000.0)
142 | self._slider_widget.slider.setValue(int(1000000.0 * self._value))
143 | self.setFocus()
144 | self._slider_widget._slider_block = True
145 | super()._set_box_value()
146 |
147 |
148 | def _wheel_set_box_value(self):
149 | if self._slider_widget.boxEdit.wheelState():
150 | self._slider_block = False
151 | self._boxedit_block = False
152 | self._value = self._slider_widget.boxEdit.value()
153 | self._slider_widget.slider.setValue(int(1000000.0 * self._value))
154 | self._slider_block = True
155 | self._boxedit_block = True
156 | super()._set_box_value()
157 |
158 |
159 |
160 |
161 | class IntegerClass(TemplateBuildClass.ParameterBuild):
162 |
163 | def widgetClass(self):
164 | return IntegerSliderClass
165 |
166 |
167 |
168 | class FloatClass(TemplateBuildClass.ParameterBuild):
169 |
170 | def widgetClass(self):
171 | return FloatSliderClass
172 |
173 |
174 |
175 | def register():
176 | UIEditorFactory.WidgetFactory.register('Integer', IntegerClass)
177 | UIEditorFactory.WidgetFactory.register('Float', FloatClass)
178 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.