universal_tool_template.py

A quick Qt GUI tool development template for cross-platform standalone desktop tools, and sub-tools for python supported host applications, including

It automatically supports any combination of (Python 2.x, Python 3.x in 32bit and 64bit) with (PySide, PyQt4, PySide2, PyQt5)

Detail Documentation at wiki: https://github.com/shiningdesign/universal_tool_template.py/wiki

ClassName.py

The light-weight version of universal_tool_template.py, designed for widget level implementation but still with utt qui() features.

Key Feature

Feature Description
Host Detection Maya, Houdini, Nuke, Fusion, Blender, Notepad++, Desktop
Python Detection 2.x, 3.x, 32bit, 64bit
Qt Binding Detection PySide, PyQt4, PySide2, PyQt5
Universal Coding seamlessly works in above 2x2x4=16 combinations
File IO Support json, cPicle binary, plain text
oneline multi-UI creation quickUI() v4.0; qui() v1.0
one-stop UI management self.uiList, self.iconList, self.hotkey
auto UI-Action bindinig button, menuItem, message button
auto Icon loading maya shelf icon, class name icon
Template Style Option standalone, frameless, trans-irregular, on-top
Global Style Option modern style
Interface Interaction Drag, Move, right-click-menu
Element Style Option invisible-functional button
Extension Features self location for script mode and app mode
Language Features auto Export and Load UI language json

Widget Level of UTT:

v1010 (public release):

New Revolution of UTT - version 2000 series:

v2010 (public release):

Archive Version of UTT - 1000 series


How to Use

(for Version 9 and 10 and newer):

  1. global replace class name "UserClassUI" to "YourToolName" in your editor,
    • in icons folder, the Tool GUI icon should name as "YourToolName.png"
  2. change file name "universal_tool_template.py" to "YourPythonFileName.py",
    • in icons folder, the Maya shelf icon should name as "YourPythonFileName.png", if you name all name the same, then 1 icon is enough
  3. load it up and run
  4. further edit:
    • change the version, date, log, help variable before UserClassUI to update your app internal info

(for Version 8 and older)

  * Prepare into Your Tool:
    1. global replace class name "UniversalToolUI"  to "YourToolName" in your editor,
      * in icons folder, the Tool GUI icon should name as "YourToolName.png"
    2. change file name "universal_tool_template.py" to "YourPythonFileName.py",
      * in icons folder, the Maya shelf icon should name as "YourPythonFileName.png", if you name all name the same, then 1 icon is enough
    3. load it up and run

Get PySide2 for Blender

UPDATE: 2020/06.23 install PySide2 for Blender 2.83

  1. go to Blender install folder, D:\YourPathToThat\blender-2.83.0-windows64\2.83\python\bin
  2. copy the path, and go commandline (type D: enter if your blender in D drive, C drive no need):
  3. for Mac and Linux, same, just cd to that directory, and do above. the drive letter thing is just for windows, if you prefer to put app in other drive
  4. restart blender, you should be able to call “from PySide2 import QtWidgets,QtCore,QtGui” without issue
cd D:\YourPathToThat\blender-2.83.0-windows64\2.83\python\bin
D:
.\python.exe -m pip install PySide2

blender_2.83_pyside2.jpg

One-line Multi-UI Creation Syntax

My Varaible-Free Quick-GUI-Generating Text-Code Syntax

element_list:

ui_name@ui_label;ui_type;ui_opts ##################################### elementA_btn;QPushButton;Title Here elementA_btn@User label;QPushButton;Title Here elementB_choice@Choose one;QComboBox;(A,B,C,4) partB_space;QSpacerItem;(200,10,5,4) elementC_txtEdit@Custom label;LNTextEdit partB_layout;vbox partB_QVBoxLayout

main_split;QSplitter;v main_tab;QTabWidget elementB_grp@System label;QGroupBox;vbox,My Group Title

parentObject parent_name;parent_type;parent_opts ##################################### config_layout;QVBoxLayout config_vbox config_split;QSplitter;v config_split;v config_grp;QGroupBox;vbox,My Group Title main_tab main_tab;QTabWidget

parentObject's insert_opt ##################################### gridLayout: "h", "v" for grid insertion tab: (Tab A, Tab B, Tab C) for tab name insertion

#####################################

qui('elementA_btn;Title Here | elementB_label;Label here', 'config_vbox')

element_list:

ui_name@ui_label;ui_opts ##################################### can't use ; in ui_opts

parentObject parent_name;parent_type;parent_opts ##################################### parentObject's insert_opt #####################################


Universal Tool Template UI creation syntax
-------------

now all the creation is using qui function

| UI element | syntax | 
| --------- | ------------ |
| **QVBoxLayout** | `self.qui('my_vbox')` <br> `self.qui('my_layout;vbox')` |  
| **QHBoxLayout** | `self.qui('my_hbox')` <br> `self.qui('my_layout;hbox')` |  
| **QGridLayout** | `self.qui('my_grid')` <br> `self.qui('my_layout;grid')` |  
| | `self.qui('box_btn;Box \| sphere_btn;Sphere  \| ring_btn;Ring', 'my_layout;grid', 'h')` |  
|  | create and insert those 3 buttons as horizontal row in the grid  | 
| | `self.qui('box_btn;Box \| sphere_btn;Sphere  \| ring_btn;Ring', 'my_layout;grid', 'h')` <br> `self.qui('box2_btn;Box2 \| sphere2_btn;Sphere2 \| ring2_btn;Ring2', 'my_layout', 'h')` | 
|  | create 2 rows of button, first row (Box,Sphere,Rig), second row (Box2,Sphere2,Ring2)  | 
| | `self.qui('cat_btn;Cat \| dog_btn;Dog \| pig_btn;Pig', 'pet_layout;grid', 'v') ` <br> `self.qui('cat2_btn;Cat2 \| dog2_btn;Dog2 \| pig2_btn;Pig2', 'pet_layout', 'v') ` | 
|  | create 2 column of button, first column (cat,dog,pig), second column (cat2,dog2,pig2) | 
| **QFormLayout** | self.qui('my_form') <br> self.qui('my_layout;form') |  
| | `self.qui('name_input@Name:;John \| email_input@Email:;test@test.com', 'entry_form')` |  
|  | create a name input with label "Name:" and default text "John", and then create email input with label "Email" and default text "test@test.com" inside entry_form form layout | 
| | | 
| **QSplitter** | `self.qui('user_layout \| info_layout', 'my_split;h')` <br> `self.qui('user_grp \| info_tab', 'my_split;h')` |
|  | put user UI and info UI side by side in split, <br> child can be either a layout or widget | 
| **QGroupBox** | `self.qui('user2_btn;User2 \| info2_btn;Info2', 'my_grp;vbox,Personal Data')` | 
|  | put user UI and info UI inside "my_grp" group box and with internal vbox layout and title as "Personal Data" <br> Note:**no ,() in title** | 
| **QWidget** | `self.qui('user_label;Name \| user_input', 'user_widget;vbox')` |  
|  | like Groupbox widget, but without a title, useful for hide show a set of UIs | 
| **QTabWidget** | `self.qui('client_layout \| product_layout', 'database_tab;h', '(Client,Product)')` |
|  | put client UI and product UI into database_tab tabwidget, as horizontal tab, with title as "Client", "Product", UI can be either widget or layout | 
| | | 
| **QPushButton** | `self.qui('my_btn;Submit')` |  
|  | create pushbutton with title "Submit" | 
|  | `self.qui('my_btnMsg;Info')`  | 
|  | create pushbutton with title "Info" with automatically pop up a dialog show text string stored in self.uiList['my_msg'] | 
| **QLabel** | `self.qui('info_label;Please select all objects')` |  
|  | a label with text "Please select all objects"  | 
| **QLineEdit** | `self.qui('user_input;Your Email')` |  
|  | a line input with default text "Your Email" | 
| **QCheckBox** | `self.qui('testOnly_check;Run as Test Only')` | 
|  | create a check box with title "Run as Test Only"  | 
| **QComboBox** | `self.qui('objectType_choice;(Box,Sphere,Ring)')` |
|  | create a drop down list with option "Box", "Sphere", "Ring"| 
| || 
| **QTextEdit** | `self.qui('comment_txt;Please write details here')`  |
|  | create a text area with default text "Please write details here" | 
| || 
| **QListWidget** | `self.qui('name_list')` |
|  | note, list has no header and single column | 
| **QTreeWidget** | `self.qui('file_tree;(Name,Path)')` |
|  | create a tree widget with column names as "Name", "Path"| 
| **QTableWidget** | `self.qui('data_table;(Name,Email,Phone)')` |
|  | create a data table with column name as "Name", "Email", "Phone" | 
| || 
| **QSpacerItem** | `self.qui('user_space;(100,30,4,3)')` | 
|  | create a space item with policy expanding horizontally and normal vertically <br> # 0 = fixed; 1 > min; 2 \< max; 3 = prefered; 4 = \<expanding>; 5 = expanding> Aggresive; 6=4 ignored size input | 

now all menu creation is using qui_atn,qui_menu,qui_menubar function (replaced quickMenuAction, quickMenu since v11)

| menu element | syntax | 
| --------- | ------------ |
| **QMenu** | `self.qui_menu('right_menu_createFolder_atn;Create Folder,Ctrl+D \| _ \| right_menu_openFolder_atn;Open Folder', 'right_menu')` |
|  | create a list of menu QAction with title and optional shortcut and form (into) a menu object, while _ means a seperator in menu |
|  | `self.qui_menubar('file_menu;&File \| setting_menu;&Setting \| help_menu;&Help')` |
|  | create a list of menu in menubar |
| **QAction** | `self.qui_atn(ui_name, title, tip=None, icon=None, parent=None, key=None)` <br> `self.qui_atn('importConfig_atn','Import Config (&I)','Import Config Setting.','importConfig.png', 'setting_menu', 'Ctrl+I')`  |
|  | create a detailed QAction with uiList name, title, tip, icon, optionally inside a menu; for simple menuAction creation, just use with qui_menu |
| **QShortcut** | `self.qui_key('editNoter', 'Alt+E', self.editNoter_action )` |
|  | create hotkey without a menuAction, stored in self.hotkey |

File Structure
===================

  * **universal_tool_template_VERSION.py**: main TEMPLATE and USERCLASS and MAIN()
  * **GearBox**: a json config file editor for both language dict files and config export dict files from template.
  * **LNTextEdit.py**: (optional) if you want to use LNTextEdit in your tool.
  * **UITranslator.py**: (optional) a GUI tool to create translation json file from template's exported default language json
  * **install-v5.0_App.mel**: (optional) a quick Maya shelf installer that auto put python tool in maya shelf based on naming format and ctrl+RMB menu for reload your tool, good for code test
  * **universal_tool_template.bat**: window console mode or window mode auto launcher, it detect whether to use launch with pythonw or python by the file name
    * if you name as YourPythonFileName.bat, it will launch a console to run your Py
    * if you name as YourPythonFileName_w.bat, it will use Pythonw to directly run your Py without pop-up console floating there
    * if you name as YourPythonFileName_z.bat, it will launch without console in Python3 (change the py3 path inside)
    * if you name as YourPythonFileName_x.bat, it will launch with console in Python3 (change the py3 path inside)

Screenshot
===================

![universal_tool_template_2010_krita.png](screenshot/universal_tool_template_2010_krita.png?raw=true)
![universal_tool_template_v10.2.png](screenshot/universal_tool_template_v10.2.png?raw=true)
![universal_tool_template_v10.2_blender.png](screenshot/universal_tool_template_v10.2_blender.png?raw=true)
![universal_tool_template_v10.2_fusion.png](screenshot/universal_tool_template_v10.2_fusion.png?raw=true)
![universal_tool_template_v10.2_houdini.png](screenshot/universal_tool_template_v10.2_houdini.png?raw=true)
![universal_tool_template_v8.0.png](screenshot/universal_tool_template_v8.0.png?raw=true)
![universal_tool_template_v7.3.png](screenshot/universal_tool_template_v7.3.png?raw=true)
![universal_tool_template_v5.0.png](screenshot/universal_tool_template_v5.0.png?raw=true)
![universal_tool_template_v4.0.png](screenshot/universal_tool_template_v4.0.png?raw=true)
![universal_tool_template_v3.0.png](screenshot/universal_tool_template_v3.0.png?raw=true)

File Structure in Details
===================

GearBox
-------------
  * a json dict file editor, for editing config dict file exported from template for external config file use.
  * it also can serve a lite or better version of UITranslator.py
  * you can also use it as a example of how universal_tool_template.py can be used to create tools

**screenshot**

![GearBox_v1.0.png](screenshot/GearBox_v1.0.png?raw=true)
![GearBox_v1.0_2.png](screenshot/GearBox_v1.0_2.png?raw=true)

**usage**
  * run the GearBox_w.bat to start it if you have python on windows
  * load the json file from browser inside it,
  * click on the tree item to show in the bottom left preview text box, and use right text box to draft out your edit content and then copy paste into edit field on the tree, by double click the tree item.
  * change the file name if you want to export as different file
  * click export button below to save it

**feature list**
  * v001.1 (2017.09.25)
    * update GearBox to template 1010,
    * fix export null error when there is single data entry in the config_tree and the data has a name
  * v001. (2017.04.17)
    * support dict type json file only
    * file loading and exporting
    * add, remove tree branch
    * edit the field and has a large preview text box to auto loading from selection
    * show pure text for json text data, and show json format text for other type data in tree view

LNTextEdit.py
-------------
  * a line number text edit Ui element, a replacement of the original LNTextEdit and my variations like LNTextEditEx, LNTextEdit_Pside, LNTextEdit_PyQt

**usage**

```python
import LNTextEdit
display_textEdit = LNTextEdit.LNTextEdit()
display_textEdit.setWrap(0)
display_textEdit.setReadOnly(1)
display_textEdit.setReadOnlyStyle(1)
display_textEdit.setZoom(1) # enable text zoom feature

feature list

UITranslator.py

Feature

How to Use

File Structure

screenshot

uitranslator_v1.0.png

auto maya shelf installer v5.0 (install-v5.0_App.mel)

feature and usage:

cross-platform cx_Freeze binary build script