├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── CHANGELOG.md ├── LICENSE.md ├── PySideLayoutTool ├── Plugins │ ├── TestingWidgetPlugin │ │ ├── Common │ │ │ ├── WidgetTestClass.py │ │ │ └── __init__.py │ │ ├── TestingWidgetPlugin.uiplugin │ │ └── __init__.py │ └── __init__.py ├── UIEditorLib │ ├── EditorDataManger.py │ ├── LayoutConstructorClass.py │ ├── LayoutTemplate.py │ ├── RootWidget.py │ ├── SetupTools.py │ ├── StringValidatorClass.py │ ├── TemplateBuildClass.py │ ├── TemplateDataClass.py │ ├── TemplateDisplayUI.py │ ├── TreeItemInterface.py │ ├── UIEditorFactory.py │ ├── UIEditorIconFactory.py │ ├── UIEditorMediators.py │ ├── UIEditorProperty.py │ ├── UIEditorScript.py │ ├── UIEditorWrapper.py │ ├── UIFunctions.py │ ├── WindowsModule.py │ ├── __init__.py │ └── boilerplate_class.py ├── UIEditorTemplates │ ├── Common │ │ ├── ButtonTemplate │ │ │ ├── ButtonClass.py │ │ │ ├── ButtonWidgetClass.py │ │ │ └── __init__.py │ │ ├── CheckBoxTemplate │ │ │ ├── CheckboxClass.py │ │ │ ├── CheckboxProperty.py │ │ │ ├── CheckboxWidgetClass.py │ │ │ └── __init__.py │ │ ├── ClampRangeTemplate │ │ │ ├── ClampRangeClass.py │ │ │ ├── ClampRangeProperty.py │ │ │ ├── ClampRangeWidgetClass.py │ │ │ └── __init__.py │ │ ├── ColorTemplate │ │ │ ├── ColorClass.py │ │ │ ├── ColorWidgetClass.py │ │ │ └── __init__.py │ │ ├── ComboBoxTemplate │ │ │ ├── ComboBoxClass.py │ │ │ ├── ComboBoxProperty.py │ │ │ ├── ComboBoxWidgetClass.py │ │ │ └── __init__.py │ │ ├── DictionaryTemplate │ │ │ ├── DictionaryClass.py │ │ │ ├── DictionaryWidgetClass.py │ │ │ ├── DictionaryWidgetProperty.py │ │ │ └── __init__.py │ │ ├── FileTemplate │ │ │ ├── FileClass.py │ │ │ ├── FileWidgetClsss.py │ │ │ └── __init__.py │ │ ├── LabelTemplate │ │ │ ├── LabelClass.py │ │ │ ├── LabelSwitchWidget.py │ │ │ └── __init__.py │ │ ├── LineEditTemplate │ │ │ ├── LineEditWidgets.py │ │ │ ├── MultiLineEditClasses.py │ │ │ └── __init__.py │ │ ├── RampTemplate │ │ │ ├── RampClass.py │ │ │ ├── RampColorWidgetClass.py │ │ │ ├── RampWidgetClass.py │ │ │ └── __init__.py │ │ ├── SeparatorTemplate │ │ │ ├── SeparatorClass.py │ │ │ ├── SeparatorWidgetClass.py │ │ │ └── __init__.py │ │ ├── SliderTemplate │ │ │ ├── SliderClass.py │ │ │ ├── SliderWidgetClass.py │ │ │ └── __init__.py │ │ ├── StringEditTemplate │ │ │ ├── StringEditClass.py │ │ │ ├── StringEditProperty.py │ │ │ ├── StringEditWidgetClass.py │ │ │ └── __init__.py │ │ └── __init__.py │ ├── Folder │ │ ├── CollapisbleFolderTemplate │ │ │ ├── CollapisbleFolderClass.py │ │ │ ├── CollapisbleFolderWidgetClass.py │ │ │ └── __init__.py │ │ ├── SimpleFolderTemplate │ │ │ ├── SimpleFolderClass.py │ │ │ └── __init__.py │ │ ├── TabFolderTemplate │ │ │ ├── FolderTabClasses.py │ │ │ ├── FolderTabWidgetClass.py │ │ │ └── __init__.py │ │ └── __init__.py │ ├── IconRegistration.py │ ├── Layout │ │ ├── CustomFormLayout.py │ │ └── __init__.py │ ├── UIEditorTemplates.uiplugin │ └── __init__.py ├── UIEditorWindows │ ├── InitWindow.py │ ├── MainEditorWindow.py │ ├── MainLayoutWindow.py │ ├── NotificationSetup.py │ ├── SettingWindow.py │ ├── TabScript.py │ └── __init__.py ├── main.py ├── resources │ ├── Icons │ │ ├── add_file.svg │ │ ├── arrow_chevron_down.svg │ │ ├── arrow_chevron_up.svg │ │ ├── arrow_down_box.svg │ │ ├── arrow_exchange_alt.svg │ │ ├── arrow_exchange_v.svg │ │ ├── arrow_left_box.svg │ │ ├── border_style_dashed_sep.svg │ │ ├── border_style_solid_sep.svg │ │ ├── checkbox_checked.svg │ │ ├── checkbox_unchecked.svg │ │ ├── checkbox_unchecked_disable.svg │ │ ├── checkerPattern.png │ │ ├── checkerPatternAlpha.png │ │ ├── chevron_arrow_down.svg │ │ ├── chevron_arrow_right.svg │ │ ├── color_picker.svg │ │ ├── comment.svg │ │ ├── eye_view.svg │ │ ├── folder_minus.svg │ │ ├── folder_plus.svg │ │ ├── lock_locked.svg │ │ ├── lock_unlocked.svg │ │ ├── menu_list_display.svg │ │ ├── move_left_arrow.svg │ │ ├── move_right_arrow.svg │ │ ├── normal_close.svg │ │ ├── normal_close_pressed.svg │ │ ├── normal_folder.svg │ │ ├── setting_gear_icon.svg │ │ ├── solid_line.svg │ │ ├── splitter_vertical_alt_2.svg │ │ ├── vertical_alt.svg │ │ ├── zoom_in.svg │ │ └── zoom_out.svg │ ├── __init__.py │ ├── data │ │ ├── CHANGELOG.md │ │ ├── HoudiniStyle.css │ │ ├── LayoutToolBaseStyle.qss │ │ ├── PySideLayoutTool.uiproject │ │ └── __init__.py │ ├── mypysidelayouticons_rc.py │ └── pysidelayouticons.qrc └── saved │ └── __init__.py ├── README.md └── setup.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: JonathanCortez 4 | 5 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## V0.3.1 (2023-05-09) 2 | ___ 3 | - ### Added : 4 | - Added New Widget for Unreal Engine Plugin, replicating the unreal editor

5 | drop-down menu for content classes and level actors. 6 | - ### Update : 7 | - Reworked the Ramp Widget to be more responsive and look to it

8 | also added the missing interpolation types with some blends between them. 9 | 10 | - ### Hotfix : 11 | - Added some small improvements to the MultiFolder(Scroll) widget

12 | with height resize and removing item from list. 13 | 14 | ## V0.3.1 (2023-04-09) 15 | ___ 16 | - ### Hotfix : 17 | - Added `self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)` to

18 | `class Plugin_Create(QtWidgets.QDialog):` to fix crash when closing

19 | inside other DCC. 20 | 21 | ## V0.3.0 (2023-04-09) 22 | ___ 23 | - ### Feature : 24 | - New **Notification** window implementation changelog view. 25 | - To help keep track of new updates and feature implementation for tool. 26 | - New functions have been added in `SetupTools.py`. 27 | - Create Window `?` is working now with notification window. 28 | - Custom plugin path. 29 | - New **Settings** Window has been added under **Create Button**. 30 | - This window will allow you to enable/disable plugins found. 31 | - New system to create plugins. 32 | 33 | - ### Update : 34 | - File **UISetupModule** as been renamed to **SetupTools** 35 | - ` pip Markdown` has been added to install requires for pip setup. 36 | - Initiating **Plugins** system has been slightly reworked to be

37 | more dynamic and easier to use. 38 | - `UIEditorFactory.py` func `unregister` has been updated to work with

39 | the new **Settings > Plugins** window. 40 | - `SetupTools.py` has been slightly reworked to work with the new

41 | implementation of the **Settings > Plugins** window. 42 | - `CreateUISetupWin.py` has been renamed to `InitWindow`. 43 | - `StringValidator.py` improved the special characters compile. 44 | - `WindowsManager.py` has been renamed to `WindowsModule`. 45 | - `README.md` has been updated to reflect the new **Plugins** system and tool usage. 46 | - `SetupTools.py` new functions. 47 | - `set_custom_plugin_loader(plugin_path: str) -> None` 48 | - `load_plugin_modules(plugin_name : str, path : str) -> None` 49 | - `unload_plugin_modules(plugin_name : str, path : str) -> None` 50 | - `Tool_Json_Data() -> tuple` 51 | - `enable_notification(state: bool) -> None` 52 | 53 | - ### Added : 54 | - New **Plugins** system. 55 | - New **Settings** window. 56 | - New **Notification** window. 57 | - New **Create Plugins** window 58 | - Documentation for **Plugins** system has been added. -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /PySideLayoutTool/Plugins/TestingWidgetPlugin/Common/WidgetTestClass.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib.UIEditorFactory import WidgetFactory 2 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty 3 | from PySide2 import QtWidgets 4 | 5 | import PySideLayoutTool.UIEditorLib.TemplateBuildClass as TemplateBuildClass 6 | import PySideLayoutTool.UIEditorLib.LayoutTemplate as LayoutTemplate 7 | 8 | # Class to layout your widgets 9 | class WidgetDemoLayout(QtWidgets.QWidget): 10 | 11 | def __init__(self): 12 | super(WidgetDemoLayout, self).__init__() 13 | self._base_layout = QtWidgets.QVBoxLayout() 14 | self._base_layout.setSpacing(0) 15 | self._base_layout.setContentsMargins(0,0,0,0) 16 | 17 | self._hbox_layout = QtWidgets.QHBoxLayout() 18 | self._hbox_layout.setSpacing(0) 19 | self._hbox_layout.setContentsMargins(0, 0, 0, 0) 20 | 21 | self._line_widget = QtWidgets.QLineEdit('Testing') 22 | self._button_widget = QtWidgets.QPushButton("Push") 23 | 24 | self._hbox_layout.addWidget(self._line_widget) 25 | self._hbox_layout.addWidget(self._button_widget) 26 | 27 | self._base_layout.addLayout(self._hbox_layout) 28 | self.setLayout(self._base_layout) 29 | 30 | 31 | # Base widget class template 32 | """ 33 | LayoutTemplate.ParmSetup : is for most common parameters. 34 | LayoutTemplate.FolderSetup : is good for folder type templates. 35 | 36 | """ 37 | class WidgetDemoClass(LayoutTemplate.ParmSetup): 38 | 39 | def __init__(self,parent=None): 40 | super(WidgetDemoClass, self).__init__(parent) 41 | self._widget = WidgetDemoLayout() 42 | self._layout.addWidget(self._widget) 43 | 44 | 45 | """ 46 | UIProperty decorator which will add a widget info filler 47 | for the widget description. 48 | 49 | Current Widget Properties supported: 50 | - CheckProperty 51 | - ClampProperty 52 | - ComboProperty 53 | - DictionaryProperty 54 | - LineEditProperty 55 | 56 | Can also make your own Property Widget and register to the system. 57 | 58 | """ 59 | 60 | @UIProperty(metaWidget='CheckProperty',label='Check Demo', category='Solo') 61 | def demo_check(self): 62 | pass 63 | 64 | 65 | 66 | 67 | # Class for properly building the widget with the application. 68 | """ 69 | TemplateBuildClass.ParameterBuild: for most common parameters. 70 | TempalteBuildClass.FolderBuild: good for folder types, handling items within items 71 | 72 | """ 73 | class WidgetDemoBuild(TemplateBuildClass.ParameterBuild): 74 | 75 | def widgetClass(self): 76 | return WidgetDemoClass 77 | 78 | 79 | """ 80 | register() and unregister() are required for the plugin to be loaded. 81 | """ 82 | 83 | """ 84 | Register widget to be shown in supported templates. 85 | """ 86 | def register(): 87 | WidgetFactory.register('Demo Widget', WidgetDemoBuild) 88 | 89 | def unregister(): 90 | WidgetFactory.unregister('Demo Widget') 91 | 92 | -------------------------------------------------------------------------------- /PySideLayoutTool/Plugins/TestingWidgetPlugin/Common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/Plugins/TestingWidgetPlugin/Common/__init__.py -------------------------------------------------------------------------------- /PySideLayoutTool/Plugins/TestingWidgetPlugin/TestingWidgetPlugin.uiplugin: -------------------------------------------------------------------------------- 1 | { 2 | "Categories": 3 | [ 4 | { 5 | "Name": "Common", 6 | "Modules": 7 | [ 8 | "WidgetTestClass" 9 | ] 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /PySideLayoutTool/Plugins/TestingWidgetPlugin/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/Plugins/TestingWidgetPlugin/__init__.py -------------------------------------------------------------------------------- /PySideLayoutTool/Plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/Plugins/__init__.py -------------------------------------------------------------------------------- /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/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/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/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/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/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/UIEditorLib/UIEditorFactory.py: -------------------------------------------------------------------------------- 1 | from typing import Callable, Dict, List, Any 2 | 3 | class WidgetFactory: 4 | 5 | widget_creation_funcs: Dict[str, Callable[..., Any]] = {} 6 | widget_category: Dict[str, List[dict]] = {} 7 | 8 | @classmethod 9 | def registerCategory(cls, category: str): 10 | if category not in cls.widget_category: 11 | cls.widget_category[category] = [] 12 | 13 | @classmethod 14 | def unregisterCategory(self, category_name: str): 15 | self.widget_category.pop(category_name, None) 16 | 17 | @classmethod 18 | def register(cls, widget_type: str, creator_fn: Callable[..., Any]) -> None: 19 | """Register a widget layout type.""" 20 | if widget_type not in cls.widget_creation_funcs: 21 | cls.widget_creation_funcs[widget_type] = creator_fn 22 | module_path = creator_fn.__module__ # type: ignore 23 | module_path = module_path.split('.') 24 | index = None 25 | for i in enumerate(module_path): 26 | if i[1] in cls.widget_category: 27 | index = i[0] 28 | break 29 | 30 | tempDict = {} 31 | tempDict[widget_type] = creator_fn 32 | cls.widget_category[module_path[index]].append(tempDict) 33 | 34 | @classmethod 35 | def unregister(cls, widget_name: str) -> None: 36 | """Unregister a widget layout type.""" 37 | cls.widget_creation_funcs.pop(widget_name, None) 38 | 39 | temp_widget_category = dict(cls.widget_category) 40 | 41 | for category in temp_widget_category: 42 | for i in temp_widget_category[category]: 43 | if widget_name in i: 44 | cls.widget_category[category].remove(i) 45 | break 46 | 47 | if len(cls.widget_category[category]) == 0: 48 | cls.unregisterCategory(category) 49 | 50 | 51 | @classmethod 52 | def create(cls,widget_name: str): 53 | """Create a widget of a specific type, given JSON data.""" 54 | try: 55 | creator_func = cls.widget_creation_funcs[widget_name] 56 | except KeyError: 57 | raise ValueError(f"unknown widget type {widget_name!r}, not registered") from None 58 | return creator_func() 59 | 60 | @classmethod 61 | def registered(cls) -> widget_category: 62 | """ Get all registered parameter types""" 63 | return cls.widget_category 64 | 65 | 66 | @classmethod 67 | def ItemCategoryIn(cls, item): 68 | r_key = '' 69 | for key in cls.widget_category: 70 | for i in cls.widget_category[key]: 71 | keys = i.keys() 72 | if item == list(keys)[0]: 73 | r_key = key 74 | break 75 | 76 | return r_key 77 | 78 | @classmethod 79 | def sortCategoryItems(cls, key_list): 80 | tempList = [] 81 | for i in key_list: 82 | tempList.append(list(i)[0]) 83 | 84 | return sorted(tempList, key=lambda x: x.lower()) 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /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/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/UIEditorWrapper.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | from . import WindowsModule, LayoutConstructorClass 3 | 4 | 5 | class UIParameterStateChange: 6 | 7 | def __init__(self, layout): 8 | self._current_layout = layout 9 | 10 | def _check_item(self, data, type, func): 11 | for widget in data: 12 | if hasattr(widget, 'templateGroup'): 13 | for w in widget.templateGroup().templateGroupData().values(): 14 | if hasattr(w, 'templateGroup'): 15 | self._check_item(widget.templateGroup().templateGroupData().values(), type, func) 16 | if w.type().currentItem_name == type: 17 | w.add_delegate(func) 18 | else: 19 | if widget.type().currentItem_name == type: 20 | widget.add_delegate(func) 21 | 22 | def add_callable(self, type: str, func: Callable): 23 | self._check_item(self._current_layout.templateLayout().templateGroupData().values(), type, func) 24 | 25 | def remove_callable(self, type: str, func: Callable): 26 | for widget in self._current_layout.templateLayout().templateGroupData().values(): 27 | if widget.type().currentItem_name == type: 28 | widget.remove_delegate(func) 29 | 30 | 31 | class UIPublicAPIWrapper: 32 | 33 | @classmethod 34 | def create_instantiated_wrapper(cls, layout) -> 'UIAPILayoutWrapper' or None: 35 | 36 | if not layout: 37 | return None 38 | 39 | return UIAPILayoutWrapper(layout) 40 | 41 | @classmethod 42 | def instantiate_ui(cls, name, category, file_data): 43 | UIWindowManger.WindowsManger.initilize_windows(name, 44 | UIWindowManger.WindowsManger.root_save() + f"/{category}/" + name + ".qui", 45 | win_category=category) 46 | editor_win = UIWindowManger.WindowsManger.get_Stack(name, category)[name + '_editor'] 47 | layout_win = UIWindowManger.WindowsManger.get_Stack(name, category)[name + '_layout'] 48 | 49 | with open(file_data) as file: 50 | format_type = file_data.split('.') 51 | if format_type[1] == 'json': 52 | LayoutConstructorClass.JsonConstructor.construct(file, editor_win) 53 | 54 | editor_win.LayoutUpdate() 55 | return UIAPILayoutWrapper(layout_win) 56 | 57 | 58 | class UIAPILayoutWrapper: 59 | 60 | def __init__(self, layout): 61 | self._layout_wrap = layout 62 | 63 | @property 64 | def on_parameter_change(self): 65 | return UIParameterStateChange(self._layout_wrap) 66 | 67 | @property 68 | def on_folder_change(self): 69 | return None 70 | 71 | def on_post_update(self): 72 | pass 73 | 74 | def on_pre_update(self): 75 | pass 76 | 77 | def set_parameter_value(self, name: str, value): 78 | self._layout_wrap.parm(name).set_value(value) 79 | 80 | def get_parameter_value(self, name: str): 81 | return self._layout_wrap.parm(name).eval() 82 | -------------------------------------------------------------------------------- /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/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/UIEditorLib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorLib/__init__.py -------------------------------------------------------------------------------- /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/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/UIEditorTemplates/Common/ButtonTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/ButtonTemplate/__init__.py -------------------------------------------------------------------------------- /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/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/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/UIEditorTemplates/Common/CheckBoxTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/CheckBoxTemplate/__init__.py -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ClampRangeTemplate/ClampRangeClass.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UIProperty 2 | from PySideLayoutTool.UIEditorLib import LayoutTemplate, TemplateBuildClass, UIEditorFactory 3 | from . import ClampRangeWidgetClass 4 | 5 | 6 | class RangeWidgetSetup(LayoutTemplate.ParmSetup): 7 | 8 | def __init__(self, parent, bInt=True): 9 | super(RangeWidgetSetup, self).__init__(parent) 10 | self._range_widget = ClampRangeWidgetClass.ClampRangeWidget(0, 10, False, False, bInt) 11 | self._layout.addWidget(self._range_widget) 12 | 13 | self._range_widget.minEdit_widget.valueChanged.connect(self._range_widget_changed) 14 | self._range_widget.maxEdit_widget.valueChanged.connect(self._range_widget_changed) 15 | self._range_widget.minLock_widget.pressed.connect(self._range_widget_changed) 16 | self._range_widget.maxLock_widget.pressed.connect(self._range_widget_changed) 17 | 18 | @UIProperty(metaWidget='ClampProperty', label='Range', category='Setting') 19 | def clampRange(self): 20 | pass 21 | 22 | def _range_widget_changed(self): 23 | self.notify_expressions() 24 | 25 | def PostUpdate(self): 26 | self._range_widget.minEdit_widget.setToolTip(f"

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/ClampRangeTemplate/ClampRangeProperty.py: -------------------------------------------------------------------------------- 1 | from PySideLayoutTool.UIEditorLib.UIEditorProperty import UICProperty, PropertyFactory, IWidgetProperties 2 | from . import ClampRangeWidgetClass 3 | 4 | @PropertyFactory.register('ClampProperty') 5 | class ClampRangeProperty(IWidgetProperties): 6 | 7 | def __init__(self): 8 | super(ClampRangeProperty, self).__init__() 9 | self._min : int = 0 10 | self._max : int = 10 11 | self._lockmin : bool = False 12 | self._lockmax : bool = False 13 | 14 | self._clamp_widget = ClampRangeWidgetClass.ClampRangeWidget(self._min, self._max, self._lockmin, self._lockmax) 15 | self._layout.addWidget(self._clamp_widget) 16 | 17 | self._clamp_widget.minEdit_widget.valueChanged.connect(self.assignMin) 18 | self._clamp_widget.maxEdit_widget.valueChanged.connect(self.assignMax) 19 | self._clamp_widget.minLock_widget.pressed.connect(lambda: self.lockState(self._clamp_widget.minLock_widget)) 20 | self._clamp_widget.maxLock_widget.pressed.connect(lambda: self.lockState(self._clamp_widget.maxLock_widget)) 21 | 22 | 23 | def override_default(self, defaults: tuple): 24 | self._min = defaults[0] 25 | self._max = defaults[1] if len(defaults) == 2 else self._max 26 | self._lockmin = defaults[2] if len(defaults) == 3 else self._lockmin 27 | self._lockmax = defaults[3] if len(defaults) == 4 else self._lockmax 28 | self._clamp_widget.minEdit_widget.setValue(self._min) 29 | self._clamp_widget.maxEdit_widget.setValue(self._max) 30 | self._clamp_widget.minLock_widget.setChecked(self._lockmin) 31 | self._clamp_widget.maxLock_widget.setChecked(self._lockmax) 32 | 33 | def setValue(self, value): 34 | self._clamp_widget.minEdit_widget.setValue(value['minValue']) 35 | self._clamp_widget.maxEdit_widget.setValue(value['maxValue']) 36 | self._clamp_widget.minLock_widget.setChecked(value['minLock']) 37 | self._clamp_widget.maxLock_widget.setChecked(value['maxLock']) 38 | self._min = int(value['minValue']) 39 | self._max = int(value['maxValue']) 40 | self._lockmin = value['minLock'] 41 | self._lockmax = value['maxLock'] 42 | 43 | def value(self): 44 | clamp_dict = {} 45 | clamp_dict['minValue'] = self._clamp_widget.minEdit_widget.value() 46 | clamp_dict['maxValue'] = self._clamp_widget.maxEdit_widget.value() 47 | clamp_dict['minLock'] = self._clamp_widget.minLock_widget.isChecked() 48 | clamp_dict['maxLock'] = self._clamp_widget.maxLock_widget.isChecked() 49 | return clamp_dict 50 | 51 | def lockState(self, button): 52 | if button is self._clamp_widget.minLock_widget: 53 | self._lockmin = not button.isChecked() 54 | else: 55 | self._lockmax = not button.isChecked() 56 | 57 | 58 | def assignMin(self): 59 | self._min = int(self._clamp_widget.minEdit_widget.value()) 60 | self.setFocus() 61 | 62 | 63 | def assignMax(self): 64 | self._max = int(self._clamp_widget.maxEdit_widget.value()) 65 | self.setFocus() 66 | 67 | 68 | @UICProperty 69 | def min(self) -> int: 70 | """ min value for range""" 71 | return self._min 72 | 73 | @UICProperty 74 | def max(self) -> int: 75 | """ max value for range""" 76 | return self._max 77 | 78 | @UICProperty 79 | def minLock(self): 80 | return self._lockmin 81 | 82 | @UICProperty 83 | def maxLock(self): 84 | return self._lockmax -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ClampRangeTemplate/ClampRangeWidgetClass.py: -------------------------------------------------------------------------------- 1 | from PySide2 import QtWidgets,QtGui 2 | from PySideLayoutTool.UIEditorLib.UIEditorIconFactory import IconEditorFactory 3 | 4 | class ClampRangeWidget(QtWidgets.QWidget): 5 | 6 | def __init__(self, min, max, lockmin, lockmax, int_type=True, validator:bool=True): 7 | super(ClampRangeWidget, self).__init__() 8 | self._validator = self.validator_type(validator) 9 | self._rangeLayout = QtWidgets.QHBoxLayout() 10 | self.setMinimumHeight(40) 11 | self.setMaximumHeight(40) 12 | self._icon_closed = QtGui.QIcon(IconEditorFactory.create('lock_closed')) 13 | self._icon_open = QtGui.QIcon(IconEditorFactory.create('lock_open')) 14 | 15 | self.minLock_widget = QtWidgets.QPushButton() 16 | self.minLock_widget.setFlat(True) 17 | self.minLock_widget.setIcon(QtGui.QIcon(IconEditorFactory.create('lock_open'))) 18 | self.minLock_widget.setMinimumWidth(25) 19 | self.minLock_widget.setMaximumWidth(25) 20 | self.minLock_widget.setCheckable(True) 21 | self.minLock_widget.setChecked(lockmin) 22 | 23 | # Min Edit Line Setup 24 | self.minEdit_widget = QtWidgets.QSpinBox() if int_type else QtWidgets.QDoubleSpinBox() 25 | self.minEdit_widget.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) 26 | self.minEdit_widget.setValue(min) 27 | self.minEdit_widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) 28 | 29 | # Max Edit Line Setup 30 | self.maxEdit_widget = QtWidgets.QSpinBox() if int_type else QtWidgets.QDoubleSpinBox() 31 | self.maxEdit_widget.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) 32 | self.maxEdit_widget.setValue(max) 33 | self.maxEdit_widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) 34 | 35 | self.maxLock_widget = QtWidgets.QPushButton() 36 | self.maxLock_widget.setFlat(True) 37 | self.maxLock_widget.setIcon(QtGui.QIcon(IconEditorFactory.create('lock_open'))) 38 | self.maxLock_widget.setMinimumWidth(25) 39 | self.maxLock_widget.setMaximumWidth(25) 40 | self.maxLock_widget.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 41 | self.maxLock_widget.setCheckable(True) 42 | self.maxLock_widget.setChecked(lockmax) 43 | 44 | self._rangeLayout.addWidget(self.minLock_widget) 45 | self._rangeLayout.addWidget(self.minEdit_widget) 46 | self._rangeLayout.addWidget(self.maxEdit_widget) 47 | self._rangeLayout.addWidget(self.maxLock_widget) 48 | 49 | self.setLayout(self._rangeLayout) 50 | 51 | self.minLock_widget.pressed.connect(lambda: self.lockState(self.minLock_widget)) 52 | self.maxLock_widget.pressed.connect(lambda: self.lockState(self.maxLock_widget)) 53 | 54 | def lockState(self, button): 55 | if not button.isChecked(): 56 | button.setIcon(self._icon_closed) 57 | else: 58 | button.setIcon(self._icon_open) 59 | 60 | def validator_type(self, type:bool): 61 | return QtGui.QIntValidator() if type else QtGui.QDoubleValidator() 62 | 63 | # def sizeHint(self) -> QtCore.QSize: 64 | # return QtCore.QSize(30,30) -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/ClampRangeTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/ClampRangeTemplate/__init__.py -------------------------------------------------------------------------------- /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/Common/ColorTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/ColorTemplate/__init__.py -------------------------------------------------------------------------------- /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/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/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/Common/ComboBoxTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/ComboBoxTemplate/__init__.py -------------------------------------------------------------------------------- /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/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/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/Common/DictionaryTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/DictionaryTemplate/__init__.py -------------------------------------------------------------------------------- /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/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/FileTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/FileTemplate/__init__.py -------------------------------------------------------------------------------- /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/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/LabelTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/LabelTemplate/__init__.py -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/LineEditTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/LineEditTemplate/__init__.py -------------------------------------------------------------------------------- /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/RampTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/RampTemplate/__init__.py -------------------------------------------------------------------------------- /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/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/SeparatorTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/SeparatorTemplate/__init__.py -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/UIEditorTemplates/Common/SliderTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/SliderTemplate/__init__.py -------------------------------------------------------------------------------- /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/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/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/UIEditorTemplates/Common/StringEditTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/StringEditTemplate/__init__.py -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Common/__init__.py -------------------------------------------------------------------------------- /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/Folder/CollapisbleFolderTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Folder/CollapisbleFolderTemplate/__init__.py -------------------------------------------------------------------------------- /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/Folder/SimpleFolderTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Folder/SimpleFolderTemplate/__init__.py -------------------------------------------------------------------------------- /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/UIEditorTemplates/Folder/TabFolderTemplate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Folder/TabFolderTemplate/__init__.py -------------------------------------------------------------------------------- /PySideLayoutTool/UIEditorTemplates/Folder/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Folder/__init__.py -------------------------------------------------------------------------------- /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/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/Layout/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/Layout/__init__.py -------------------------------------------------------------------------------- /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/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorTemplates/__init__.py -------------------------------------------------------------------------------- /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/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/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/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/UIEditorWindows/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/UIEditorWindows/__init__.py -------------------------------------------------------------------------------- /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/add_file.svg: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_chevron_down.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_chevron_up.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_down_box.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 18 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_exchange_alt.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 16 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_exchange_v.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 16 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/arrow_left_box.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 18 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/border_style_dashed_sep.svg: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/border_style_solid_sep.svg: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/checkbox_checked.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 18 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/checkbox_unchecked.svg: -------------------------------------------------------------------------------- 1 | 8 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/checkbox_unchecked_disable.svg: -------------------------------------------------------------------------------- 1 | 8 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/checkerPattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/resources/Icons/checkerPattern.png -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/checkerPatternAlpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/resources/Icons/checkerPatternAlpha.png -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/chevron_arrow_down.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/chevron_arrow_right.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/color_picker.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 18 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/comment.svg: -------------------------------------------------------------------------------- 1 | 8 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/eye_view.svg: -------------------------------------------------------------------------------- 1 | 8 | 14 | 20 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/folder_minus.svg: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/folder_plus.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 18 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/lock_locked.svg: -------------------------------------------------------------------------------- 1 | 8 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/lock_unlocked.svg: -------------------------------------------------------------------------------- 1 | 8 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/menu_list_display.svg: -------------------------------------------------------------------------------- 1 | 8 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/move_left_arrow.svg: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/move_right_arrow.svg: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/normal_close.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/normal_close_pressed.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/normal_folder.svg: -------------------------------------------------------------------------------- 1 | 8 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/setting_gear_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/solid_line.svg: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/splitter_vertical_alt_2.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 16 | 20 | 26 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/vertical_alt.svg: -------------------------------------------------------------------------------- 1 | 8 | 12 | 16 | 20 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/zoom_in.svg: -------------------------------------------------------------------------------- 1 | 8 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/Icons/zoom_out.svg: -------------------------------------------------------------------------------- 1 | 8 | 14 | -------------------------------------------------------------------------------- /PySideLayoutTool/resources/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/resources/__init__.py -------------------------------------------------------------------------------- /PySideLayoutTool/resources/data/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## V0.3.1 (2023-05-09) 2 | ___ 3 | - ### Added : 4 | - Added New Widget for Unreal Engine Plugin, replicating the unreal editor

5 | drop-down menu for content classes and level actors. 6 | - ### Update : 7 | - Reworked the Ramp Widget to be more responsive and look to it

8 | also added the missing interpolation types with some blends between them. 9 | 10 | - ### Hotfix : 11 | - Added some small improvements to the MultiFolder(Scroll) widget

12 | with height resize and removing item from list. 13 | 14 | ## V0.3.1 (2023-04-09) 15 | ___ 16 | - ### Hotfix : 17 | - Added `self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)` to

18 | `class Plugin_Create(QtWidgets.QDialog):` to fix crash when closing

19 | inside other DCC. 20 | 21 | ## V0.3.0 (2023-04-09) 22 | ___ 23 | - ### Feature : 24 | - New **Notification** window implementation changelog view. 25 | - To help keep track of new updates and feature implementation for tool. 26 | - New functions have been added in `SetupTools.py`. 27 | - Create Window `?` is working now with notification window. 28 | - Custom plugin path. 29 | - New **Settings** Window has been added under **Create Button**. 30 | - This window will allow you to enable/disable plugins found. 31 | - New system to create plugins. 32 | 33 | - ### Update : 34 | - File **UISetupModule** as been renamed to **SetupTools** 35 | - ` pip Markdown` has been added to install requires for pip setup. 36 | - Initiating **Plugins** system has been slightly reworked to be

37 | more dynamic and easier to use. 38 | - `UIEditorFactory.py` func `unregister` has been updated to work with

39 | the new **Settings > Plugins** window. 40 | - `SetupTools.py` has been slightly reworked to work with the new

41 | implementation of the **Settings > Plugins** window. 42 | - `CreateUISetupWin.py` has been renamed to `InitWindow`. 43 | - `StringValidator.py` improved the special characters compile. 44 | - `WindowsManager.py` has been renamed to `WindowsModule`. 45 | - `README.md` has been updated to reflect the new **Plugins** system and tool usage. 46 | - `SetupTools.py` new functions. 47 | - `set_custom_plugin_loader(plugin_path: str) -> None` 48 | - `load_plugin_modules(plugin_name : str, path : str) -> None` 49 | - `unload_plugin_modules(plugin_name : str, path : str) -> None` 50 | - `Tool_Json_Data() -> tuple` 51 | - `enable_notification(state: bool) -> None` 52 | 53 | - ### Added : 54 | - New **Plugins** system. 55 | - New **Settings** window. 56 | - New **Notification** window. 57 | - New **Create Plugins** window 58 | - Documentation for **Plugins** system has been added. -------------------------------------------------------------------------------- /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/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/resources/data/__init__.py -------------------------------------------------------------------------------- /PySideLayoutTool/resources/pysidelayouticons.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Icons/add_file.svg 5 | Icons/arrow_chevron_down.svg 6 | Icons/arrow_chevron_up.svg 7 | Icons/arrow_down_box.svg 8 | Icons/arrow_exchange_alt.svg 9 | Icons/arrow_exchange_v.svg 10 | Icons/arrow_left_box.svg 11 | Icons/border_style_dashed_sep.svg 12 | Icons/border_style_solid_sep.svg 13 | Icons/checkbox_checked.svg 14 | Icons/checkbox_unchecked.svg 15 | Icons/checkbox_unchecked_disable.svg 16 | Icons/checkerPattern.png 17 | Icons/checkerPatternAlpha.png 18 | Icons/chevron_arrow_down.svg 19 | Icons/chevron_arrow_right.svg 20 | Icons/color_picker.svg 21 | Icons/comment.svg 22 | Icons/eye_view.svg 23 | Icons/folder_minus.svg 24 | Icons/folder_plus.svg 25 | Icons/lock_locked.svg 26 | Icons/lock_unlocked.svg 27 | Icons/menu_list_display.svg 28 | Icons/move_left_arrow.svg 29 | Icons/move_right_arrow.svg 30 | Icons/normal_close.svg 31 | Icons/normal_close_pressed.svg 32 | Icons/normal_folder.svg 33 | Icons/splitter_vertical_alt_2.svg 34 | Icons/vertical_alt.svg 35 | Icons/zoom_in.svg 36 | Icons/zoom_out.svg 37 | Icons/solid_line.svg 38 | Icons/setting_gear_icon.svg 39 | 40 | -------------------------------------------------------------------------------- /PySideLayoutTool/saved/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanCortez/PySideLayoutTool/dff5bb9ef91a47dd227e72e9ef52c7bcc28f9883/PySideLayoutTool/saved/__init__.py -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | description = """PySide Layout Tool is an open-source graphical user interface (GUI) tool developed using Python and 4 | the PySide2 library for creating and editing layouts in PySide-based applications. The tool provides a simple and 5 | intuitive interface for designing and manipulating widgets and layouts, which are the building blocks of PySide 6 | applications. The PySide Layout Tool allows users to create, edit, and save layouts in various file formats, 7 | including JSON and XML. It also provides a preview mode that allows users to see how the layout will look. The tool 8 | provides a wide range of layout options, including grid layout, horizontal layout, vertical layout, and stacked 9 | layout. The tool is designed to simplify the layout creation process and make it more efficient. Users can drag and 10 | drop widgets onto the canvas and adjust their position and size using the mouse. The tool also provides alignment and 11 | spacing options to help users create a neat and organized layout. """ 12 | 13 | 14 | setup(name='PySideLayoutTool', 15 | version='0.3.4', 16 | description='PySide Layout Tool is an open-source graphical user interface (GUI) tool developed using PySide2', 17 | long_description=description, 18 | maintainer='Jonathan Cortez', 19 | url='https://github.com/JonathanCortez/PySideLayoutTool', 20 | author='Jonathan Cortez', 21 | author_email='jonathancdev@outlook.com', 22 | license='LGPL-3.0', 23 | install_requires=['PySide2>=5.15.2.1', 'Markdown'], 24 | package_data={'PySideLayoutTool.resources': ['data/*.uiproject', 'data/*.css', 'data/*.qss', 'data/*.md', 'Icons/*.svg', '*.qrc'], 25 | 'PySideLayoutTool.UIEditorTemplates': ['*.uiplugin']}, 26 | packages=find_packages(), 27 | classifiers=[ 28 | 'Development Status :: 3 - Alpha', 29 | 'Intended Audience :: Developers', 30 | 'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)', 31 | 'Natural Language :: English', 32 | 'Operating System :: Microsoft :: Windows', 33 | 'Operating System :: Microsoft :: Windows :: Windows 11', 34 | 'Programming Language :: Python :: 3', 35 | 'Programming Language :: Python :: 3.4', 36 | 'Programming Language :: Python :: 3.5', 37 | 'Programming Language :: Python :: 3.6', 38 | 'Programming Language :: Python :: 3.7', 39 | 'Programming Language :: Python :: 3.8', 40 | 'Programming Language :: Python :: 3.9', 41 | 'Programming Language :: Python :: 3.10', 42 | 'Topic :: Software Development :: Libraries :: Python Modules', 43 | 'Topic :: Software Development :: User Interfaces' 44 | ], 45 | ) 46 | --------------------------------------------------------------------------------