<?xml version="1.0" encoding="UTF-8"?>
<pythonPanelDocument>
<!--
This file contains the definition for the viewport color editor panel
-->
<interface name="viewport_color_editor" label="Viewport Color Editor" icon="MISC_python">
<script><![CDATA[########################################################################
# Replace the sample code below with your own to create a
# PyQt or PySide interface. Your code must define a 'onCreateInterface()'
# function that returns the root widget of your interface.
########################################################################
import os
from hutil.Qt import QtCore, QtGui, QtWidgets
class ColorInfo:
theDialog = None
def __init__(self, name, values, comment):
self.myName = name
self.myValues = values
self.myOrigValues = values
self.myComment = comment
def __str__(self):
if isinstance(self.myValues, str):
return self.myName + ":\t@" + \
self.myValues + "\t# " + \
self.myComment
elif self.isAlpha():
return self.myName + ":\tALPHA " + \
str(self.myValues[0]) + "\t# " + \
self.myComment
else:
return self.myName + ":\t" + \
str(self.myValues[0]) + " " + \
str(self.myValues[1]) + " " + \
str(self.myValues[2]) + "\t# " + \
self.myComment
def getValueStr(self):
if isinstance(self.myValues, str):
return "@" + self.myValues
elif self.isAlpha():
valuestr = str(self.myValues[0])
else:
valuestr = str(self.myValues)
return valuestr
def isAlpha(self):
if isinstance(self.myValues, str):
return self.findReference(self.myValues).isAlpha()
else:
return len(self.myValues) == 1
def getAlpha(self):
if isinstance(self.myValues, str):
return self.findReference(self.myValues).getAlpha()
else:
return self.myValues[0]
def getColor(self):
if isinstance(self.myValues, str):
return self.findReference(self.myValues).getColor()
else:
return QtGui.QColor.fromRgbF(self.myValues[0], \
self.myValues[1], \
self.myValues[2])
def getColorStyleStr(self):
if isinstance(self.myValues, str):
return self.findReference(self.myValues).getColorStyleStr()
elif not self.isAlpha() and \
(self.myValues[0] + self.myValues[1] + self.myValues[2]) < 0.75:
return "background-color: rgb(" + \
str(int(self.myValues[0] * 255.0)) + ", " + \
str(int(self.myValues[1] * 255.0)) + ", " + \
str(int(self.myValues[2] * 255.0)) + "); " + \
"color: white;"
else:
return "background-color: rgb(" + \
str(int(self.myValues[0] * 255.0)) + ", " + \
str(int(self.myValues[1] * 255.0)) + ", " + \
str(int(self.myValues[2] * 255.0)) + ");"
def twoDigits(self, val):
if isinstance(val, float):
return float(int(val * 100.0)) / 100.0
else:
l = []
for v in val:
l.append(float(int(v * 100.0)) / 100.0)
return l
def setAlpha(self, value):
try:
self.myValues[0] = float(value)
for info in ColorInfo.theDialog.myInfos:
if (info == self or info.mySelected.isChecked()) and \
info.myShown and info.isAlpha():
if info != self:
info.myValues = self.myName
ColorInfo.theDialog.myChanged = True
except:
pass
def doneAlpha(self):
for info in ColorInfo.theDialog.myInfos:
if (info == self or info.mySelected.isChecked()) and \
info.myShown and info.isAlpha():
info.myAlphaValue.setText(info.getValueStr())
def setColor(self):
color = QtWidgets.QColorDialog.getColor(self.getColor())
if color.isValid():
self.myValues = list(self.twoDigits(color.getRgbF()))
for info in ColorInfo.theDialog.myInfos:
if (info == self or info.mySelected.isChecked()) and \
info.myShown and not info.isAlpha():
if info != self:
info.myValues = self.myName
info.myColorValue.setText(info.getValueStr())
info.myColorValue.setStyleSheet(info.getColorStyleStr())
ColorInfo.theDialog.myChanged = True
def setComment(self, comment):
self.myComment = comment
def findReference(self, reference):
return ColorInfo.theDialog.findColor(reference)
class Dialog(QtWidgets.QFrame):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
ColorInfo.theDialog = self
# Create the filter input field and add the widgets to a scrolling
# list in the dialog.
self.myFilterRow = QtWidgets.QHBoxLayout()
self.myFilterLabel = QtWidgets.QLabel("Filter:")
self.myFilter = QtWidgets.QLineEdit()
self.myFilter.textChanged.connect(self.doFilterUpdated)
self.myFilterChanged = QtWidgets.QCheckBox("Changed Values")
self.myFilterChanged.stateChanged.connect(self.doFilterChangedUpdated)
self.myFilterRow.addWidget(self.myFilterLabel)
self.myFilterRow.addWidget(self.myFilter)
self.myFilterRow.addWidget(self.myFilterChanged)
self.myScroller = QtWidgets.QScrollArea()
self.myScroller.setWidgetResizable(True)
self.myActionRow = QtWidgets.QHBoxLayout()
self.myClearSelectionButton = QtWidgets.QPushButton("Clear Selection")
self.myClearSelectionButton.clicked.connect(self.doClearSelection)
self.mySchemeMenu = QtWidgets.QComboBox()
self.mySchemeMenu.setEditable(False)
self.mySchemeMenu.addItem("Light", "config/3DSceneColors.light")
self.mySchemeMenu.addItem("Dark", "config/3DSceneColors.dark")
self.mySchemeMenu.addItem("Grey", "config/3DSceneColors.bw")
self.mySchemeMenu.currentIndexChanged.connect(self.doSchemeChanged)
self.mySaveButton = QtWidgets.QPushButton("Save")
self.mySaveButton.clicked.connect(self.doSave)
self.myQuitButton = QtWidgets.QPushButton("Revert")
self.myQuitButton.clicked.connect(self.doLoad)
self.myActionRow.addWidget(self.myClearSelectionButton)
self.myActionRow.addStretch(1)
self.myActionRow.addWidget(QtWidgets.QLabel("Color Scheme:"))
self.myActionRow.addWidget(self.mySchemeMenu)
self.myActionRow.addStretch(1)
self.myActionRow.addWidget(self.mySaveButton)
self.myActionRow.addWidget(self.myQuitButton)
# Create the initial dialog layout.
mainLayout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.Direction.TopToBottom)
mainLayout.addLayout(self.myFilterRow)
mainLayout.addWidget(self.myScroller)
mainLayout.addLayout(self.myActionRow)
self.setLayout(mainLayout)
self.doLoad()
def findColor(self, name):
for info in self.myInfos:
if info.myName == name:
return info
return ColorInfo(name, [0.0, 0.0, 0.0], "")
def doFilterUpdated(self, state):
self.fillColorList(self.myFilter.text(), \
self.myFilterChanged.isChecked())
def doFilterChangedUpdated(self, state):
self.fillColorList(self.myFilter.text(), \
self.myFilterChanged.isChecked())
def fillColorList(self, filterStr = None, changedOnly = False):
# Sort widgets into shown or hidden containers. The hidden container
# exists to make sure the underlying QT widgets don't get deleted.
hiddenWidget = QtWidgets.QWidget()
hidden = QtWidgets.QGridLayout()
shownWidget = QtWidgets.QWidget()
shown = QtWidgets.QGridLayout()
shown.setColumnStretch(4, 1)
shown.setColumnMinimumWidth(4, 250)
i = 0
for info in self.myInfos:
info.myShown = self.matchFilter(filterStr, changedOnly, info)
if not info.myShown:
info.mySelected.setChecked(False)
layout = shown if info.myShown else hidden
layout.addWidget(info.mySelected, i, 0)
layout.addWidget(info.myNameLabel, i, 1)
if info.isAlpha():
layout.addWidget(info.myAlphaValue, i, 2)
layout.addWidget(info.myOrigAlphaValue, i, 3)
else:
layout.addWidget(info.myColorValue, i, 2)
layout.addWidget(info.myOrigColorValue, i, 3)
layout.addWidget(info.myCommentText, i, 4)
i = i + 1
shownWidget.setLayout(shown)
hiddenWidget.setLayout(hidden)
self.myScroller.setWidget(shownWidget)
self.myHidden = hiddenWidget
self.myContainer = shownWidget;
def matchFilter(self, filterStr, changedOnly, info):
# First thing to chec is if he value is changed
if changedOnly and info.myValues == info.myOrigValues:
return False
# Empty string matches anything
if filterStr is None or filterStr == "":
return True
# With a string, look for each word individually.
words = filterStr.split()
for word in words:
if info.myName.lower().find(word.lower()) != -1 or \
info.myComment.lower().find(word.lower()) != -1:
return True
return False
def doSchemeChanged(self, menu_index):
if self.myChanged:
if hou.displayMessage("You have unsaved changes.",
button = ("Save", "Discard")) == 0:
self.doSave()
self.doLoad()
def doClearSelection(self):
for info in self.myInfos:
info.mySelected.setChecked(False)
def doSave(self):
colorFilePath = hou.findFile(self.mySchemeMenu.itemData(self.mySchemeMenu.currentIndex()))
try:
colorFile = open(colorFilePath, "w")
except IOError:
colorFilePath = hou.homeHoudiniDirectory() + "/" + \
self.mySchemeMenu.itemData(self.mySchemeMenu.currentIndex())
try:
os.mkdir(colorFilePath[0:colorFilePath.rfind("/")])
except OSError:
pass
colorFile = open(colorFilePath, "w")
for info in self.myInfos:
colorFile.write(str(info))
colorFile.write("\n")
colorFile.close()
hou.ui.reloadViewportColorSchemes()
self.myChanged = False
def doLoad(self):
# Read the scene colors file.
colorFilePath = hou.findFile(self.mySchemeMenu.itemData(self.mySchemeMenu.currentIndex()))
colorFile = open(colorFilePath)
colorLines = colorFile.readlines()
# Strip out empty lines and leading and trailing spaces.
for i in reversed(range(0, len(colorLines))):
colorLines[i] = colorLines[i].strip()
if len(colorLines[i]) == 0:
colorLines.pop(i)
# Put the lines in alphabetical order by color name.
colorLines.sort()
# Convert the lines into a list of ColorInfo structures.
self.myInfos = []
for i in range(0, len(colorLines)):
(rest, comment) = colorLines[i].split("#", 1)
if len(rest) > 0:
comment = comment.strip()
(name, value) = rest.split(":", 1)
name = name.strip()
value = value.strip()
if value.startswith("ALPHA"):
values = [float(value.split()[1])]
elif value.startswith("@"):
values = value[1:len(value)]
else:
values = value.split()
values = [float(values[0]), float(values[1]), float(values[2])]
self.myInfos.append(ColorInfo(name, values, comment))
# Build Qt widgets for displaying and editing the color information.
frameStyle = QtWidgets.QFrame.Sunken | QtWidgets.QFrame.Panel
for info in self.myInfos:
info.mySelected = QtWidgets.QCheckBox()
info.myNameLabel = QtWidgets.QLabel()
info.myNameLabel.setText(info.myName)
info.myNameLabel.setFrameStyle(frameStyle)
if info.isAlpha():
info.myAlphaValue = QtWidgets.QLineEdit()
info.myAlphaValue.setText(info.getValueStr())
info.myAlphaValue.textEdited.connect(info.setAlpha)
info.myAlphaValue.editingFinished.connect(info.doneAlpha)
info.myOrigAlphaValue = QtWidgets.QLabel()
info.myOrigAlphaValue.setText(info.getValueStr())
else:
info.myColorValue = QtWidgets.QPushButton(info.getValueStr())
info.myColorValue.setStyleSheet(info.getColorStyleStr())
info.myColorValue.clicked.connect(info.setColor)
info.myOrigColorValue = QtWidgets.QLabel()
info.myOrigColorValue.setStyleSheet(info.getColorStyleStr())
info.myOrigColorValue.setAlignment(QtCore.Qt.AlignCenter)
info.myOrigColorValue.setText(info.getValueStr())
info.myCommentText = QtWidgets.QLineEdit()
info.myCommentText.setText(info.myComment)
info.myCommentText.textChanged.connect(info.setComment)
self.fillColorList()
self.myChanged = False
def onCreateInterface():
# Create the dialog to display and edit the color information.
root = Dialog()
return root
]]></script>
</interface>
</pythonPanelDocument>