Created
February 2, 2020 11:40
-
-
Save fereria/43b2d6b28a54507bf8a301e1eca17dcd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import sys | |
import os.path | |
import re | |
from PySide2.QtWidgets import (QApplication, | |
QDialog, | |
QTreeView, | |
QAbstractItemView, | |
QVBoxLayout, | |
QItemDelegate, | |
QStyle, | |
QLineEdit, | |
QVBoxLayout, | |
QPushButton, | |
QCompleter, | |
QShortcut) | |
from PySide2.QtCore import (QModelIndex, | |
Qt, | |
QAbstractItemModel, | |
QObject, | |
QEvent, | |
QSortFilterProxyModel, | |
QRegExp, | |
Signal, | |
QStringListModel) | |
from PySide2.QtUiTools import QUiLoader | |
from PySide2.QtGui import (QBrush, | |
QColor, | |
QPen, | |
QKeySequence, | |
QCursor) | |
from pxr import Usd, Sdf | |
sample_usd = "D:/work/usd_py36/usd/tree_view_sample.usda" | |
class TestView(QTreeView): | |
def __init__(self, parent=None): | |
super().__init__(parent) | |
self.setDragEnabled(False) | |
self.setAcceptDrops(True) | |
self.setDragDropOverwriteMode(True) | |
def dragEnterEvent(self, event): | |
if event.mimeData().hasUrls(): | |
event.accept() | |
else: | |
super().dragEnterEvent(event) | |
def dragMoveEvent(self, event): | |
if event.mimeData().hasUrls(): | |
# USふファイルのDDか確認 | |
urls = [x.toLocalFile() for x in event.mimeData().urls() | |
if os.path.splitext(x.toLocalFile())[1] in ['.usda', '.usd', '.usdc']] | |
index = self.indexAt(event.pos()) | |
if index.isValid() and len(urls) > 0: | |
QApplication.setActiveWindow(self) | |
self.setDropIndicatorShown(True) | |
event.accept() | |
else: | |
event.ignore() | |
else: | |
super().dragMoveEvent(event) | |
def dropEvent(self, event): | |
if event.mimeData().hasUrls(): | |
urls = event.mimeData().urls() | |
index = self.indexAt(event.pos()) | |
for url in urls: | |
file = url.toLocalFile() | |
self.model().addUsdReference(file, index) | |
self.expandAll() | |
event.accept() | |
else: | |
super().dropEvent(event) | |
self.setDropIndicatorShown(False) | |
class UISample(QDialog): | |
def __init__(self, parent=None): | |
super().__init__(parent) | |
self.resize(600, 400) | |
self.view = TestView() | |
self.edit = QLineEdit() | |
layout = QVBoxLayout() | |
layout.addWidget(self.view) | |
layout.addWidget(self.edit) | |
self.setLayout(layout) | |
self.model = UsdStageModel(sample_usd) | |
self.view.setModel(self.model) | |
self.delegate = TableDelegate() | |
self.view.setItemDelegate(self.delegate) | |
self.completer = CustomQCompleter(self.edit) | |
self.completer.setModel(self.model) | |
self.edit.setCompleter(self.completer) | |
QShortcut(QKeySequence(Qt.Key_Tab), self, self.showSearchEdit) | |
def showSearchEdit(self): | |
popup = PopupSerchEdit(self) | |
popup.show() | |
class CustomQCompleter(QCompleter): | |
def __init__(self, parent=None): | |
super().__init__(parent=parent) | |
self.setCompletionMode(self.PopupCompletion) | |
self.setCaseSensitivity(Qt.CaseInsensitive) | |
def splitPath(self, path): | |
return re.sub("^/", "", path).split("/") | |
# super(CustomQCompleter, self).splitPath(path) | |
def pathFromIndex(self, index): | |
# SdfPatにに置き換える | |
item = index.data(Qt.UserRole) | |
return item.data(2) | |
class PrimItem(object): | |
def __init__(self, prim=None, parentItem=None): | |
self._prim = prim | |
self._parentItem = parentItem | |
self._childItems = [] | |
def addChild(self, item): | |
self._childItems.append(item) | |
def getChild(self, row): | |
if row <= len(self._childItems): | |
return self._childItems[row] | |
return None | |
def getChildren(self): | |
return self._childItems | |
def getParentItem(self): | |
return self._parentItem | |
def getPrim(self): | |
return self._prim | |
def getFontColor(self): | |
if self._prim.HasAuthoredReferences(): | |
return QColor(255, 121, 0) | |
else: | |
return QColor(0, 0, 0) | |
def row(self): | |
if len(self._parentItem.getChildren()) == 0: | |
return 0 | |
return self._parentItem.getChildren().index(self) | |
def data(self, column): | |
if column == 0: | |
return self._prim.GetName() | |
if column == 1: | |
return self._prim.GetTypeName() | |
if column == 2: | |
return str(self._prim.GetPath()) | |
if column == 3: | |
if self._prim.HasAuthoredReferences(): | |
# print(self._prim.GetName()) | |
for f in self._prim.GetPrimStack(): | |
ref = f.referenceList.prependedItems | |
if len(ref) != 0: | |
return ref[0].assetPath | |
return "" | |
else: | |
return "" | |
BACKGROUND_BASE = QColor(255, 255, 255) | |
BACKGROUND_SELECTED = QColor(204, 230, 255) | |
BACKGROUND_FOCUS = QColor(240, 248, 255) | |
class TableDelegate(QItemDelegate): | |
def __init__(self, parent=None): | |
super().__init__(parent) | |
def paint(self, painter, option, index): | |
data = index.data(Qt.UserRole) | |
bgColor = BACKGROUND_BASE | |
if option.state & QStyle.State_Selected: | |
bgColor = BACKGROUND_SELECTED | |
if option.state & QStyle.State_HasFocus: | |
bgColor = BACKGROUND_FOCUS | |
brush = QBrush(bgColor) | |
painter.fillRect(option.rect, brush) | |
painter.setPen(data.getFontColor()) | |
painter.drawText(option.rect, Qt.TextWordWrap, data.data(index.column())) | |
class UsdStageModel(QAbstractItemModel): | |
header = ["PrimName", "Type", "SdfPath", "ReferencePath"] | |
def __init__(self, usdPath: str, parent=None): | |
super().__init__(parent) | |
# self.setupModelData(data.split('\n'), self.rootItem) | |
self.stage = Usd.Stage.Open(usdPath) | |
self.createModelTree() | |
def createModelTree(self): | |
# {SdfPath:Item} | |
self.rootItem = PrimItem(self.stage.GetPrimAtPath("/"), None) | |
self.prims = {Sdf.Path("/"): self.rootItem} | |
for prim in self.stage.Traverse(): | |
parentPath = prim.GetParent().GetPath() | |
item = PrimItem(prim, self.prims[parentPath]) | |
self.prims[parentPath].addChild(item) | |
self.prims[prim.GetPath()] = item | |
self.layoutChanged.emit() | |
def columnCount(self, parent): | |
return 4 | |
def data(self, index, role): | |
if not index.isValid(): | |
return None | |
item = index.internalPointer() | |
if role == Qt.DisplayRole: | |
return item.data(index.column()) | |
if role == Qt.UserRole: | |
return item | |
if role == Qt.EditRole: | |
return item.data(0) | |
return None | |
def flags(self, index): | |
if not index.isValid(): | |
return Qt.NoItemFlags | |
return Qt.ItemIsEnabled | Qt.ItemIsDropEnabled | Qt.ItemIsDragEnabled | Qt.ItemIsSelectable | |
def index(self, row, column, parent): | |
if not self.hasIndex(row, column, parent): | |
return QModelIndex() | |
if not parent.isValid(): | |
parentItem = self.rootItem | |
else: | |
parentItem = parent.internalPointer() | |
childItem = parentItem.getChild(row) | |
if childItem: | |
index = self.createIndex(row, column, childItem) | |
return index | |
else: | |
return QModelIndex() | |
def parent(self, index): | |
if not index.isValid(): | |
return QModelIndex() | |
childItem = index.internalPointer() | |
parentItem = childItem.getParentItem() | |
if parentItem == self.rootItem: | |
return QModelIndex() | |
return self.createIndex(parentItem.row(), 0, parentItem) | |
def rowCount(self, parent): | |
if parent.column() > 0: | |
return 0 | |
if not parent.isValid(): | |
parentItem = self.rootItem | |
else: | |
parentItem = parent.internalPointer() | |
return len(parentItem.getChildren()) | |
def headerData(self, section, orientation, role): | |
if orientation == Qt.Horizontal and role == Qt.DisplayRole: | |
return self.header[section] | |
def supportedDropActions(self): | |
return Qt.MoveAction | Qt.CopyAction | |
def addUsdReference(self, usdPath, index): | |
item = index.data(Qt.UserRole) | |
prim = item.getPrim() | |
path = prim.GetPath() | |
# DDしたUSDからDefaultPrimを取得 | |
ref_stage = Usd.Stage.Open(usdPath) | |
defPrim = ref_stage.GetDefaultPrim() | |
def_prim = self.stage.DefinePrim(path.AppendChild(defPrim.GetName())) | |
def_prim.GetReferences().AddReference(usdPath) | |
self.createModelTree() | |
class PopupSerchEdit(QDialog): | |
send = Signal(str) | |
def __init__(self, parent=None): | |
super().__init__(parent) | |
self.setWindowFlags(Qt.Popup) | |
self.setAttribute(Qt.WA_TranslucentBackground) | |
layout = QVBoxLayout(self) | |
self.edit = QLineEdit(self) | |
layout.addWidget(self.edit) | |
self.setLayout(layout) | |
# 現在のマウス位置にGUIを出す | |
size_x = 200 | |
size_y = 50 | |
pos = QCursor().pos() | |
self.setGeometry(pos.x() - size_x, | |
pos.y() - size_y, | |
size_x, | |
size_y) | |
self.edit.returnPressed.connect(self.Submit) | |
self.edit.setFocus() | |
# SimpleなAutoCompleteを作る | |
comp = QCompleter(self) | |
comp.setModel(QStringListModel(['hogehoge', 'fugafuga', 'foo', 'bar'])) | |
# 全部表示: UnfilteredPopupCompletion | |
# Inlineに候補を表示: InlineCompletion | |
# POPUP表示: PopupCompletion | |
comp.setCompletionMode(QCompleter.UnfilteredPopupCompletion) | |
self.edit.setCompleter(comp) | |
def Submit(self): | |
# Enterしたら文字をEmitして閉じる | |
self.send.emit(self.edit.text()) | |
self.close() | |
if __name__ == '__main__': | |
app = QApplication(sys.argv) | |
QApplication.setFallbackSessionManagementEnabled(True) | |
a = UISample() | |
a.show() | |
sys.exit(app.exec_()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment