From 7e41e418cbaa2c4d745ab2a5ba372fd60aae628c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=8D=E4=B9=8B=E5=B9=BB=E7=81=B5?= Date: Thu, 9 Dec 2021 07:01:50 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E5=A4=A7=E7=9A=84?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++ script/test_attr_regex_match_dialog.py | 19 ++++ script/test_gen_name_exp_dialog.py | 20 +++++ script/test_main_window.py | 19 ++++ script/test_regex_match_dialog.py | 20 +++++ script/test_rename.py | 38 ++++++++ script/userSetup.py | 16 ++++ src/attr_regex_match.py | 27 ++++++ src/attr_regex_match_dialog.py | 55 ++++++++++++ src/config.py | 19 ++++ src/connect_widget.py | 107 ++++++++++++++++++++++ src/create_node_exp.py | 99 +++++++++++++++++++++ src/gen_name_exp.py | 100 +++++++++++++++++++++ src/gen_name_exp_dialog.py | 65 ++++++++++++++ src/init.py | 61 +++++++++++++ src/main.py | 12 +++ src/main_window.py | 65 ++++++++++++++ src/nodes_widget.py | 118 +++++++++++++++++++++++++ src/qt_widgets/__init__.py | 18 ++++ src/qt_widgets/background.py | 25 ++++++ src/regex_match.py | 25 ++++++ src/regex_match_dialog.py | 54 +++++++++++ src/rename.py | 44 +++++++++ src/rename_widget.py | 101 +++++++++++++++++++++ src/setting.json | 1 + src/setting.py | 42 +++++++++ src/setting_widget.py | 67 ++++++++++++++ src/utils.py | 27 ++++++ 28 files changed, 1272 insertions(+) create mode 100644 script/test_attr_regex_match_dialog.py create mode 100644 script/test_gen_name_exp_dialog.py create mode 100644 script/test_main_window.py create mode 100644 script/test_regex_match_dialog.py create mode 100644 script/test_rename.py create mode 100644 script/userSetup.py create mode 100644 src/attr_regex_match.py create mode 100644 src/attr_regex_match_dialog.py create mode 100644 src/config.py create mode 100644 src/connect_widget.py create mode 100644 src/create_node_exp.py create mode 100644 src/gen_name_exp.py create mode 100644 src/gen_name_exp_dialog.py create mode 100644 src/init.py create mode 100644 src/main.py create mode 100644 src/main_window.py create mode 100644 src/nodes_widget.py create mode 100644 src/qt_widgets/__init__.py create mode 100644 src/qt_widgets/background.py create mode 100644 src/regex_match.py create mode 100644 src/regex_match_dialog.py create mode 100644 src/rename.py create mode 100644 src/rename_widget.py create mode 100644 src/setting.json create mode 100644 src/setting.py create mode 100644 src/setting_widget.py create mode 100644 src/utils.py diff --git a/README.md b/README.md index 71481bd..85c39da 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ # dg_editor 一个maya DG图的编辑工具 + +## 目录 + +- [版权说明](#版权说明) + +### 版权说明 + +该项目签署了Apache-2.0 授权许可,详情请参阅 LICENSE \ No newline at end of file diff --git a/script/test_attr_regex_match_dialog.py b/script/test_attr_regex_match_dialog.py new file mode 100644 index 0000000..3131baf --- /dev/null +++ b/script/test_attr_regex_match_dialog.py @@ -0,0 +1,19 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/5 7:39 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +import imp +import init + +imp.reload(init) +import attr_regex_match_dialog + +print(attr_regex_match_dialog.exec_()) diff --git a/script/test_gen_name_exp_dialog.py b/script/test_gen_name_exp_dialog.py new file mode 100644 index 0000000..1077baf --- /dev/null +++ b/script/test_gen_name_exp_dialog.py @@ -0,0 +1,20 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/22 5:37 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function + +import imp +import init + +imp.reload(init) +import gen_name_exp_dialog + +print(gen_name_exp_dialog.exec_()) diff --git a/script/test_main_window.py b/script/test_main_window.py new file mode 100644 index 0000000..9812197 --- /dev/null +++ b/script/test_main_window.py @@ -0,0 +1,19 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/19 3:54 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +import imp +import init + +imp.reload(init) +import main_window + +win = main_window.new() + diff --git a/script/test_regex_match_dialog.py b/script/test_regex_match_dialog.py new file mode 100644 index 0000000..eae4712 --- /dev/null +++ b/script/test_regex_match_dialog.py @@ -0,0 +1,20 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/5 1:40 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function + +import imp +import init + +imp.reload(init) +import regex_match_dialog + +print(regex_match_dialog.exec_()) diff --git a/script/test_rename.py b/script/test_rename.py new file mode 100644 index 0000000..68474ba --- /dev/null +++ b/script/test_rename.py @@ -0,0 +1,38 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/6 5:48 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +import imp +import init + +imp.reload(init) + +import rename + +import maya.mel as mel + +mel.eval(""" +polySphere -r 1 -sx 20 -sy 20 -ax 0 1 0 -cuv 2 -ch 1; +// 结果: pSphere1 polySphere1 // +select -r pSphere1 ; +doGroup 0 1 1; +doGroup 0 1 1; +doGroup 0 1 1; +doGroup 0 1 1; +doGroup 0 1 1; +doGroup 0 1 1; +duplicate -rr; +//结果: group7 // +select -add group6 ; +""") +rename.add_name_prefix("_") +rename.search_replace_name("gr", "gra") +rename.regex_search_replace_name("o.p", "urp") diff --git a/script/userSetup.py b/script/userSetup.py new file mode 100644 index 0000000..071384f --- /dev/null +++ b/script/userSetup.py @@ -0,0 +1,16 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/19 3:45 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +import sys + +sys.path = [i for i in sys.path if not "\\MASH\\" in i] +sys.path.append(r"D:\Development\python_maya\dg_editor\src") +sys.path.append(r"D:\Development\python_maya\dg_editor\script") diff --git a/src/attr_regex_match.py b/src/attr_regex_match.py new file mode 100644 index 0000000..aaa7448 --- /dev/null +++ b/src/attr_regex_match.py @@ -0,0 +1,27 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/5 7:38 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function + +import re + +import maya.cmds as mc + + +def match(exp): + re_o = re.compile(exp) + for n in mc.ls("*"): + for attr in mc.listAttr(n): + attr = "{}.{}".format(n, attr) + m = re_o.match(attr) + if not m is None: + if m.group() == attr: + yield attr diff --git a/src/attr_regex_match_dialog.py b/src/attr_regex_match_dialog.py new file mode 100644 index 0000000..24f850e --- /dev/null +++ b/src/attr_regex_match_dialog.py @@ -0,0 +1,55 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/5 7:38 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +from PySide2.QtGui import * +from PySide2.QtCore import Qt +from PySide2.QtWidgets import * + +import setting +import attr_regex_match + + +class AttrRegexMatchDialog(QDialog): + def __init__(self, parent=None): + self.names = None + super(AttrRegexMatchDialog, self).__init__(parent) + self.setWindowTitle("attr regex match") + self.main_layout = QHBoxLayout(self) + + self.exp_line_edit = QLineEdit() + self.match_bn = QPushButton("匹配") + self.match_bn.clicked.connect(self.match) + + self.main_layout.addWidget(QLabel("正则表达式: ")) + self.main_layout.addWidget(self.exp_line_edit) + self.main_layout.addWidget(self.match_bn) + # 应用设置 + self.setting() + + def setting(self): + fs = setting.get("font", None) + if fs is None: + fs = QFont().toString() + f = QFont() + f.fromString(fs) + self.setFont(f) + + def match(self): + self.names = list(attr_regex_match.match(self.exp_line_edit.text())) + # print("attr_regex_match_dialog self.names >> ", self.names) + self.close() + + +def exec_(parent=None): + dia = AttrRegexMatchDialog(parent) + dia.exec_() + return dia.names diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..0b02bab --- /dev/null +++ b/src/config.py @@ -0,0 +1,19 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/17 5:12 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals +import os +# 是否处于DEBUG状态 +DEBUG = True +# 版本 +VERSION = "0.1.0" +# 插件目录 +PATH = os.path.dirname(os.path.abspath(__file__)) \ No newline at end of file diff --git a/src/connect_widget.py b/src/connect_widget.py new file mode 100644 index 0000000..e1d8966 --- /dev/null +++ b/src/connect_widget.py @@ -0,0 +1,107 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/20 6:06 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +import config +import sys +from PySide2.QtCore import Qt +from PySide2.QtWidgets import * + +import maya.cmds as mc + +import attr_regex_match_dialog + +from utils import undo_block + + +class FuncSelectWidget(QWidget): + Connect, DisConnect = range(2) + ConnectText = "建立连接" + DisConnectText = "断开连接" + + def __init__(self, parent=None): + super(FuncSelectWidget, self).__init__(parent) + self.main_layout = QHBoxLayout(self) + + self.f_com = QComboBox(self) + self.f_com.addItem(self.ConnectText) + self.f_com.addItem(self.DisConnectText) + + self.main_layout.addWidget(QLabel("功能")) + self.main_layout.addWidget(self.f_com) + self.main_layout.addStretch(0) + + def func(self): + if self.f_com.currentText() == self.ConnectText: + return self.Connect + else: + return self.DisConnect + + +class MatchWidget(QWidget): + def __init__(self, parent=None): + super(MatchWidget, self).__init__(parent) + self.main_layout = QHBoxLayout(self) + self.name_text = QTextEdit() + self.r_layout = QVBoxLayout() + self.regex_match_bn = QPushButton("通过正则表达式匹配") + self.regex_match_bn.clicked.connect(self.regex_match) + self.r_layout.addWidget(self.regex_match_bn) + self.r_layout.addStretch(0) + + self.main_layout.addWidget(self.name_text) + self.main_layout.addLayout(self.r_layout) + + def regex_match(self): + names = attr_regex_match_dialog.exec_(self) + if names is None: + mc.warning("取消了操作") + return + self.name_text.setPlainText("\n".join(names)) + + def names(self): + return list(self.name_text.toPlainText().splitlines()) + + +class ConnectWidget(QWidget): + def __init__(self, parent=None): + super(ConnectWidget, self).__init__(parent) + self.main_layout = QVBoxLayout(self) + + self.func_sel_widget = FuncSelectWidget(self) + self.match_out_attrs_widget = MatchWidget(self) + self.match_in_attrs_widget = MatchWidget(self) + self.do_bn = QPushButton("执行功能") + self.do_bn.clicked.connect(self.do) + + self.main_layout.addWidget(self.func_sel_widget) + self.main_layout.addWidget(QLabel("输出属性: ")) + self.main_layout.addWidget(self.match_out_attrs_widget) + self.main_layout.addWidget(QLabel("输入属性: ")) + self.main_layout.addWidget(self.match_in_attrs_widget) + self.main_layout.addWidget(self.do_bn) + + @undo_block + def do(self): + out_attrs = self.match_out_attrs_widget.names() + in_attrs = self.match_in_attrs_widget.names() + if len(out_attrs) != len(in_attrs): + raise ValueError("输出输入属性数量不一致") + if self.func_sel_widget.func() == FuncSelectWidget.Connect: + for o, i in zip(out_attrs, in_attrs): + mc.connectAttr(o, i) + else: + for o, i in zip(out_attrs, in_attrs): + mc.disconnectAttr(o, i) + + +def new(): + return ConnectWidget() diff --git a/src/create_node_exp.py b/src/create_node_exp.py new file mode 100644 index 0000000..ab6ecb2 --- /dev/null +++ b/src/create_node_exp.py @@ -0,0 +1,99 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/21 6:38 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +import re + + +class TokenBase(object): + def __init__(self, s): + self.s = s + + +class NameToken(TokenBase): + pass + + +class CoToken(TokenBase): + pass + + +class LFToken(TokenBase): + pass + + +class ExpExc(Exception): + pass + + +name_match = re.compile(r"[a-zA-Z0-9_]+") +co_match = re.compile(r":") +lf_match = re.compile(r"\n|\r\n") +skip_space_match = re.compile(r"[ \t]+") + + +def _lex(exp): + while True: + m = skip_space_match.match(exp) + if not m is None: + exp = exp[m.end():] + if len(exp) == 0: + return + m = name_match.match(exp) + if not m is None: + token = NameToken(exp[m.start(): m.end()]) + exp = exp[m.end():] + yield token + continue + m = co_match.match(exp) + if not m is None: + token = CoToken(":") + exp = exp[1:] + yield token + continue + m = lf_match.match(exp) + if not m is None: + token = LFToken(exp[m.start(): m.end()]) + exp = exp[m.end():] + yield token + continue + raise ExpExc("lex error") + + +def compile(exp): + tokens = list(_lex(exp)) + while True: + if len(tokens) == 0: + return + t = tokens[0] + if isinstance(t, LFToken): + tokens.pop(0) + continue + if isinstance(tokens[0], NameToken) and \ + isinstance(tokens[1], CoToken) and \ + isinstance(tokens[2], NameToken): + yield tokens[0].s, tokens[2].s + tokens = tokens[3:] + continue + raise ExpExc("syntax error") + + +if __name__ == "__main__": + test_exp = """\t +\r\n +locator1: transform +locator1: transform + """ + print("test lex") + print(list(compile(test_exp)._lex())) + + print("test synex") + print(list(compile(test_exp))) diff --git a/src/gen_name_exp.py b/src/gen_name_exp.py new file mode 100644 index 0000000..accf49a --- /dev/null +++ b/src/gen_name_exp.py @@ -0,0 +1,100 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/22 6:14 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function + +import re + + +class GenNameExpExc(Exception): + pass + + +class TokenBase(object): + def __init__(self, s): + self.s = s + + def __repr__(self): + return "{}<{}>".format(self.__class__.__name__, self.s) + + +class NameToken(TokenBase): + pass + + +class ValueNameToken(TokenBase): + pass + + +skip_space_match = re.compile(r"[ \t]+") +name_match = re.compile(r"[a-zA-Z0-9_]+") +value_name_match = re.compile(r"\{[a-zA-Z0-9_]+\}") + + +def _lex(exp): + """ + + :param exp: box_{value_name} + :return: + """ + while True: + m = skip_space_match.match(exp) + if not m is None: + exp = exp[m.end():] + if len(exp) == 0: + return + m = name_match.match(exp) + if not m is None: + token = NameToken(exp[m.start(): m.end()]) + exp = exp[m.end():] + yield token + continue + m = value_name_match.match(exp) + if not m is None: + token = ValueNameToken(exp[m.start() + 1: m.end() - 1]) + exp = exp[m.end():] + yield token + continue + raise GenNameExpExc("lex error") + + +def compile(exp, values): + """ + + :param exp: box_{value_name} or {value_name}_box or box_{value_name}_joint + :param values: [{k: v, ...}, ...] + :return: + """ + tokens = list(_lex(exp)) + for kv in values: + name = "" + for t in tokens: + if isinstance(t, NameToken): + name += t.s + else: + v = kv.get(t.s) + if v is None: + raise GenNameExpExc("ket not fount") + name += str(v) + yield name + + +if __name__ == "__main__": + test_exp = "box_{name_id}_joint" + print("test lex") + print(list(_lex(test_exp))) + print("test compile") + print(list(compile(test_exp, [ + {"name_id": 0}, + {"name_id": 1}, + {"name_id": 2}, + {"name_id": 3}, + ]))) diff --git a/src/gen_name_exp_dialog.py b/src/gen_name_exp_dialog.py new file mode 100644 index 0000000..d874f0d --- /dev/null +++ b/src/gen_name_exp_dialog.py @@ -0,0 +1,65 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/22 5:35 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +from PySide2.QtGui import * +from PySide2.QtCore import Qt +from PySide2.QtWidgets import * + +import setting +import gen_name_exp + + +class GenNameDialog(QDialog): + def __init__(self, parent=None): + self.names = None + super(GenNameDialog, self).__init__(parent) + self.setWindowTitle("gen name") + self.main_layout = QHBoxLayout(self) + + self.node_size = QSpinBox() + self.node_size.setRange(5, 9999) + self.exp_line_edit = QLineEdit() + self.type_line_edit = QLineEdit() + self.gen_bn = QPushButton("生成") + self.gen_bn.clicked.connect(self.gen) + + self.main_layout.addWidget(QLabel("节点计数: ")) + self.main_layout.addWidget(self.node_size) + self.main_layout.addWidget(QLabel("表达式: ")) + self.main_layout.addWidget(self.exp_line_edit) + self.main_layout.addWidget(QLabel("节点类型: ")) + self.main_layout.addWidget(self.type_line_edit) + self.main_layout.addWidget(self.gen_bn) + # 应用设置 + self.setting() + + def setting(self): + fs = setting.get("font", None) + if fs is None: + fs = QFont().toString() + f = QFont() + f.fromString(fs) + self.setFont(f) + + def gen(self): + node_size = self.node_size.value() + exp = self.exp_line_edit.text() + type_ = self.type_line_edit.text() + values = [{"name_id": i} for i in range(node_size)] + self.names = [(n, type_) for n in gen_name_exp.compile(exp, values)] + self.close() + + +def exec_(parent=None): + dia = GenNameDialog(parent) + dia.exec_() + return dia.names diff --git a/src/init.py b/src/init.py new file mode 100644 index 0000000..1d089b0 --- /dev/null +++ b/src/init.py @@ -0,0 +1,61 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/17 5:12 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +import imp +import config + +imp.reload(config) + +# 导入所有需要的模块 +import qt_widgets + +import create_node_exp +import regex_match +import attr_regex_match +import rename +import setting + +import gen_name_exp_dialog +import regex_match_dialog +import attr_regex_match_dialog + +import nodes_widget +import connect_widget +import rename_widget +import setting_widget + +import main_window + +# 模块列表 +modules = [ + qt_widgets, + + create_node_exp, + regex_match, + attr_regex_match, + rename, + setting, + + gen_name_exp_dialog, + regex_match_dialog, + attr_regex_match_dialog, + + nodes_widget, + connect_widget, + rename_widget, + setting_widget, + + main_window, +] +if config.DEBUG: + # 在DEBUG下reload所有模块 + for m in modules: + imp.reload(m) diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..2325091 --- /dev/null +++ b/src/main.py @@ -0,0 +1,12 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/17 5:12 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +# 作为启动模块 diff --git a/src/main_window.py b/src/main_window.py new file mode 100644 index 0000000..cdaa80f --- /dev/null +++ b/src/main_window.py @@ -0,0 +1,65 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/19 3:46 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +import config +import sys +from PySide2.QtGui import * +from PySide2.QtCore import Qt +from PySide2.QtWidgets import * +from maya.OpenMayaUI import MQtUtil +from shiboken2 import wrapInstance + +import setting + +import nodes_widget +import connect_widget +import rename_widget +import setting_widget + + +class MainWindow(QWidget): + def __init__(self): + super(MainWindow, self).__init__() + if sys.version_info.major >= 3: + self.setParent(wrapInstance(int(MQtUtil.mainWindow()), QWidget)) + else: + self.setParent(wrapInstance(long(MQtUtil.mainWindow()), QWidget)) + self.setWindowFlags(Qt.Window) + + self.setWindowTitle("dg editor {}".format(config.VERSION)) + + self.main_layout = QVBoxLayout(self) + self.main_layout.setContentsMargins(0, 0, 0, 0) + self.tab = QTabWidget(self) + self.main_layout.addWidget(self.tab) + self.tab.addTab(nodes_widget.new(), "节点") + self.tab.addTab(connect_widget.new(), "连接") + self.tab.addTab(rename_widget.new(), "名称") + self.tab.addTab(setting_widget.new(), "设置") + + # 应用设置 + self.setting() + + def setting(self): + fs= setting.get("font", None) + if fs is None: + fs = QFont().toString() + f = QFont() + f.fromString(fs) + self.setFont(f) + + +def new(): + win = MainWindow() + win.show() + if config.DEBUG: + return win diff --git a/src/nodes_widget.py b/src/nodes_widget.py new file mode 100644 index 0000000..50383ba --- /dev/null +++ b/src/nodes_widget.py @@ -0,0 +1,118 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/11/20 6:06 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +import config +from PySide2.QtGui import * +from PySide2.QtCore import Qt +from PySide2.QtWidgets import * + +import maya.cmds as mc + +import create_node_exp +import gen_name_exp_dialog +import regex_match_dialog + +from utils import undo_block +from qt_widgets import Background + +class CreateWidget(Background): + def __init__(self, parent=None): + super(CreateWidget, self).__init__(parent) + self.main_layout = QVBoxLayout(self) + + self.body_layout = QHBoxLayout() + + self.name_text = QTextEdit() + self.create_exp_bn_layout = QVBoxLayout() + self.create_exp_bn = QPushButton("通过表达式创建") + self.create_exp_bn.setFixedWidth(120) + self.create_exp_bn.clicked.connect(self.create_exp) + self.create_exp_bn_layout.addWidget(self.create_exp_bn) + self.create_exp_bn_layout.addStretch(0) + + self.body_layout.addWidget(self.name_text) + self.body_layout.addLayout(self.create_exp_bn_layout) + + self.create_bn = QPushButton("创建") + self.create_bn.clicked.connect(self.create_node) + + self.main_layout.addWidget(QLabel("创建: ")) + self.main_layout.addLayout(self.body_layout) + self.main_layout.addWidget(self.create_bn) + + def create_exp(self): + names = gen_name_exp_dialog.exec_(self) + if names is None: + mc.warning("取消了操作") + return + self.name_text.setText("\n".join(("{}: {}".format(n, t) for n, t in names))) + + @undo_block + def create_node(self): + exp = self.name_text.toPlainText() + for n, t in create_node_exp.compile(exp): + mc.createNode(t, n=n) + + +class DeleteWidget(Background): + def __init__(self, parent=None): + super(DeleteWidget, self).__init__(parent) + self.main_layout = QVBoxLayout(self) + + self.body_layout = QHBoxLayout() + + self.name_text = QTextEdit() + self.match_exp_bn_layout = QVBoxLayout() + self.match_exp_bn = QPushButton("通过正则表达式匹配") + self.match_exp_bn.setFixedWidth(120) + self.match_exp_bn.clicked.connect(self.regex_match) + self.match_exp_bn_layout.addWidget(self.match_exp_bn) + self.match_exp_bn_layout.addStretch(0) + + self.body_layout.addWidget(self.name_text) + self.body_layout.addLayout(self.match_exp_bn_layout) + + self.delete_bn = QPushButton("删除") + self.delete_bn.clicked.connect(self.delete_nodes) + + self.main_layout.addWidget(QLabel("删除: ")) + self.main_layout.addLayout(self.body_layout) + self.main_layout.addWidget(self.delete_bn) + + def regex_match(self): + names = regex_match_dialog.exec_(self) + if names is None: + mc.warning("取消了操作") + return + self.name_text.setPlainText("\n".join(names)) + + @undo_block + def delete_nodes(self): + nodes = list(self.name_text.toPlainText().splitlines()) + if len(nodes) < 1: + return + mc.delete(nodes) + + +class NodesWidget(QWidget): + def __init__(self, parent=None): + super(NodesWidget, self).__init__(parent) + self.main_layout = QVBoxLayout(self) + self.create_widget = CreateWidget(self) + self.delete_widget = DeleteWidget(self) + + self.main_layout.addWidget(self.create_widget) + self.main_layout.addWidget(self.delete_widget) + + +def new(): + return NodesWidget() diff --git a/src/qt_widgets/__init__.py b/src/qt_widgets/__init__.py new file mode 100644 index 0000000..ea0d139 --- /dev/null +++ b/src/qt_widgets/__init__.py @@ -0,0 +1,18 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/8 5:53 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +import config +import imp +from . import background + +if config.DEBUG: + imp.reload(background) +from .background import Background diff --git a/src/qt_widgets/background.py b/src/qt_widgets/background.py new file mode 100644 index 0000000..7809afa --- /dev/null +++ b/src/qt_widgets/background.py @@ -0,0 +1,25 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/8 5:53 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function + +from PySide2.QtGui import * +from PySide2.QtCore import Qt +from PySide2.QtWidgets import * + + +class Background(QWidget): + def paintEvent(self, *args, **kwargs): + p = QPainter(self) + p.setPen(Qt.NoPen) + p.setBrush(QBrush(QColor(65, 65, 65))) + p.drawRect(self.rect()) + p.end() diff --git a/src/regex_match.py b/src/regex_match.py new file mode 100644 index 0000000..e2c5708 --- /dev/null +++ b/src/regex_match.py @@ -0,0 +1,25 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/5 1:43 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function + +import re + +import maya.cmds as mc + + +def match(exp): + re_o = re.compile(exp) + for n in mc.ls("*"): + m = re_o.match(n) + if not m is None: + if m.group() == n: + yield n diff --git a/src/regex_match_dialog.py b/src/regex_match_dialog.py new file mode 100644 index 0000000..a8a9d99 --- /dev/null +++ b/src/regex_match_dialog.py @@ -0,0 +1,54 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/5 1:39 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +from PySide2.QtGui import * +from PySide2.QtCore import Qt +from PySide2.QtWidgets import * + +import setting +import regex_match + + +class RegexMatchDialog(QDialog): + def __init__(self, parent=None): + self.names = None + super(RegexMatchDialog, self).__init__(parent) + self.setWindowTitle("regex match") + self.main_layout = QHBoxLayout(self) + + self.exp_line_edit = QLineEdit() + self.match_bn = QPushButton("匹配") + self.match_bn.clicked.connect(self.match) + + self.main_layout.addWidget(QLabel("正则表达式: ")) + self.main_layout.addWidget(self.exp_line_edit) + self.main_layout.addWidget(self.match_bn) + # 应用设置 + self.setting() + + def setting(self): + fs = setting.get("font", None) + if fs is None: + fs = QFont().toString() + f = QFont() + f.fromString(fs) + self.setFont(f) + + def match(self): + self.names = list(regex_match.match(self.exp_line_edit.text())) + self.close() + + +def exec_(parent=None): + dia = RegexMatchDialog(parent) + dia.exec_() + return dia.names diff --git a/src/rename.py b/src/rename.py new file mode 100644 index 0000000..8a6b5b1 --- /dev/null +++ b/src/rename.py @@ -0,0 +1,44 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/6 5:37 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function + +import re + +import maya.cmds as mc + + +def _selection_list_uids(): + sel = mc.ls(sl=True, l=True) + nodes = [n for i in sel for o in ([i], mc.listRelatives(i, ad=True, pa=True)) for n in o] + uids = mc.ls(nodes, uid=True) + return uids + + +def add_name_prefix(prefix): + for uid in _selection_list_uids(): + n = mc.ls(uid)[0] + mc.rename(n, prefix + n.split("|")[-1]) + + +def search_replace_name(search, replace): + for uid in _selection_list_uids(): + n = mc.ls(uid)[0] + sn = n.split("|")[-1] + mc.rename(n, sn.replace(search, replace)) + + +def regex_search_replace_name(search, replace): + re_o = re.compile(search) + for uid in _selection_list_uids(): + n = mc.ls(uid)[0] + sn = n.split("|")[-1] + mc.rename(n, re_o.sub(replace, sn)) diff --git a/src/rename_widget.py b/src/rename_widget.py new file mode 100644 index 0000000..02d87fb --- /dev/null +++ b/src/rename_widget.py @@ -0,0 +1,101 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/6 4:35 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +import config +import sys +from PySide2.QtGui import * +from PySide2.QtCore import Qt +from PySide2.QtWidgets import * + +import rename +from utils import undo_block +from qt_widgets import Background + + +class AddNamePrefix(Background): + def __init__(self, parent=None): + super(AddNamePrefix, self).__init__(parent) + self.main_layout = QVBoxLayout(self) + # + self.body_layout = QHBoxLayout() + + self.prefix = QLineEdit() + self.do_bn = QPushButton("添加") + self.do_bn.clicked.connect(self.add_name_prefix) + + self.body_layout.addWidget(QLabel("前缀")) + self.body_layout.addWidget(self.prefix) + self.body_layout.addWidget(self.do_bn) + # + self.main_layout.addWidget(QLabel("添加名称前缀: ")) + self.main_layout.addLayout(self.body_layout) + + @undo_block + def add_name_prefix(self): + rename.add_name_prefix(self.prefix.text()) + + +class ReplaceNameWidget(Background): + def __init__(self, parent=None): + super(ReplaceNameWidget, self).__init__(parent) + self.main_layout = QVBoxLayout(self) + + self.search_layout = QHBoxLayout() + self.search = QLineEdit() + self.search_layout.addWidget(QLabel("搜索:")) + self.search_layout.addWidget(self.search) + + self.replace_layout = QHBoxLayout() + self.replace = QLineEdit() + self.replace_layout.addWidget(QLabel("替换:")) + self.replace_layout.addWidget(self.replace) + # + self.do_bn_layout = QHBoxLayout() + + self.search_replace_bn = QPushButton("搜索替换") + self.search_replace_bn.clicked.connect(self.search_replace) + + self.regex_search_replace_bn = QPushButton("正则搜索替换") + self.regex_search_replace_bn.clicked.connect(self.regex_search_replace) + + self.do_bn_layout.addWidget(self.search_replace_bn) + self.do_bn_layout.addWidget(self.regex_search_replace_bn) + # + self.main_layout.addWidget(QLabel("搜索替换名称: ")) + self.main_layout.addLayout(self.search_layout) + self.main_layout.addLayout(self.replace_layout) + self.main_layout.addLayout(self.do_bn_layout) + self.main_layout.addStretch(0) + + @undo_block + def search_replace(self): + rename.search_replace_name(self.search.text(), self.replace.text()) + + @undo_block + def regex_search_replace(self): + rename.regex_search_replace_name(self.search.text(), self.replace.text()) + + +class RenameWidget(QWidget): + def __init__(self, parent=None): + super(RenameWidget, self).__init__(parent) + self.main_layout = QVBoxLayout(self) + + self.add_name_prefix = AddNamePrefix() + self.replace_name = ReplaceNameWidget() + + self.main_layout.addWidget(self.add_name_prefix) + self.main_layout.addWidget(self.replace_name) + + +def new(): + return RenameWidget() diff --git a/src/setting.json b/src/setting.json new file mode 100644 index 0000000..b0fc88f --- /dev/null +++ b/src/setting.json @@ -0,0 +1 @@ +{"font": "\u7ad9\u9177\u6587\u827a\u4f53,12,-1,5,50,0,0,0,0,0", "font_size": 10} \ No newline at end of file diff --git a/src/setting.py b/src/setting.py new file mode 100644 index 0000000..58497a4 --- /dev/null +++ b/src/setting.py @@ -0,0 +1,42 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/6 7:08 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +import config +import os +import json +import codecs + +SETTING_FILE = os.path.join(config.PATH, "setting.json") + + +def _open_setting_file(): + if not os.path.isfile(SETTING_FILE): + with codecs.open(SETTING_FILE, "w", encoding="utf-8") as f: + json.dump(dict(), f) + with codecs.open(SETTING_FILE, "r", encoding="utf-8") as f: + return json.load(f) + + +def _save_setting_file(data): + with codecs.open(SETTING_FILE, "w", encoding="utf-8") as f: + json.dump(data, f) + + +def set(key, val): + data = _open_setting_file() + data[key] = val + _save_setting_file(data) + + +def get(key, default): + data = _open_setting_file() + return data.get(key, default) diff --git a/src/setting_widget.py b/src/setting_widget.py new file mode 100644 index 0000000..08161e3 --- /dev/null +++ b/src/setting_widget.py @@ -0,0 +1,67 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/6 6:59 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function +import config +from PySide2.QtGui import * +from PySide2.QtCore import Qt +from PySide2.QtWidgets import * + +import maya.cmds as mc + +import setting +from qt_widgets import Background + + +class FontSettingWidget(Background): + def __init__(self, parent=None): + super(FontSettingWidget, self).__init__(parent) + self.main_layout = QHBoxLayout(self) + + self.font = QLabel(self.font_setting()) + self.font_setting_bn = QPushButton("设置") + self.font_setting_bn.clicked.connect(self.set_font_setting) + self.main_layout.addWidget(QLabel("字体: ")) + self.main_layout.addWidget(self.font) + self.main_layout.addWidget(self.font_setting_bn) + + def font_setting(self): + f = setting.get("font", None) + if f is None: + return QFont().toString() + return f + + def set_font_setting(self): + a, b = QFontDialog.getFont() + if type(a) == bool: + ok = a + f = b + else: + ok = b + f = a + if ok: + setting.set("font", f.toString()) + else: + mc.warning("取消了操作") + + +class RenameWidget(QWidget): + def __init__(self, parent=None): + super(RenameWidget, self).__init__(parent) + self.main_layout = QVBoxLayout(self) + + self.font_setting_widget = FontSettingWidget() + self.main_layout.addWidget(self.font_setting_widget) + self.main_layout.addStretch(0) + + +def new(): + return RenameWidget() diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..af6c57a --- /dev/null +++ b/src/utils.py @@ -0,0 +1,27 @@ +# -*-coding:utf-8 -*- +u""" +:创建时间: 2021/12/8 4:54 +:作者: 苍之幻灵 +:我的主页: https://cpcgskill.com +:QQ: 2921251087 +:爱发电: https://afdian.net/@Phantom_of_the_Cang +:aboutcg: https://www.aboutcg.org/teacher/54335 +:bilibili: https://space.bilibili.com/351598127 + +""" +from __future__ import unicode_literals, print_function + +import functools +import maya.cmds as mc + + +def undo_block(fn): + @functools.wraps(fn) + def _(*args, **kwargs): + mc.undoInfo(ock=True) + try: + return fn(*args, **kwargs) + finally: + mc.undoInfo(cck=True) + + return _