diff --git a/.gitignore b/.gitignore
index 1c0384c..c938ddb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
#General ------------------------------------------------------------
-**.idea*
+**.idea/*
**.experiments*
#Golang -------------------------------------------------------------
@@ -49,13 +49,13 @@ share/python-wheels/
*.egg
MANIFEST
*.db
-python2.7libs/*
-!python2.7libs/searcher/
-python2.7libs/searcher/.history
+python*.7libs/*
+!python*.7libs/searcher/
+python*.7libs/searcher/.history
**.history*
-python2.7libs/searcher/go/houdini
-python2.7libs/searcher/db
-python2.7libs/searcher/_conversion
+python*.7libs/searcher/go/houdini
+python*.7libs/searcher/db
+python*.7libs/searcher/_conversion
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
@@ -158,3 +158,5 @@ dmypy.json
.pyre/
venv1/*
.DS_Store
+
+.idea/
diff --git a/.idea/Searcher.iml b/.idea/Searcher.iml
deleted file mode 100644
index e5da05c..0000000
--- a/.idea/Searcher.iml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index e6361d2..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index e2f46d8..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 04c43ba..804e4a0 100644
--- a/README.md
+++ b/README.md
@@ -13,17 +13,17 @@ Thanks for checking out Searcher. Below are the instructions to get you up and r
## Help Docs
https://help.instance.id/searcher/
-## Note for Houdini 18.5
-SideFX has only included SQLite v 3.31.0 with H18.5 and their support has told me they have no plans to upgrade it to 3.33.0 (which has FTS5 enabled (Full-Text Search), which is needed by Searcher). Because of this, an extra step is required to install/use Searcher with Houdini 18.5 until/unless they decide to include SQLite 3.33.0 instead of 3.31.0.
+## Note for Houdini 18.5+
+SideFX has only included SQLite v 3.31.0 with H18.5 and their support has told me they have no plans to upgrade it to 3.33.0 (which has FTS5 enabled (Full-Text Search), which is needed by Searcher). Because of this, an extra step is required to install/use Searcher with Houdini 18.5+ until/unless they decide to include SQLite 3.33.0 instead of 3.31.0.
Download:
Windows x64: [SQLite v3.33.0](https://www.sqlite.org/2020/sqlite-dll-win64-x64-3330000.zip)
- Extract the downloaded sqlite-dll-win64-x64-3330000.zip file, then in another window browse to your Houdini installation directory: aka `$HFS/bin`.
- By default this is located at: `C:\Program Files\SideFX\Houdini18.5.351\bin`
+ By default this is located at: `C:\Program Files\SideFX\Houdini19.0.xxx\bin`
- In the Houdini $HFS/bin folder, locate the `sqlite3.dll` file and either make a backup copy to save elsewhere (just in case), or simply rename it to `sqlite3.dll.bak`
- From the extracted sqlite-dll-win64-x64-3330000.zip, locate the new `sqlite3.dll` then copy and paste it into the `$HFS/bin` folder.
-From my testing, that was all that needed to be done, as Searcher worked for me at that point, but Houdini support mentioned that the sqlite3.dll located in the `$HFS/python27/dlls` folder should be replaced as well. Just make sure to back it up/rename it as well. Always better to be safe than sorry!
+From my testing, that was all that needed to be done, as Searcher worked for me at that point, but Houdini support mentioned that the sqlite3.dll located in the `$HFS/python27/dlls` or `$HFS/python37/dlls` folder should be replaced as well. Just make sure to back it up/rename it as well. Always better to be safe than sorry!
The process is the same for Unix OS's, you just have to go to the `$HFS/bin` folder that cooresponds to your particular OS and instead of looking for sqlite3.dll, the file will just be `sqlite3`. I would love to test it, but Houdini 18.5 on Linux crashes when I try to open it on both my laptop and VM on my desktop.
diff --git a/build.ps1 b/build.ps1
index 2afc684..5f64ba2 100644
--- a/build.ps1
+++ b/build.ps1
@@ -1,3 +1,5 @@
+#!/usr/bin/env pwsh
+
# .\build.ps1 -Zip -Version v0.1.0
Param (
[Parameter()]
@@ -8,60 +10,84 @@ Param (
if ($Version) {
Write-Host "Building $Version..."
} else {
- Write-Host "Just updating files..."
+ Write-Host 'Just updating files...'
}
-$date = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
-$exclude = "--exclude-from=E:\GitHub\Searcher\build\exclude.excl"
-$include = "--include-from=E:\GitHub\Searcher\build\include.incl"
-$config = "--config=C:/Users/mosthated/.backup/rclone.conf"
-
-$cmd = "C:\files\rclone\rclone.exe"
+$date = Get-Date -Format 'yyyy-MM-dd_HH-mm-ss'
+$exclude = '--exclude-from=build/exclude.excl'
+$include = '--include-from=build/include.incl'
+$config = '--config=C:/Users/mosthated/.backup/rclone.conf'
+$cmd = ''
+$source1 = ''
+$destination1 = ''
-$source1 = "E:\GitHub\Searcher\"
-$destination1 = "E:\Searcher"
-$log1 = "--log-file=C:\files\rclone\logs\searcher_$date.log"
+if ($IsWindows) {
+ $cmd = 'C:\files\rclone\rclone.exe'
+ $source1 = 'E:\GitHub\Searcher\'
+ $destination1 = 'E:\Searcher'
+ $log1 = "--log-file=C:\files\rclone\logs\Searcher_Build_$date.log"
+} elseif ($IsLinux) {
+ $cmd = 'rclone'
+ $source1 = '/mnt/x/GitHub/instance-id/1_Projects/Searcher'
+ $destination1 = '/mnt/x/_dev/Searcher'
+ $log1 = "--log-file=$HOME/.backup/logs/Searcher_Build_$date.log"
+}
-&$cmd sync $source1 $destination1 $log1 $exclude $config --log-level NOTICE --progress --no-update-modtime --transfers=4 --checkers=8 --contimeout=60s --timeout=300s --retries=3 --low-level-retries=10 -L --stats=1s --stats-file-name-length=0 -P --ignore-case --fast-list --drive-chunk-size=64M
+&$cmd sync $source1 $destination1 $log1 $exclude $config --log-level NOTICE `
+ --progress `
+ --no-update-modtime `
+ --transfers=4 `
+ --checkers=8 `
+ --contimeout=60s `
+ --timeout=300s `
+ --retries=3 `
+ --low-level-retries=10 `
+ -L `
+ --stats=1s `
+ --stats-file-name-length=0 `
+ -P `
+ --ignore-case `
+ --fast-list `
+ --drive-chunk-size=64M
if ($Version) {
Write-Host "Building $Version..."
- $searcher = "Searcher"
- $destination2 = $searcher, $Version -join "_"
+ $searcher = 'Searcher'
+ $destination2 = $searcher, $Version -join '_'
$folderVer = "$destination1\$destination2"
-
+
Write-Host "Destination2: $destination2"
-
- if([System.IO.File]::Exists($folderVer)){
+
+ if ([System.IO.File]::Exists($folderVer)) {
Get-ChildItem $folderVer -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse
}
- New-Item "$folderVer\$searcher" -Type Directory
+ New-Item "$folderVer\$searcher" -Type Directory
Move-Item -Path $destination1\packages -Destination $folderVer\packages
Move-Item -Path $destination1\README.md -Destination $folderVer\README.md
Move-Item -Path $destination1\Searcher_install_instructions.url -Destination $folderVer\Searcher_install_instructions.url
-
+
Move-Item -Path $destination1\dso -Destination $folderVer\$searcher\dso
Move-Item -Path $destination1\help -Destination $folderVer\$searcher\help
Move-Item -Path $destination1\python2.7libs -Destination $folderVer\$searcher\python2.7libs
+ Move-Item -Path $destination1\python3.7libs -Destination $folderVer\$searcher\python3.7libs
Move-Item -Path $destination1\toolbar -Destination $folderVer\$searcher\toolbar
-
+
$listfiles = Get-ChildItem $folderVer -Recurse -File -Include '*.md', '*.txt'
$old = '{#version}'
- foreach($file in $listfiles) {
- (Get-Content $file) -Replace ($old,$Version) | Set-Content $file
+ foreach ($file in $listfiles) {
+ (Get-Content $file) -Replace ($old, $Version) | Set-Content $file
}
-
+
$FileName = "$destination1\$destination2.zip"
if (Test-Path $FileName) {
Write-Host "Removing $FileName and recreating"
Remove-Item $FileName
}
- if($Zip)
- {
+ if ($Zip) {
Compress-Archive -Path $folderVer -DestinationPath $FileName
}
- Write-Host "Update Complete"
+ Write-Host 'Update Complete'
} else {
- Write-Host "Update Complete"
+ Write-Host 'Update Complete'
}
\ No newline at end of file
diff --git a/python2.7libs/searcher/__init__.py b/python2.7libs/searcher/__init__.py
index c688ca8..8f3e41d 100644
--- a/python2.7libs/searcher/__init__.py
+++ b/python2.7libs/searcher/__init__.py
@@ -2,3 +2,5 @@
__author__ = "instance.id"
__copyright__ = "2020 All rights reserved. See LICENSE for more details."
__status__ = "Prototype"
+
+from . searcher import *
diff --git a/python2.7libs/searcher/bugreport.py b/python2.7libs/searcher/bugreport.py
index 5aa1ace..04fe76f 100644
--- a/python2.7libs/searcher/bugreport.py
+++ b/python2.7libs/searcher/bugreport.py
@@ -3,7 +3,6 @@
import os
import hou
-
hver = 0
if os.environ["HFS"] != "":
ver = os.environ["HFS"]
diff --git a/python2.7libs/searcher/nodegraphhooks.py b/python2.7libs/searcher/nodegraphhooks.py
index c6a0a9c..af011c3 100644
--- a/python2.7libs/searcher/nodegraphhooks.py
+++ b/python2.7libs/searcher/nodegraphhooks.py
@@ -5,13 +5,9 @@
sys.dont_write_bytecode = True
import hou
-
from PySide2 import QtWidgets
-
from houdini_markingmenu import markingmenu as mm
-
from canvaseventtypes import *
-
import nodegraphbase as base
sys.path.insert(0, os.path.join(hou.getenv('HOUDINI_USER_PREF_DIR'),
diff --git a/python3.7libs/searcher/.extra/Untitled.json b/python3.7libs/searcher/.extra/Untitled.json
new file mode 100644
index 0000000..887b166
--- /dev/null
+++ b/python3.7libs/searcher/.extra/Untitled.json
@@ -0,0 +1,14 @@
+{
+ "env": [
+ {
+ "MODELER": "C:/Users/PATH/TO/modeler/"
+ },
+ {
+ "HOUDINI_PATH" :
+ {
+ "value": "$MODELER/",
+ "method": "append"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/python3.7libs/searcher/.extra/__init__.py b/python3.7libs/searcher/.extra/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/python3.7libs/searcher/.extra/bug.html b/python3.7libs/searcher/.extra/bug.html
new file mode 100644
index 0000000..33c26fa
--- /dev/null
+++ b/python3.7libs/searcher/.extra/bug.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+ Demo
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/python3.7libs/searcher/.extra/bugsubmit.html b/python3.7libs/searcher/.extra/bugsubmit.html
new file mode 100644
index 0000000..d01f5d7
--- /dev/null
+++ b/python3.7libs/searcher/.extra/bugsubmit.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+ ISSUE_TITLE
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/python3.7libs/searcher/.extra/scratch b/python3.7libs/searcher/.extra/scratch
new file mode 100644
index 0000000..f1527a4
--- /dev/null
+++ b/python3.7libs/searcher/.extra/scratch
@@ -0,0 +1,324 @@
+# C:\Users\mosthated\AppData\Roaming\Python\Python37\Scripts\pyuic5.exe .\SearcherSettings.ui -o .\SearcherSettings.py
+
+ # panetab = None
+ # for pane in hou.ui.floatingPaneTabs():
+ # if pane.type() == hou.paneTabType.PythonPanel:
+ # print(pane.activeInterface().name())
+ # if pane.activeInterface().name() == 'SceneGraphDetailsPanel':
+ # panetab = pane
+ # break
+
+ # ret = []
+ # for t in tabs:
+ # if t.type() == hou.paneTabType.PythonPanel:
+ # if t.activeInterface() == pytype:
+ # t.pane().setIsSplitMaximized(False)
+ # ret.append(t)
+
+
+# else:
+# os.environ['QT_API'] = 'pyside2'
+# from PySide import QtUiTools
+# from qtpy import QtGui
+# from qtpy import QtCore
+# from qtpy import QtWidgets
+# endregion
+
+
+
+ # ------------------------------------- checkforchanges
+ def checkforchanges(self):
+ for i in range(len(util.SETTINGS_KEYS)):
+ if util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "bool":
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Get attribute: ", getattr(self, util.SETTINGS_KEYS[i]))
+ print("Get settings: ", bc(self.currentsettings[util.SETTINGS_KEYS[i]]))
+ if getattr(self, util.SETTINGS_KEYS[i]).isChecked() != bc(self.currentsettings[util.SETTINGS_KEYS[i]]):
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("{} value {}".format(util.SETTINGS_KEYS[i], getattr(self, util.SETTINGS_KEYS[i]).isChecked()))
+ print("{} value {}".format(util.SETTINGS_KEYS[i], bc(self.currentsettings[util.SETTINGS_KEYS[i]])))
+ return True
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "text":
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Get attribute: ", getattr(self, util.SETTINGS_KEYS[i]))
+ print("Get settings: ", self.currentsettings[util.SETTINGS_KEYS[i]])
+ if getattr(self, util.SETTINGS_KEYS[i]).text() != self.currentsettings[util.SETTINGS_KEYS[i]]:
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("{} value {}".format(util.SETTINGS_KEYS[i], getattr(self, util.SETTINGS_KEYS[i]).text()))
+ print("{} value {}".format(util.SETTINGS_KEYS[i], self.currentsettings[util.SETTINGS_KEYS[i]]))
+ return True
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "intval":
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Get attribute: ", getattr(self, util.SETTINGS_KEYS[i]))
+ print("Get settings: ", self.currentsettings[util.SETTINGS_KEYS[i]])
+ if getattr(self, util.SETTINGS_KEYS[i]).value() != self.currentsettings[util.SETTINGS_KEYS[i]]:
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("{} value {}".format(util.SETTINGS_KEYS[i], getattr(self, util.SETTINGS_KEYS[i]).value()))
+ print("{} value {}".format(util.SETTINGS_KEYS[i], int(self.currentsettings[util.SETTINGS_KEYS[i]])))
+ return True
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "cbx":
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Get attribute: ", getattr(self, util.SETTINGS_KEYS[i]))
+ print("Get settings: ", self.currentsettings[util.SETTINGS_KEYS[i]])
+ if getattr(self, util.SETTINGS_KEYS[i]).currentText() != self.currentsettings[util.SETTINGS_KEYS[i]]:
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("{} value {}".format(util.SETTINGS_KEYS[i], getattr(self, util.SETTINGS_KEYS[i]).currentText()))
+ print("{} value {}".format(util.SETTINGS_KEYS[i], str(self.currentsettings[util.SETTINGS_KEYS[i]])))
+ return True
+ return False
+
+
+ def bug_cb(self, toggled):
+ if toggled == True and not self.bugreport.isVisible():
+ if self.animatedsettings.isChecked():
+ pos = self.bugreportbtn.mapToGlobal(
+ QtCore.QPoint( -43, 34))
+ else:
+ pos = self.bugreportbtn.mapToGlobal(
+ QtCore.QPoint( -45, 35))
+ self.bugreport.setGeometry(
+ pos.x(),
+ pos.y(),
+ self.bugreport.width(),
+ self.bugreport.height()
+ )
+ self.bugreport.show()
+ else:
+ self.bugreport.close()
+
+ def theme_cb(self, toggled):
+ if toggled == True and not self.theme.isVisible():
+ if self.animatedsettings.isChecked():
+ pos = self.themebtn.mapToGlobal(
+ QtCore.QPoint( -77, 34))
+ else:
+ pos = self.themebtn.mapToGlobal(
+ QtCore.QPoint( -79, 35))
+ self.theme.setGeometry(
+ pos.x(),
+ pos.y(),
+ self.theme.width(),
+ self.theme.height()
+ )
+ self.theme.show()
+ else:
+ self.theme.close()
+
+ def about_cb(self):
+ self.aboutui = about.About(self.parentwindow)
+ self.aboutui.setAttribute(QtCore.Qt.WA_StyledBackground, True)
+ self.aboutui.setWindowFlags(
+ QtCore.Qt.Popup |
+ QtCore.Qt.WindowStaysOnTopHint |
+ QtCore.Qt.NoDropShadowWindowHint |
+ QtCore.Qt.WindowStaysOnTopHint
+ )
+ self.aboutui.setParent(self.parentwindow)
+ self.aboutui.move(self.pos().x() - 175, self.pos().y())
+ self.aboutui.show()
+
+
+# ------------------------------------------------------- CUSTOM FONT LOADER
+style script ----------
+def getfontdb():
+ return getattr(hou.session, "FONTDB", None)
+
+def getfont(font, size = -1, weight = -1):
+ if font in getfontdb().families():
+ fontstr = ""
+ fontstr += ("Using %s" % font)
+ if size >= 0:
+ fontstr += (" : Size %s" % size)
+ if weight >= 0:
+ fontstr += (" : Weight %s" % weight)
+ else:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(("%s not available" % font), severity=hou.severityType.Message)
+ return QtGui.QFont()
+ else:
+ print(("%s not available" % font))
+ return QtGui.QFont()
+
+ return QtGui.QFont(font, size, weight)
+-------
+
+ # CUSTOM FONT LOADER
+ self.infolbl = self.sui.info_lbl
+ self.infolbl_font = style.getfont("JetBrains Mono", 8)
+ self.infolbl_font.setWeight(40)
+ self.infolbl_font.setLetterSpacing(QtGui.QFont.AbsoluteSpacing, -1)
+ self.infolbl_font.setWordSpacing(-2)
+ # self.infolbl.setFont(self.infolbl_font)
+
+ self.treetotal_lbl = self.sui.treetotal_lbl
+ self.treetotal_lbl_font = style.getfont("JetBrains Mono", 8)
+ self.treetotal_lbl_font.setWeight(40)
+ self.treetotal_lbl_font.setLetterSpacing(QtGui.QFont.AbsoluteSpacing, -1)
+ self.treetotal_lbl_font.setWordSpacing(0)
+ # self.treetotal_lbl.setFont(self.treetotal_lbl_font)
+ # self.treetotal_lbl.setMinimumSize(QtCore.QSize(50, 0))
+
+ # ------------------------------------------------------- Spacing
+ # tnum = str(treeitemsnum)
+ # goalnum = 5
+ # if len(tnum) == 3:
+ # itmvald = tnum.rjust((goalnum + 2) - count_chars(str(treeitemsnum)), " ")
+ # else:
+ # itmvald = tnum.rjust((goalnum) - count_chars(str(treeitemsnum)), " ")
+ # itm = itmvald.replace(" ", " ")
+
+ # ------------------------------------------------------- Auto - Add font
+ jbfont = getattr(hou.session, "FONTDB", None)
+ if not getattr(hou.session, "FONTDB", None):
+ fontlocation = os.path.join(script_path, "fonts")
+ jbfontfolder = "JetBrainsMono-1.0.0"
+ f = []
+ for (dirpath, dirnames, filenames) in os.walk(os.path.join(fontlocation, jbfontfolder)):
+ f.extend(filenames)
+ break
+ if f:
+ for font in f:
+ fontdb = QtGui.QFontDatabase()
+ fontdb.addApplicationFont(os.path.join(fontlocation, jbfontfolder, font))
+ print("Added %s" % font)
+ hou.session.FONTDB = fontdb
+
+
+
+ # # ----------------------------------------- chooseColor
+ # # NOTE chooseColor ------------------------------------
+ # def chooseColor(self):
+ # sender = self.sender()
+ # name = sender.objectName()
+ # colorfield = getattr(self.ui, name)
+
+ # qcolor = QtGui.QColor()
+ # qcolor.setNamedColor(colorfield.text())
+
+ # color = hou.Color()
+ # color.setRGB((
+ # qcolor.redF(),
+ # qcolor.greenF(),
+ # qcolor.blueF())
+ # )
+
+ # result = hou.ui.selectColor(initial_color = color)
+ # allWidgets = QtWidgets.QApplication.allWidgets()
+ # for w in allWidgets:
+ # if "Select Color" in w.windowTitle():
+ # pos = self.parent.mapToGlobal(
+ # QtCore.QPoint(-self.parent.width(), -self.parent.height()))
+ # w.setGeometry(
+ # pos.x(),
+ # pos.y(),
+ # w.width(),
+ # w.height()
+ # )
+ # # w.move(self.parent.width()200, 100)
+
+ # if result:
+ # rgb = result.rgb()
+ # newcolor = QtGui.QColor(
+ # rgb[0]*255,
+ # rgb[1]*255,
+ # rgb[2]*255
+ # )
+
+ # if newcolor.isValid():
+ # colorfield.setText(newcolor.name())
+ # sender.setStyleSheet("background-color:" + colorfield.text())
+
+
+
+
+
+ # ----------------------------------------- chooseColor
+ # NOTE chooseColor ------------------------------------
+ def chooseColor(self):
+ sender = self.sender()
+
+ self.name = sender.objectName()
+ self.colorfield[self.name] = (getattr(self.ui, self.name), sender)
+
+ qcolor = QtGui.QColor()
+ qcolor.setNamedColor(self.colorfield[self.name][0].text())
+
+ # color = hou.Color()
+ # color = QtGui.QColor()
+ # color.setRGB((
+ # qcolor.redF(),
+ # qcolor.greenF(),
+ # qcolor.blueF())
+ # )
+
+ # hou.ui.openColorEditor(self.colorchange_cb, include_alpha=False, initial_color = color)
+ # hd.executeDeferred(self._opencoloreditor, color)
+ colord = QtWidgets.QColorDialog(self)
+ colord.setModal(False)
+ pos = self.parentwindow.mapToGlobal(
+ QtCore.QPoint(self.parentwindow.width(), self.parentwindow.height()))
+ colord.move(
+ pos.x() + 300,
+ pos.y(),
+ )
+ colord.getColor(
+ initial=qcolor,
+ parent=self,
+ options=QtWidgets.QColorDialog.DontUseNativeDialog
+ )
+ # colord.setWindowFlags(
+ # QtCore.Qt.CustomizeWindowHint
+ # # | QtCore.Qt.WindowStaysOnTopHint
+ # # | QtCore.Qt.X11BypassWindowManagerHint
+ # )
+ # self.activateWindow()
+ # self._opencoloreditor(color)
+
+
+
+ # NOTE PANES ---------------------------
+ # hou.playbar.moveToBottom()
+
+ # for ii in i:
+ # print(ii)
+ # print("Under mouse: ", i.windowTitle())
+ print("--------------------------------------")
+ current_desktop = hou.ui.curDesktop()
+ # allpanes = current_desktop.panes()
+ # if allpanes:
+ # try:
+ # self.processdesktop("current_desktop.panes()", allpanes)
+ # except:
+ # pass
+ # panetabsd = current_desktop.paneTabs()
+ # panetabs = hou.ui.paneTabs()
+ # if panetabs:
+ # try:
+ # self.processdesktop("current_desktop.paneTabs()", panetabsd)
+ # self.processdesktop("hou.ui.paneTabs()", panetabs) # ------ Good one
+ # except:
+ # pass
+ # floating = hou.ui.floatingPanels()
+ # if floating:
+ # try:
+ # self.processdesktop("current_desktop.floatingPanels()", floating)
+ # print(floating.name())
+ # except:
+ # pass
+ # desktoppane = current_desktop.paneUnderCursor()
+ # if desktoppane:
+ # try:
+ # self.processdesktop("current_desktop.paneUnderCursor()", desktoppane)
+ # except:
+ # pass
+ # desktoptab = current_desktop.paneTabUnderCursor()
+ # if desktoptab:
+ # try:
+ # self.processdesktop("current_desktop.paneTabUnderCursor()", desktoptab)
+ # except:
+ # pass
+
+ allWidgets = QtWidgets.QApplication.allWidgets()
+ for w in allWidgets:
+ if "playbar" in w.windowTitle():
+ print("Is Playbar? ", w.windowTitle(), w)
\ No newline at end of file
diff --git a/python3.7libs/searcher/.extra/session.py b/python3.7libs/searcher/.extra/session.py
new file mode 100644
index 0000000..949cca5
--- /dev/null
+++ b/python3.7libs/searcher/.extra/session.py
@@ -0,0 +1,111 @@
+
+
+import os
+import time
+
+# attempt to import hou module. if it fails, not in a houdini session.
+try:
+ import hou
+except ImportError:
+ HOU_IMPORTED = False
+else:
+ HOU_IMPORTED = True
+
+# -----------------------------------------------------------------------------
+# attempt to import hou ui module. if it fails, not in the UI
+try:
+ from PySide import QtCore, QtGui
+except:
+ HOU_UI_IMPORTED = False
+else:
+ HOU_UI_IMPORTED = True
+
+from dpa.app.session import RemoteMixin, Session, SessionRegistry, SessionError
+
+# -----------------------------------------------------------------------------
+class HoudiniSession(RemoteMixin, Session):
+
+ app_name = 'houdini'
+
+ # XXX should come from config
+ SERVER_EXECUTABLE = "/home/jtomlin/dev/dpa-pipe/bin/dpa_houdini_server"
+
+ # -------------------------------------------------------------------------
+ @classmethod
+ def current(cls):
+ if not HOU_IMPORTED:
+ return None
+ return cls()
+
+ # -------------------------------------------------------------------------
+ def __init__(self, filepath=None, remote=False):
+
+ super(HoudiniSession, self).__init__(remote=remote)
+
+ self._hou = self.init_module('hou')
+
+ if filepath:
+ self.open_file(filepath)
+
+ # -------------------------------------------------------------------------
+ def close(self):
+ if self.remote_connection:
+ self.shutdown()
+ else:
+ self.hou.hipFile.clear()
+
+ # -------------------------------------------------------------------------
+ def open_file(self, filepath):
+
+ if not os.path.exists(filepath):
+ raise SessionError(
+ "Can not open '{f}'. File does not exist.".format(f=filepath))
+
+ try:
+ self.hou.hipFile.load(filepath)
+ except RuntimeError as e:
+ raise SessionError(str(e))
+
+ # -------------------------------------------------------------------------
+ def save(self, filepath=None, overwrite=False):
+
+ if filepath and os.path.exists(filepath) and not overwrite:
+ raise SessionError(
+ "Can not save '{f}'. File exists.".format(f=filepath))
+
+ self.hou.hipFile.save(file_name=filepath)
+
+ # -------------------------------------------------------------------------
+ @property
+ def hou(self):
+ return self._hou
+
+ # -------------------------------------------------------------------------
+ @property
+ def in_session(self):
+ """Returns True if inside a current app session."""
+ return HOU_IMPORTED or self.remote_connection
+
+ # -------------------------------------------------------------------------
+ @property
+ def main_window(self):
+
+ if not HOU_UI_IMPORTED:
+ return None
+
+ return QtGui.QApplication.activeWindow()
+
+ # -------------------------------------------------------------------------
+ @property
+ def name(self):
+ """Returns the name of the application."""
+ return "houdini"
+
+ # -------------------------------------------------------------------------
+ @property
+ def server_executable(self):
+ return self.__class__.SERVER_EXECUTABLE
+
+
+# -----------------------------------------------------------------------------
+SessionRegistry().register(HoudiniSession)
diff --git a/python3.7libs/searcher/.extra/shelf.py b/python3.7libs/searcher/.extra/shelf.py
new file mode 100644
index 0000000..e5a4406
--- /dev/null
+++ b/python3.7libs/searcher/.extra/shelf.py
@@ -0,0 +1,55 @@
+import hou
+
+
+def create_shelf_current_desktop(shelf_obj):
+ # Add the shelf to the current desktop.
+ desktop = hou.ui.curDesktop()
+ dock = desktop.shelfDock()
+ shelfSets = dock.shelfSets()
+ shelfSet = shelfSets[0]
+ if shelf_obj not in shelfSet.shelves():
+ shelfSet.setShelves(shelfSet.shelves() + (shelf_obj, ))
+ return shelf_obj
+
+def is_shelf_created(shelf_name, shelf_tab="shelf_set_1"):
+ try:
+ shelf_set = hou.shelves.shelfSets()[shelf_tab]
+ except KeyError:
+ print("Key not Found! for shelf.")
+ return False
+ return shelf_name in shelf_set.shelves()
+
+def create_shelf_under_tab(shelf_name, shelf_tab="shelf_set_1"):
+ shelves = hou.shelves.shelves()
+ _shelf = shelves.get(shelf_name)
+ if not _shelf:
+ _shelf = hou.shelves.newShelf(name=shelf_name, label=shelf_name)
+ try:
+ shelf_set = hou.shelves.shelfSets()[shelf_tab]
+ except KeyError:
+ print("Key not Found! for shelf.")
+ return 0
+ shelf_set.setShelves(shelf_set.shelves() + (_shelf, ))
+ return _shelf
+
+def create_tool_under_shelf(shelf_obj, tool_name):
+ # Clear the existing tools
+ shelf_obj.setTools(())
+
+ tools = hou.shelves.tools()
+ tool = tools.get(tool_name)
+ if not tool:
+ tool = hou.shelves.newTool(name=tool_name)
+
+ # Set up the tool.
+ tool.setLabel(tool_name)
+ # tool.setScript('from houtools.shelf import dispatch; dispatch(%r)' % spec['entrypoint'])
+ shelf_obj.setTools(shelf_obj.tools() + (tool, ))
+
+def run_shelf_creation():
+ print("Trying to create the shelf.")
+ if is_shelf_created("BpCustom"):
+ print("Not running shelf creation as its present.")
+ return 1
+ shelf_obj = create_shelf_under_tab("BpCustom")
+ create_tool_under_shelf(shelf_obj, "BpTool1")
\ No newline at end of file
diff --git a/python3.7libs/searcher/.vscode/settings.json b/python3.7libs/searcher/.vscode/settings.json
new file mode 100644
index 0000000..e657cfe
--- /dev/null
+++ b/python3.7libs/searcher/.vscode/settings.json
@@ -0,0 +1,12 @@
+{
+ "python.pythonPath": "C:\\Python27\\python.exe",
+ "python.formatting.provider": "autopep8",
+ "python.linting.pylintEnabled": false,
+ "python.linting.flake8Enabled": true,
+ "python.linting.enabled": true,
+ "cSpell.words": [
+ "gocommandtext",
+ "updatetmphk",
+ "updatetmphotkey"
+ ]
+}
\ No newline at end of file
diff --git a/python3.7libs/searcher/HelpButton.py b/python3.7libs/searcher/HelpButton.py
new file mode 100644
index 0000000..0e8151a
--- /dev/null
+++ b/python3.7libs/searcher/HelpButton.py
@@ -0,0 +1,61 @@
+from __future__ import print_function
+from __future__ import absolute_import
+from searcher import util
+
+import hou
+import os
+
+hver = 0
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.')+1:])
+ from hutil.Qt import QtCore
+ from hutil.Qt import QtWidgets
+else:
+ from qtpy import QtCore
+ from qtpy import QtWidgets
+
+
+# ---------------------------------------------------- Help
+# NOTE Help -----------------------------------------------
+class HelpButton(QtWidgets.QToolButton):
+ """Generic Help button."""
+
+ def __init__(self, name, tooltip, size, searcher, parent=None):
+ super(HelpButton, self).__init__(parent=parent)
+
+ self.parentWindow = searcher
+ self._name = name
+ self.setToolTip(tooltip)
+ self.clicked.connect(self.display_help)
+ help_button_size = hou.ui.scaledSize(size)
+ self.setProperty("flat", True)
+ self.setIcon(hou.qt.createIcon(util.get_path(["images", "help1.png"])))
+ self.setIconSize(QtCore.QSize(
+ help_button_size,
+ help_button_size
+ ))
+
+ def display_help(self):
+ """Display help panel."""
+ # Look for an existing, float help browser.
+ for pane_tab in hou.ui.paneTabs():
+ if isinstance(pane_tab, hou.HelpBrowser):
+ if pane_tab.isFloating():
+ browser = pane_tab
+ break
+
+ # Didn't find one, so create a new floating browser.
+ else:
+ desktop = hou.ui.curDesktop()
+
+ posx = self.parentWindow.pos().x()
+ posy = self.parentWindow.pos().y()
+ sizew = self.parentWindow.width()
+ sizeh = self.parentWindow.height()
+
+ browser = desktop.createFloatingPaneTab(
+ hou.paneTabType.HelpBrowser, position=(posx + sizew / 8, posy - (sizeh / 2)), size=(805, 650))
+ self.parentWindow.close()
+
+ browser.displayHelpPath("/searcher/{}".format(self._name))
diff --git a/python3.7libs/searcher/__init__.py b/python3.7libs/searcher/__init__.py
new file mode 100644
index 0000000..66960fc
--- /dev/null
+++ b/python3.7libs/searcher/__init__.py
@@ -0,0 +1,7 @@
+__package__ = "searcher"
+__author__ = "instance.id"
+__copyright__ = "2020 All rights reserved. See LICENSE for more details."
+__status__ = "Prototype"
+
+from . searcher import *
+# from settings_data import *
\ No newline at end of file
diff --git a/python3.7libs/searcher/about.py b/python3.7libs/searcher/about.py
new file mode 100644
index 0000000..50aff6d
--- /dev/null
+++ b/python3.7libs/searcher/about.py
@@ -0,0 +1,115 @@
+from __future__ import absolute_import
+from searcher import about_ui
+from searcher import util
+import os
+import hou
+
+hver = 0
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.')+1:])
+ from hutil.Qt import QtGui
+ from hutil.Qt import QtCore
+ from hutil.Qt import QtWidgets
+else:
+ from qtpy import QtGui
+ from qtpy import QtCore
+ from qtpy import QtWidgets
+
+scriptpath = os.path.dirname(os.path.realpath(__file__))
+
+
+# noinspection PyCallByClass,PyUnresolvedReferences
+class About(QtWidgets.QWidget):
+ """ Searcher Settings and Debug Menu"""
+
+ def __init__(self, parent=None):
+ super(About, self).__init__(parent=parent)
+ self.setParent(parent)
+ self.parentwindow = parent
+ self.ui = about_ui.Ui_About()
+ self.ui.setupUi(self)
+ self.ui.retranslateUi(self)
+
+ self.ui.web_icon.setIcon(hou.qt.createIcon(
+ util.get_path(["images", "icons", "firefox-browser-brands.svg"])))
+ self.ui.web_icon.clicked.connect(self.openWeb)
+ web_icon_size = hou.ui.scaledSize(16)
+ self.ui.web_icon.setProperty("flat", True)
+ self.ui.web_icon.setIconSize(QtCore.QSize(
+ web_icon_size,
+ web_icon_size
+ ))
+
+ self.ui.github_icon.setIcon(hou.qt.createIcon(
+ util.get_path(["images", "icons", "github-brands.svg"])))
+ self.ui.github_icon.clicked.connect(self.openGithub)
+ github_icon_size = hou.ui.scaledSize(16)
+ self.ui.github_icon.setProperty("flat", True)
+ self.ui.github_icon.setIconSize(QtCore.QSize(
+ github_icon_size,
+ github_icon_size
+ ))
+
+ self.ui.twitter_icon.setIcon(hou.qt.createIcon(
+ util.get_path(["images", "icons", "twitter-brands.svg"])))
+ self.ui.twitter_icon.clicked.connect(self.openTwitter)
+ twitter_icon_size = hou.ui.scaledSize(16)
+ self.ui.twitter_icon.setProperty("flat", True)
+ self.ui.twitter_icon.setIconSize(QtCore.QSize(
+ twitter_icon_size,
+ twitter_icon_size
+ ))
+
+ self.ui.email_icon.setIcon(hou.qt.createIcon(
+ util.get_path(["images", "icons", "at-solid.svg"])))
+ self.ui.email_icon.clicked.connect(self.openEmail)
+ email_icon_size = hou.ui.scaledSize(16)
+ self.ui.email_icon.setProperty("flat", True)
+ self.ui.email_icon.setIconSize(QtCore.QSize(
+ email_icon_size,
+ email_icon_size
+ ))
+
+ self.ui.web.mousePressEvent = self.openWeb
+ self.ui.github.mousePressEvent = self.openGithub
+ self.ui.twitter.mousePressEvent = self.openTwitter
+ self.ui.email.mousePressEvent = self.openEmail
+
+ self.installEventFilter(self)
+
+ def initmenu(self):
+ return
+
+ def openWeb(self, _):
+ weburl = '''https://instance.id/'''
+ QtGui.QDesktopServices.openUrl(QtCore.QUrl(weburl))
+ self.parentwindow.parentwindow.close()
+
+ def openGithub(self, _):
+ ghurl = '''https://github.com/instance-id/'''
+ QtGui.QDesktopServices.openUrl(QtCore.QUrl(ghurl))
+ self.parentwindow.parentwindow.close()
+
+ def openTwitter(self, _):
+ twitterurl = '''https://twitter.com/instance_id'''
+ QtGui.QDesktopServices.openUrl(QtCore.QUrl(twitterurl))
+ self.parentwindow.parentwindow.close()
+
+ def openEmail(self, _):
+ email = '''mailto:support@instance.id'''
+ QtGui.QDesktopServices.openUrl(QtCore.QUrl(email))
+ self.parentwindow.parentwindow.close()
+
+ # ------------------------------------------------------------- Events
+ # SECTION Events -----------------------------------------------------
+ def eventFilter(self, obj, event):
+ event_type = event.type()
+
+ # ---------------------------------------- Keypress
+ # NOTE Keypress -----------------------------------
+ if event_type == QtCore.QEvent.KeyPress:
+ if event.key() == QtCore.Qt.Key_Escape:
+ self.parentwindow.closeroutine()
+
+ return QtCore.QObject.eventFilter(self, obj, event)
diff --git a/python3.7libs/searcher/about_ui.py b/python3.7libs/searcher/about_ui.py
new file mode 100644
index 0000000..9263ac3
--- /dev/null
+++ b/python3.7libs/searcher/about_ui.py
@@ -0,0 +1,135 @@
+# -*- coding: utf-8 -*-
+import os
+hver = 0
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.')+1:])
+ from hutil.Qt import QtGui
+ from hutil.Qt import QtCore
+ from hutil.Qt import QtWidgets
+else:
+ from qtpy import QtGui
+ from qtpy import QtCore
+ from qtpy import QtWidgets
+
+scriptpath = os.path.dirname(os.path.realpath(__file__))
+
+
+# noinspection PyAttributeOutsideInit,DuplicatedCode,PyPep8Naming
+class Ui_About(object):
+ def setupUi(self, About):
+ About.setObjectName("About")
+ About.setWindowModality(QtCore.Qt.NonModal)
+ About.resize(185, 251)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(About.sizePolicy().hasHeightForWidth())
+ About.setSizePolicy(sizePolicy)
+ About.setMinimumSize(QtCore.QSize(100, 0))
+ About.setBaseSize(QtCore.QSize(0, 0))
+ About.setStyleSheet("")
+
+ # ------------------------------------------------- gridsetup
+ # NOTE gridsetup --------------------------------------------
+ self.gridLayout = QtWidgets.QGridLayout(About)
+ self.gridLayout.setContentsMargins(-1, -1, -1, 6)
+ self.gridLayout.setSpacing(6)
+ self.gridLayout.setObjectName("gridLayout")
+ self.verticalLayout_4 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_4.setObjectName("verticalLayout_4")
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.verticalLayout = QtWidgets.QVBoxLayout()
+ self.verticalLayout.setObjectName("verticalLayout")
+ spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.verticalLayout.addItem(spacerItem)
+
+ # ------------------------------------------------- secondrow
+ # NOTE Second Row -------------------------------------------
+ self.secondrow = QtWidgets.QHBoxLayout()
+ self.secondrow.setObjectName("secondrow")
+ self.web_icon = QtWidgets.QToolButton(About)
+ self.web_icon.setObjectName("web_icon")
+ self.web = QtWidgets.QLabel(About)
+ self.web.setObjectName("web")
+ self.secondrow.addWidget(self.web_icon)
+ self.secondrow.addWidget(self.web)
+ self.verticalLayout.addLayout(self.secondrow)
+
+ # -------------------------------------------------- thirdrow
+ # NOTE Third Row --------------------------------------------
+ self.thirdrow = QtWidgets.QHBoxLayout()
+ self.thirdrow.setObjectName("thirdrow")
+ self.github_icon = QtWidgets.QToolButton(About)
+ self.github_icon.setObjectName("github_icon")
+ self.github = QtWidgets.QLabel(About)
+ self.github.setObjectName("github")
+ self.thirdrow.addWidget(self.github_icon)
+ self.thirdrow.addWidget(self.github)
+ self.verticalLayout.addLayout(self.thirdrow)
+
+ # ------------------------------------------------- fourthrow
+ # NOTE fourthrow --------------------------------------------
+ self.fourthrow = QtWidgets.QHBoxLayout()
+ self.fourthrow.setObjectName("fourthrow")
+ self.twitter_icon = QtWidgets.QToolButton(About)
+ self.twitter_icon.setObjectName("twitter_icon")
+ self.twitter = QtWidgets.QLabel(About)
+ self.twitter.setObjectName("twitter")
+ self.fourthrow.addWidget(self.twitter_icon)
+ self.fourthrow.addWidget(self.twitter)
+ self.verticalLayout.addLayout(self.fourthrow)
+
+ # ------------------------------------------------- fifthrow
+ # NOTE fifthrow --------------------------------------------
+ self.fifthrow = QtWidgets.QHBoxLayout()
+ self.fifthrow.setObjectName("fifthrow")
+ self.email_icon = QtWidgets.QToolButton(About)
+ self.email_icon.setObjectName("email_icon")
+ self.email = QtWidgets.QLabel(About)
+ self.email.setObjectName("email")
+ self.fifthrow.addWidget(self.email_icon)
+ self.fifthrow.addWidget(self.email)
+ self.verticalLayout.addLayout(self.fifthrow)
+
+ # ----------------------------------------------- columnsetup
+ # NOTE columnsetup ------------------------------------------
+ self.horizontalLayout.addLayout(self.verticalLayout)
+ self.verticalLayout_4.addLayout(self.horizontalLayout)
+ self.gridLayout.addLayout(self.verticalLayout_4, 0, 0, 1, 1)
+
+ # ----------------------------------------------------- image
+ # NOTE image --- --------------------------------------------
+ self.logo = QtWidgets.QLabel(About)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.logo.sizePolicy().hasHeightForWidth())
+ self.logo.setSizePolicy(sizePolicy)
+ self.logo.setMaximumSize(QtCore.QSize(120, 120))
+ self.logo.setText("")
+ self.logo.setPixmap(QtGui.QPixmap(scriptpath + "/images/logo.png"))
+ self.logo.setScaledContents(True)
+ self.logo.setObjectName("logo")
+ self.gridLayout.addWidget(self.logo, 0, 1, 1, 1)
+
+ self.retranslateUi(About)
+ QtCore.QMetaObject.connectSlotsByName(About)
+
+ def retranslateUi(self, About):
+ _translate = QtCore.QCoreApplication.translate
+ About.setWindowTitle(_translate("About", "Form"))
+ self.web.setText(_translate("About", 'website'))
+ self.github.setText(_translate("About", 'github'))
+ self.twitter.setText(_translate("About", 'twitter'))
+ self.email.setText(_translate("About", 'email'))
+
+# class LinkLabel(QtWidgets.QLabel):
+# def __init__(self, parent, text):
+# super(LinkLabel, self).__init__(parent)
+
+# self.setText(text)
+# self.setTextFormat(QtCore.Qt.RichText)
+# self.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
+# self.setOpenExternalLinks(True)
\ No newline at end of file
diff --git a/python3.7libs/searcher/animator.py b/python3.7libs/searcher/animator.py
new file mode 100644
index 0000000..79f1b09
--- /dev/null
+++ b/python3.7libs/searcher/animator.py
@@ -0,0 +1,58 @@
+from hutil.Qt import QtCore, QtGui, QtWidgets
+
+
+class Animator(QtWidgets.QWidget):
+ def __init__(self, parent=None, close_cb=None, animationDuration=200):
+ super(Animator, self).__init__(parent)
+
+ self.animationDuration = animationDuration
+
+ self.toggleAnimation = QtCore.QParallelAnimationGroup()
+ if close_cb is not None:
+ self.toggleAnimation.finished.connect(close_cb)
+
+ self.contentArea = QtWidgets.QScrollArea(
+ maximumHeight=0, minimumHeight=0, minimumWidth=500)
+ self.contentArea.setStyleSheet(
+ "QScrollArea { background-color: rgba(58 58, 58, 1); border: none;}")
+ self.contentArea.setSizePolicy(
+ QtWidgets.QSizePolicy.Expanding,
+ QtWidgets.QSizePolicy.Fixed)
+
+ toggleAnimation = self.toggleAnimation
+ toggleAnimation.addAnimation(
+ QtCore.QPropertyAnimation(self, b"minimumHeight"))
+ toggleAnimation.addAnimation(
+ QtCore.QPropertyAnimation(self, b"maximumHeight"))
+ toggleAnimation.addAnimation(QtCore.QPropertyAnimation(
+ self.contentArea, b"maximumHeight"))
+
+ mainLayout = QtWidgets.QVBoxLayout(self)
+ mainLayout.setSpacing(0)
+ mainLayout.setContentsMargins(0, 0, 0, 0)
+ mainLayout.addWidget(self.contentArea)
+
+ def start_animation(self, checked):
+ direction = QtCore.QAbstractAnimation.Forward if checked else QtCore.QAbstractAnimation.Backward
+ self.toggleAnimation.setDirection(direction)
+ self.toggleAnimation.start()
+
+ def setContentLayout(self, contentLayout):
+ # Not sure if this is equivalent to self.contentArea.destroy()
+ lay = self.contentArea.layout()
+ del lay
+ self.contentArea.setLayout(contentLayout)
+ collapsedHeight = self.sizeHint().height() - self.contentArea.maximumHeight()
+
+ contentHeight = contentLayout.sizeHint().height()
+ for i in range(self.toggleAnimation.animationCount()-1):
+ expandAnimation = self.toggleAnimation.animationAt(i)
+ expandAnimation.setDuration(self.animationDuration)
+ expandAnimation.setStartValue(collapsedHeight)
+ expandAnimation.setEndValue(collapsedHeight + contentHeight)
+
+ contentAnimation = self.toggleAnimation.animationAt(
+ self.toggleAnimation.animationCount() - 1)
+ contentAnimation.setDuration(self.animationDuration)
+ contentAnimation.setStartValue(0)
+ contentAnimation.setEndValue(contentHeight)
diff --git a/python3.7libs/searcher/bugreport.py b/python3.7libs/searcher/bugreport.py
new file mode 100644
index 0000000..91afd0e
--- /dev/null
+++ b/python3.7libs/searcher/bugreport.py
@@ -0,0 +1,102 @@
+from __future__ import absolute_import
+
+from hutil.py23 import reload
+
+from searcher import bugreport_ui
+import os
+
+import hou
+
+hver = 0
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.') + 1:])
+ from hutil.Qt import QtGui
+ from hutil.Qt import QtCore
+ from hutil.Qt import QtWidgets
+
+try:
+ pyside = os.environ['HOUDINI_QT_PREFERRED_BINDING']
+ parent = hou.qt.mainWindow()
+except KeyError:
+ parent = hou.ui.mainQtWindow()
+ pyside = 'PySide'
+
+if pyside == 'PySide2':
+ # noinspection PyUnresolvedReferences
+ from PySide2 import QtWebEngineWidgets
+
+elif pyside == 'PySide':
+ # noinspection PyUnresolvedReferences
+ from PySide.QtWebKit import QWebView
+
+reload(bugreport_ui)
+
+scriptpath = os.path.dirname(os.path.realpath(__file__))
+
+
+def submittypeswitch(argument):
+ switcher = {
+ 0: "assignees=&labels=bug&template=bug_report.md&title=",
+ 1: "assignees=&labels=enhancement&template=feature_request.md&title=",
+ 2: "assignees=&labels=&template=general-question.md&title=",
+ }
+ return switcher.get(argument, "nothing")
+
+
+class BugReport(QtWidgets.QWidget):
+ """ Searcher Settings and Debug Menu"""
+
+ def __init__(self, parent=None):
+ super(BugReport, self).__init__(parent=parent)
+ self.priortext = ""
+ self.isediting = True
+ self.setParent(parent)
+ self.parentwindow = parent
+ self.ui = bugreport_ui.Ui_BugReport()
+ self.ui.setupUi(self)
+ self.ui.retranslateUi(self)
+ self._webview = None
+ self.installEventFilter(self)
+ self.ui.title.installEventFilter(self)
+
+ def initmenu(self):
+ self.resize(self.width(), self.parentwindow.height() - 300)
+ self._webview = None
+ self.ui.title.setText("")
+ self.ui.edittitle_btn.pressed.connect(self.doweb)
+
+ self.ui.title.setFocus()
+
+ def doweb(self):
+ if self.ui.title.text() == "":
+ self.parentwindow.parentwindow.setstatusmsg("Please enter a title for your bug report", "ImportantMessage")
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ "Please enter a title for your bug report.", severity=hou.severityType.Warning)
+ return
+
+ submittype = submittypeswitch(self.ui.label_cbox.currentIndex())
+ reporturl = '''https://github.com/instance-id/searcher_addon/issues/new?%s%s''' % (submittype, self.ui.title.text())
+
+ QtGui.QDesktopServices.openUrl(QtCore.QUrl(reporturl))
+ self.parentwindow.parentwindow.close()
+
+ # ------------------------------------------------------------- Events
+ # SECTION Events -----------------------------------------------------
+ def eventFilter(self, obj, event):
+ event_type = event.type()
+
+ # ---------------------------------------- Keypress
+ # NOTE Keypress -----------------------------------
+ if event_type == QtCore.QEvent.KeyPress:
+ self.priortext = self.ui.title.text()
+ if event.key() == QtCore.Qt.Key_Escape:
+ self.parentwindow.closeroutine()
+ return True
+
+ if event_type == QtCore.QEvent.Close:
+ self._webview = None
+ self.isediting = True
+
+ return QtCore.QObject.eventFilter(self, obj, event)
diff --git a/python3.7libs/searcher/bugreport_ui.py b/python3.7libs/searcher/bugreport_ui.py
new file mode 100644
index 0000000..c2ec21a
--- /dev/null
+++ b/python3.7libs/searcher/bugreport_ui.py
@@ -0,0 +1,69 @@
+from hutil.Qt import QtCore, QtGui, QtWidgets
+import os
+
+scriptpath = os.path.dirname(os.path.realpath(__file__))
+
+
+class Ui_BugReport(object):
+ def setupUi(self, BugReport):
+ BugReport.setObjectName("BugReport")
+ BugReport.setWindowModality(QtCore.Qt.NonModal)
+ BugReport.resize(450, 20)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(BugReport.sizePolicy().hasHeightForWidth())
+ BugReport.setSizePolicy(sizePolicy)
+ BugReport.setMinimumSize(QtCore.QSize(25, 0))
+ BugReport.setBaseSize(QtCore.QSize(0, 0))
+ BugReport.setContentsMargins(-1, -1, -1,-1)
+ BugReport.setStyleSheet("")
+ self.gridLayout = QtWidgets.QGridLayout(BugReport)
+ self.gridLayout.setContentsMargins(-1, -1, -1, -1)
+ self.gridLayout.setSpacing(0)
+ self.gridLayout.setObjectName("gridLayout")
+ self.verticalLayout_4 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_4.setObjectName("verticalLayout_4")
+ self.secondrow = QtWidgets.QHBoxLayout()
+ self.secondrow.setObjectName("secondrow")
+ self.title = QtWidgets.QLineEdit(BugReport)
+ self.title.setMinimumSize(QtCore.QSize(175, 0))
+ self.title.setObjectName("title")
+ self.secondrow.addWidget(self.title)
+ self.verticalLayout_4.addLayout(self.secondrow)
+ self.thirdrow = QtWidgets.QHBoxLayout()
+ self.thirdrow.setObjectName("thirdrow")
+ spacerItem1 = QtWidgets.QSpacerItem(40, 25, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
+ self.thirdrow.addItem(spacerItem1)
+ self.label_cbox = QtWidgets.QComboBox(BugReport)
+ self.label_cbox.setObjectName("label_cbox")
+ self.label_cbox.setLayoutDirection(QtCore.Qt.LeftToRight)
+ self.label_cbox.setMaximumSize(QtCore.QSize(100, 25))
+ self.label_cbox.addItem("Bug")
+ self.label_cbox.addItem("Suggestion")
+ self.label_cbox.addItem("Question")
+ self.thirdrow.addWidget(self.label_cbox)
+ spacerItem1 = QtWidgets.QSpacerItem(5, 30, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ self.thirdrow.addItem(spacerItem1)
+ self.edittitle_btn = QtWidgets.QPushButton(BugReport)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.edittitle_btn.sizePolicy().hasHeightForWidth())
+ self.edittitle_btn.setSizePolicy(sizePolicy)
+ self.edittitle_btn.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.edittitle_btn.setObjectName("edittitle")
+ self.thirdrow.addWidget(self.edittitle_btn)
+
+ self.verticalLayout_4.addLayout(self.thirdrow)
+ self.gridLayout.addLayout(self.verticalLayout_4, 0, 0, 1, 1)
+
+ self.retranslateUi(BugReport)
+ QtCore.QMetaObject.connectSlotsByName(BugReport)
+
+ def retranslateUi(self, BugReport):
+ _translate = QtCore.QCoreApplication.translate
+ BugReport.setWindowTitle(_translate("BugReport", "Form"))
+ self.edittitle_btn.setText(_translate("BugReport", "Create"))
+ self.title.setPlaceholderText(_translate("BugReport", "Please enter descriptive bug report title:"))
+ # self.continue_btn.setText(_translate("BugReport", "Continue"))
diff --git a/python3.7libs/searcher/colorfieldselector.py b/python3.7libs/searcher/colorfieldselector.py
new file mode 100644
index 0000000..8a14c10
--- /dev/null
+++ b/python3.7libs/searcher/colorfieldselector.py
@@ -0,0 +1,121 @@
+import hou
+
+from hutil.Qt import QtCore
+from hutil.Qt import QtGui
+from hutil.Qt import QtWidgets
+
+_MIN_RGB_VALUE = 0
+_MAX_RGB_VALUE = 255
+
+class ColorFieldSelector(QtWidgets.QWidget):
+ """
+hou.qt.ColorField
+
+A widget for color input.
+
+The widget contains a color swatch button and an input field for RGBA
+values.
+
+This class inherits from Qt's QtWidgets.QWidget class.
+
+"""
+ def __init__(self, label="", include_alpha=False):
+ """
+__init__(self, label=\"\", include_alpha=False)
+
+ Create and return a new ColorField object.
+
+
+ label
+ If set to a non-empty string then a label is added to the color
+ field.
+
+ include_alpha
+ If True, then an alpha component is added to the color field.
+
+"""
+ QtWidgets.QWidget.__init__(self)
+
+ layout = QtWidgets.QHBoxLayout()
+ layout.setSpacing(hou.ui.scaledSize(2))
+ layout.setContentsMargins(0, 0, 0, 0)
+
+ self.colorSwatchButton = hou.qt.ColorSwatchButton(include_alpha)
+
+ # Use the color swatch button's colorChanged signal as our own.
+ self.colorChanged = self.colorSwatchButton.colorChanged
+
+ self.inputField = hou.qt.InputField(
+ hou.qt.InputField.FloatType,
+ 4 if include_alpha else 3)
+
+ if label is not None and label != "":
+ layout.addWidget(hou.qt.FieldLabel(label))
+
+ layout.addWidget(self.colorSwatchButton)
+ layout.addSpacing(hou.ui.scaledSize(5))
+ layout.addWidget(self.inputField)
+
+ # Connect color swatch button to field so their values
+ # are always in-sync.
+ self.colorSwatchButton.colorChanged.connect(
+ self._updateFieldFromColorSwatch)
+ self.inputField.valueChanged.connect(
+ self._updateColorSwatchFromField)
+
+ # Sync input field with color swatch.
+ self._updateFieldFromColorSwatch(self.colorSwatchButton.color())
+
+ self.setLayout(layout)
+
+ def color(self):
+ """
+color() -> QtGui.QColor
+
+ Return the field's current color.
+
+"""
+ return self.colorSwatchButton.color()
+
+ def setColor(self, color):
+ """
+setColor(color)
+
+ Set the field's current color. color must be a QtGui.QColor object.
+
+"""
+ self.colorSwatchButton.setColor(color)
+
+ # Update the input field with the new color.
+ self._updateFieldFromColorSwatch(color)
+
+ def _updateFieldFromColorSwatch(self, color):
+ if self.colorSwatchButton.hasAlpha():
+ self.inputField.setValues([
+ color.redF(), color.greenF(), color.blueF(), color.alphaF()])
+ else:
+ self.inputField.setValues([
+ color.redF(), color.greenF(), color.blueF()])
+
+ def _updateColorSwatchFromField(self):
+ values = list(self.inputField.values())
+
+ color = QtGui.QColor()
+ color.setRedF(self._clampRGBValue(values[0]))
+ color.setGreenF(self._clampRGBValue(values[1]))
+ color.setBlueF(self._clampRGBValue(values[2]))
+
+ if self.colorSwatchButton.hasAlpha():
+ color.setAlphaF(self._clampRGBValue(values[3]))
+
+ self.colorSwatchButton.setColor(color)
+
+ def _clampRGBValue(self, val):
+ if val > 1.0:
+ return 1.0
+
+ if val < 0.0:
+ return 0.0
+
+ return val
+
diff --git a/python3.7libs/searcher/database.py b/python3.7libs/searcher/database.py
new file mode 100644
index 0000000..b4b306b
--- /dev/null
+++ b/python3.7libs/searcher/database.py
@@ -0,0 +1,437 @@
+from __future__ import print_function
+from __future__ import absolute_import
+import weakref
+
+import hou
+import os
+
+from . import util
+from . import settings_data
+from . import ptime as ptime
+
+from peewee import *
+from playhouse.sqlite_ext import SqliteExtDatabase, RowIDField, FTS5Model, SearchField
+import time
+
+# --------------------------------------------- hou.session
+# NOTE hou.session ----------------------------------------
+def get_settings():
+ return getattr(hou.session, "SETTINGS", None)
+
+def get_dbconnection():
+ return getattr(hou.session, "DBCONNECTION", None)
+
+
+scriptpath = os.path.dirname(os.path.realpath(__file__))
+db = get_dbconnection()
+
+# --------------------------------------------------------- DatabaseModels
+# SECTION DatabaseModels -------------------------------------------------
+# ------------------------------------------------ Settings
+# NOTE Settings -------------------------------------------
+class Settings(Model):
+ id = IntegerField(unique=True)
+ indexvalue = IntegerField()
+ defaulthotkey = TextField()
+ searchdescription = IntegerField()
+ searchprefix = IntegerField()
+ searchcurrentcontext = IntegerField()
+ lastused = TextField()
+
+ class Meta:
+ table_name = 'settings'
+ database = db
+
+# ------------------------------------------------ HContext
+# NOTE HContext -------------------------------------------
+class HContext(Model):
+ id = AutoField()
+ context = TextField(unique=True)
+ title = TextField()
+ description = TextField()
+
+ class Meta:
+ table_name = 'hcontext'
+ database = db
+
+# # # ------------------------------------------- HContextIndex
+# # # NOTE HContextIndex --------------------------------------
+# class HContextIndex(FTS5Model):
+# # rowid = RowIDField()
+# context = SearchField()
+# title = SearchField()
+# description = SearchField()
+
+# class Meta:
+# database = db
+# options = {'prefix': [2, 3], 'tokenize': 'porter'}
+
+# ------------------------------------------------- Hotkeys
+# NOTE Hotkeys --------------------------------------------
+class Hotkeys(Model):
+ hotkey_symbol = CharField(unique=True)
+ label = CharField()
+ description = TextField()
+ assignments = TextField()
+ context = TextField()
+
+ class Meta:
+ table_name = 'hotkeys'
+ database = db
+
+# -------------------------------------------- HotkeysIndex
+# NOTE HotkeysIndex ---------------------------------------
+class HotkeysIndex(FTS5Model):
+ # rowid = RowIDField()
+ hotkey_symbol = SearchField(unindexed=True)
+ label = SearchField()
+ description = SearchField()
+ assignments = SearchField(unindexed=True)
+ context = SearchField(unindexed=True)
+
+ def clear_index(self):
+ HotkeysIndex.delete().where(HotkeysIndex.rowid == self.id).execute()
+
+ class Meta:
+ # table_name = 'hotkeysindex'
+ database = db
+ options = {'prefix': [2, 3], 'tokenize': 'porter'}
+# !SECTION
+
+# -------------------------------------------------------------- Functions
+# SECTION Functions ------------------------------------------------------
+# ----------------------------------------------- py_unique
+# NOTE py_unique ------------------------------------------
+def py_unique(data):
+ return list(set(data))
+
+# ------------------------------------------------- getdata
+# NOTE getdata --------------------------------------------
+def getdata():
+ rval = []
+ contextdata = []
+ hotkeydata = []
+
+ def getcontexts(r, context_symbol, root):
+ keys = None
+ branches = hou.hotkeys.contextsInContext(context_symbol)
+ for branch in branches:
+ branch_path = "%s/%s" % (r, branch['label'])
+ contextdata.append(
+ {'context': branch['symbol'],
+ 'title': branch['label'],
+ 'description': branch['help']}
+ )
+ commands = hou.hotkeys.commandsInContext(branch['symbol'])
+ for command in commands:
+ keys = hou.hotkeys.assignments(command['symbol'])
+ ctx = command['symbol'].rsplit('.', 1)
+ hotkeydata.append(
+ {'hotkey_symbol': command['symbol'],
+ 'label': command['label'],
+ 'description': command['help'],
+ 'assignments': " ".join(keys),
+ 'context': ctx[0]}
+ )
+ getcontexts(branch_path, branch['symbol'], root)
+
+ getcontexts("", "", rval)
+ return contextdata, hotkeydata
+# !SECTION
+
+# ----------------------------------------------------------- Database
+# SECTION Database ---------------------------------------------------
+class Databases(object):
+ def __init__(self):
+
+ self.settings = get_settings()
+ self.isdebug = util.bc(self.settings[util.SETTINGS_KEYS[4]])
+ inmemory = util.bc(self.settings[util.SETTINGS_KEYS[0]])
+ if inmemory:
+ val = ':memory:'
+ else:
+ val = (self.settings[util.SETTINGS_KEYS[1]])
+
+ self.db = db
+ if not self.db:
+ hou.session.DBCONNECTION = DatabaseProxy()
+ self.db.initialize(
+ SqliteExtDatabase(
+ val,
+ pragmas=(
+ ("cache_size", -1024 * 64),
+ ("journal_mode", "off"),
+ ("temp_store", "memory"),
+ ("synchronous", 0)
+ )))
+ if inmemory or not os.path.isfile(self.settings[util.SETTINGS_KEYS[1]]):
+ db.create_tables([
+ Settings,
+ HContext,
+ Hotkeys,
+ HotkeysIndex,]
+ )
+ self.initialsetup(self.cur)
+
+ self.cur = db.cursor()
+ self.isdebug = None
+ self.contexttime = 0
+ self.hotkeystime = 0
+
+ # ----------------------------------------------------------- Retrieve
+ # SECTION Retrieve ---------------------------------------------------
+ # -------------------------------------- getchangeindex
+ # NOTE getchangeindex ---------------------------------
+ def getchangeindex(self):
+ try:
+ self.cur.execute("SELECT indexvalue FROM settings")
+ result = self.cur.fetchall()
+ return result
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(("Could not get Searcher changeindex: " + str(e)), severity=hou.severityType.Error)
+
+ # ------------------------------------------- getlastusedhk
+ # NOTE getlastusedhk --------------------------------------
+ def getlastusedhk(self):
+ try:
+ lastkey = self.settings[util.SETTINGS_KEYS[11]]
+ if str(lastkey) != "":
+ lasthk = str(lastkey).split(' ')
+ hkcheck = hou.hotkeys.assignments(str(lasthk[0]))
+
+ if len(hkcheck) is 0:
+ self.settings[util.SETTINGS_KEYS[11]] = ""
+ settings_data.savesettings(settingdata)
+ return
+
+ rmresult = hou.hotkeys.removeAssignment(
+ str(lasthk[0]).strip(), str(lasthk[1]).strip())
+ if rmresult:
+ hkcheck = hou.hotkeys.assignments(str(lasthk[0]))
+ hou.hotkeys.saveOverrides()
+ if len(hkcheck) is 0:
+ self.settings[util.SETTINGS_KEYS[11]] = ""
+ settings_data.savesettings(settingdata)
+ self.updatechangeindex(int(currentidx))
+ else:
+ hou.hotkeys.clearAssignments(str(lasthk[0]))
+ hou.hotkeys.saveOverrides()
+ hkcheck = hou.hotkeys.assignments(str(lasthk[0]))
+ if len(hkcheck) is 0:
+ self.settings[util.SETTINGS_KEYS[11]] = ""
+ settings_data.savesettings(settingdata)
+ self.updatechangeindex(int(currentidx))
+ else:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(("Could not clear last assigned temp hotkey on last attempt:"), severity=hou.severityType.Warning)
+ else:
+ print("Could not clear last assigned temp hotkey on last attempt:")
+ else:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(("Could not clear last assigned temp hotkey:"), severity=hou.severityType.Warning)
+ else:
+ print("Could not clear last assigned temp hotkey:")
+
+ except(AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(("Could not query last assigned temp hotkey:" + str(e)), severity=hou.severityType.Warning)
+ else:
+ print("Could not query last assigned temp hotkey: " + str(e))
+
+ # -------------------------------------------- getdefhotkey
+ # NOTE getdefhotkey ---------------------------------------
+ def getdefhotkey(self):
+ try:
+ self.cur.execute("SELECT defaulthotkey FROM settings")
+ result = self.cur.fetchall()
+ return result
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(("Could not get Searcher default hotkey: " + str(e)), severity=hou.severityType.Error)
+
+ # -------------------------------------------- gethcontexts
+ # NOTE gethcontexts ---------------------------------------
+ def gethcontexts(self):
+ try:
+ self.cur.execute("SELECT * FROM hcontext")
+ result = self.cur.fetchall()
+ return result
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(("Could not get Searcher hcontext: " + str(e)), severity=hou.severityType.Error)
+
+ # ------------------------------------------- gethcontextod
+ # NOTE gethcontextod --------------------------------------
+ def gethcontextod(self, inputlist):
+ try:
+ time1 = ptime.time()
+ result = []
+ query = (HContext
+ .select()
+ .where(HContext.context.in_(inputlist))).execute()
+ for hctx in query:
+ result.append((hctx.title, hctx.description, hctx.context))
+ uniqueresult = py_unique(result)
+ time2 = ptime.time()
+ self.contexttime = ((time2 - time1) * 1000.0)
+ return uniqueresult, self.contexttime
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(("Could not update Searcher context database: " + str(e)), severity=hou.severityType.Error)
+
+ # ---------------------------------------- ctxfilterresults
+ # NOTE ctxfilterresults -----------------------------------
+ def ctxfilterresults(self, inputTerm):
+ try:
+ result = []
+ query = (Hotkeys
+ .select()
+ .where(Hotkeys.context.in_(inputTerm))).execute()
+ for hctx in query:
+ result.append((hctx.label, hctx.description, hctx.assignments, hctx.hotkey_symbol, hctx.context))
+ uniqueresult = py_unique(result)
+ return uniqueresult
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(("Could not get Searcher context results: " + str(e)), severity=hou.severityType.Error)
+
+ # ------------------------------------------- searchresults
+ # NOTE searchresults --------------------------------------
+ def searchresults(self, inputTerm, debug, limit=0):
+ self.isdebug = debug
+ try:
+ time1 = ptime.time()
+ self.cur.execute(
+ "SELECT label, description, assignments, hotkey_symbol, context FROM hotkeysindex WHERE hotkeysindex MATCH '"
+ + str(inputTerm)
+ + "' ORDER BY rank"
+ + " LIMIT "
+ + str(limit)
+ )
+ result = self.cur.fetchall()
+ uniqueresult = py_unique(result)
+
+ time2 = ptime.time()
+ self.hotkeystime = ((time2 - time1) * 1000.0)
+
+ return uniqueresult, self.hotkeystime
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(("Could not get Searcher results: " + str(e)), severity=hou.severityType.Error)
+ # !SECTION
+
+ # ------------------------------------------------------------ Updates
+ # SECTION Updates ----------------------------------------------------
+ # --------------------------------------- updatechangeindex
+ # NOTE updatechangeindex ----------------------------------
+ def updatechangeindex(self, indexval, new=False):
+ try:
+ if new is True:
+ defaultkey = ""
+ for i in range(len(util.HOTKEYLIST)):
+ result = hou.hotkeys.findConflicts("h", util.HOTKEYLIST[i])
+ if not result:
+ defaultkey = util.HOTKEYLIST[i]
+
+ Settings.insert(indexvalue=indexval,
+ defaulthotkey=defaultkey, searchdescription=0, searchprefix=0, searchcurrentcontext=0, lastused="", id=1).execute()
+ else:
+ Settings.update(indexvalue=indexval).where(
+ Settings.id == 1).execute()
+ except(AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ ("Could not update Searcher context database: " + str(e)),
+ severity=hou.severityType.Warning
+ )
+ else:
+ print("Could not update Searcher context database: " + str(e))
+
+ # --------------------------------------------- updatetmphk
+ # NOTE updatetmphk ----------------------------------------
+ def updatetmphk(self, tmpkey):
+ try:
+ _ = Settings.update(
+ defaulthotkey=tmpkey).where(id == 1).execute()
+ return
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(("Could not update Searcher temp hotkey: " + str(e)), severity=hou.severityType.Error)
+
+ # ------------------------------------------- updatelastkey
+ # NOTE updatelastkey --------------------------------------
+ def updatelastkey(self, lastkey):
+ try:
+ _ = Settings.update(lastused=lastkey).where(id == 1).execute()
+ return
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(("Could not update Searcher temp hotkey: " + str(e)), severity=hou.severityType.Error)
+
+ # ------------------------------------------- updatecontext
+ # NOTE updatecontext --------------------------------------
+ def updatecontext(self, debug):
+ self.isdebug = debug
+ try:
+ time1 = ptime.time()
+ self.cleardatabase()
+ ctxdata, hkeydata = getdata()
+ with db.atomic():
+ for data_dict in ctxdata:
+ HContext.replace_many(data_dict).execute()
+ with db.atomic():
+ for idx in hkeydata:
+ Hotkeys.replace_many(idx).execute()
+ HotkeysIndex.replace_many(idx).execute()
+ time2 = ptime.time()
+ if self.isdebug and self.isdebug.level in {"TIMER", "ALL"}:
+ res = ((time2 - time1) * 1000.0)
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ ('DB update took %0.4f ms' % res), severity=hou.severityType.Message)
+ else:
+ print('DB update took %0.4f ms' % res)
+ return res
+
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(("Could not update Searcher context database: " + str(e)), severity=hou.severityType.Error)
+ # !SECTION
+
+ # ------------------------------------------- cleardatabase
+ # NOTE cleardatabase --------------------------------------
+ def cleardatabase(self):
+ try:
+ delhk = "DELETE FROM hotkeys"
+ delctx = "DELETE FROM hcontext"
+ delhkindex = "DELETE FROM hotkeysindex"
+ # delhcindex = "DELETE FROM hcontextindex"
+ self.cur.execute(delhk)
+ self.cur.execute(delctx)
+ self.cur.execute(delhkindex)
+ result = self.cur.fetchall()
+
+ return result
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(("Could not update Searcher temp hotkey: " + str(e)),severity=hou.severityType.Error)
+
+ # -------------------------------------------- initialsetup
+ # NOTE initialsetup ---------------------------------------
+ def initialsetup(self):
+ currentidx = hou.hotkeys.changeIndex()
+ chindex = self.getchangeindex()
+
+ if len(chindex) == 0:
+ chindex = int(currentidx)
+ self.updatechangeindex(chindex, True)
+ self.updatecontext(self.isdebug)
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ "Searcher database created", severity=hou.severityType.Message)
+ else:
+ print("Searcher database created")
+ else:
+ chindex = int(chindex[0][0])
+
+ if int(currentidx) != chindex:
+ self.getlastusedhk()
+ self.updatecontext()
+ self.updatechangeindex(int(currentidx))
+
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ "Searcher database created and populated", severity=hou.severityType.Message)
+ # !SECTION
+# !SECTION
\ No newline at end of file
diff --git a/python3.7libs/searcher/datahandler.py b/python3.7libs/searcher/datahandler.py
new file mode 100644
index 0000000..6658a9f
--- /dev/null
+++ b/python3.7libs/searcher/datahandler.py
@@ -0,0 +1,121 @@
+from __future__ import print_function
+from __future__ import absolute_import
+
+import hou
+import os
+
+from hutil.py23 import reload
+
+from searcher import util
+from searcher import settings_data
+from searcher import ptime as ptime
+from searcher import database
+
+import os
+import threading
+import hdefereval as hd
+
+reload(database)
+
+def get_db():
+ return getattr(hou.session, "DATABASE", None)
+
+def worker():
+ hd.executeInMainThreadWithResult(DataHandler().updatedata)
+
+
+class DataHandler(object):
+ """Searcher data and communication handler"""
+
+ def __init__(self, debug=None):
+ self.db = get_db()
+ if not self.db:
+ hou.session.DATABASE = database.Databases()
+ self.db = get_db()
+
+ self.isdebug = debug
+ self.scriptpath = os.path.dirname(os.path.realpath(__file__))
+
+ # ----------------------------------------------------------- Retrieve
+ # SECTION Retrieve ---------------------------------------------------
+ # -------------------------------------- getchangeindex
+ # NOTE getchangeindex ---------------------------------
+ def getchangeindex(self):
+ index = self.db.getchangeindex()
+ return index
+
+ # ------------------------------------ getdefaulthotkey
+ # NOTE getdefaulthotkey -------------------------------
+ def getdefaulthotkey(self):
+ index = self.db.getdefhotkey()
+ return index
+
+ # ----------------------------------------- gethcontext
+ # NOTE gethcontext ------------------------------------
+ # @staticmethod
+ def gethcontext(self):
+ results = self.db.gethcontexts()
+ return results
+
+ # --------------------------------------- gethcontextod
+ # NOTE gethcontextod ----------------------------------
+ def gethcontextod(self, inputtext):
+ results, timer = self.db.gethcontextod(inputtext)
+ return results, timer
+
+ # ------------------------------------------- searchctx
+ # NOTE searchctx --------------------------------------
+ def searchctx(self, txt):
+ results = self.db.ctxfilterresults(txt)
+ return results
+
+ # ------------------------------------------ searchtext
+ # NOTE searchtext -------------------------------------
+ def searchtext(self, txt, debug, limit=0):
+ self.isdebug = debug
+ results, timer = self.db.searchresults(txt, self.isdebug, limit)
+ return results, timer
+
+ # !SECTION Retrieve
+
+ # ------------------------------------------------------------- Update
+ # SECTION Update -----------------------------------------------------
+ # ----------------------------------- updatechangeindex
+ # NOTE updatechangeindex ------------------------------
+ def updatechangeindex(self, indexval, new=False):
+ self.db.updatechangeindex(indexval, new)
+ return
+
+ # ------------------------------------- updatedataasync
+ # NOTE updatedataasync --------------------------------
+ def updatedataasync(self, debug):
+ self.isdebug = debug
+ thread = threading.Thread(target=worker)
+ thread.daemon = True
+ thread.start()
+
+ # ------------------------------------------ updatedata
+ # NOTE updatedata -------------------------------------
+ def updatedata(self):
+ self.db.updatecontext(self.isdebug)
+ return
+
+ # ------------------------------------- updatetmphotkey
+ # NOTE updatetmphotkey --------------------------------
+ def updatetmphotkey(self, tmpkey):
+ self.db.updatetmphk(tmpkey)
+ return
+
+ # ---------------------------------------- updatelasthk
+ # NOTE updatelasthk -----------------------------------
+ def updatelasthk(self, lastkey):
+ self.db.updatelastkey(lastkey)
+ return
+
+ # !SECTION Update
+
+ # --------------------------------------------- cleardb
+ # NOTE cleardb ----------------------------------------
+ def cleardb(self):
+ results = self.db.cleardatabase()
+ return results
\ No newline at end of file
diff --git a/python3.7libs/searcher/debugutils.py b/python3.7libs/searcher/debugutils.py
new file mode 100644
index 0000000..a5bab8a
--- /dev/null
+++ b/python3.7libs/searcher/debugutils.py
@@ -0,0 +1,48 @@
+from __future__ import print_function
+from __future__ import division
+
+from builtins import range
+from past.utils import old_div
+from hutil.Qt import QtCore
+from hutil.Qt import QtGui
+from hutil.Qt import QtWidgets
+
+
+def dumpWidgetLayout(widget, prefix=''):
+ """ Debug utility to print out tree of widgets with relevant layout
+ properties
+ """
+ text = ""
+ if not isinstance(widget, QtWidgets.QWidget) \
+ and not isinstance(widget, QtWidgets.QDialog):
+ return
+
+ text += str((prefix, "* name:", str(widget.objectName())))
+ text += str((prefix, " visible:", str(widget.isVisible())))
+ text += str((prefix, " minimumSize:", str(widget.minimumSize())))
+ text += str((prefix, " minimumSizeHint:", str(widget.minimumSizeHint())))
+ text += str((prefix, " sizeHint:", str(widget.sizeHint())))
+ text += str((prefix, " contentsMargins:", str(widget.contentsMargins())))
+ text += str((prefix, " sizePolicy:", str(widget.sizePolicy())))
+ if widget.layout():
+ layout = widget.layout()
+ text += str((prefix, " layout.minimumSize:", str(widget.layout().minimumSize())))
+ text += str((prefix, " layout.sizeHint:", str(widget.layout().sizeHint())))
+ text += str((prefix, " layout.contentsMargins:", str(widget.layout().contentsMargins())))
+ for i in range(0, layout.count()):
+ item = layout.itemAt(i)
+ dir_flag = item.expandingDirections()
+ if (dir_flag & QtCore.Qt.Orientation.Horizontal):
+ text += str((prefix, " -> ", i, ": expand HORIZ"))
+ elif (dir_flag & QtCore.Qt.Orientation.Vertical):
+ text += str((prefix, " -> ", i, ": expand VERTICAL"))
+ else:
+ text += str((prefix, " -> ", i, ": NO expand"))
+ text += str((prefix, " -> ", i, ": sizeHint", str(item.sizeHint())))
+ if item.widget():
+ text += str((prefix, " -> ", i, ": widget.sizeHint", str(item.widget().sizeHint())))
+ text += str((prefix, " numChildren:", len(widget.children())))
+ for child in widget.children():
+ dumpWidgetLayout(child, prefix + ' ')
+
+ return text
diff --git a/python3.7libs/searcher/enum.py b/python3.7libs/searcher/enum.py
new file mode 100644
index 0000000..83d8868
--- /dev/null
+++ b/python3.7libs/searcher/enum.py
@@ -0,0 +1,38 @@
+# --------------------------------------------
+# http://code.activestate.com/recipes/413486/
+# --------------------------------------------
+def Enum(*names):
+ ##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!
+
+ class EnumClass(object):
+ __slots__ = names
+ def __iter__(self): return iter(constants)
+ def __len__(self): return len(constants)
+ def __getitem__(self, i): return constants[i]
+ def __repr__(self): return 'Enum' + str(names)
+ def __str__(self): return 'enum ' + str(constants)
+
+ class EnumValue(object):
+ __slots__ = ('__value')
+ def __init__(self, value): self.__value = value
+ Value = property(lambda self: self.__value)
+ EnumType = property(lambda self: EnumType)
+ def __hash__(self): return hash(self.__value)
+ def __cmp__(self, other):
+ # C fans might want to remove the following assertion
+ # to make all enums comparable by ordinal value {;))
+ assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
+ return cmp(self.__value, other.__value)
+ def __invert__(self): return constants[maximum - self.__value]
+ def __nonzero__(self): return bool(self.__value)
+ def __repr__(self): return str(names[self.__value])
+
+ maximum = len(names) - 1
+ constants = [None] * len(names)
+ for i, each in enumerate(names):
+ val = EnumValue(i)
+ setattr(EnumClass, each, val)
+ constants[i] = val
+ constants = tuple(constants)
+ EnumType = EnumClass()
+ return EnumType
\ No newline at end of file
diff --git a/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Bold-Italic.ttf b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Bold-Italic.ttf
new file mode 100644
index 0000000..87b9bf8
Binary files /dev/null and b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Bold-Italic.ttf differ
diff --git a/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Bold.ttf b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Bold.ttf
new file mode 100644
index 0000000..fd1ab3c
Binary files /dev/null and b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Bold.ttf differ
diff --git a/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-ExtraBold-Italic.ttf b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-ExtraBold-Italic.ttf
new file mode 100644
index 0000000..bff0884
Binary files /dev/null and b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-ExtraBold-Italic.ttf differ
diff --git a/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-ExtraBold.ttf b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-ExtraBold.ttf
new file mode 100644
index 0000000..0e09b46
Binary files /dev/null and b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-ExtraBold.ttf differ
diff --git a/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Italic.ttf b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Italic.ttf
new file mode 100644
index 0000000..2b6d374
Binary files /dev/null and b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Italic.ttf differ
diff --git a/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Medium-Italic.ttf b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Medium-Italic.ttf
new file mode 100644
index 0000000..8f7ad12
Binary files /dev/null and b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Medium-Italic.ttf differ
diff --git a/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Medium.ttf b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Medium.ttf
new file mode 100644
index 0000000..f01ae48
Binary files /dev/null and b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Medium.ttf differ
diff --git a/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Regular.ttf b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Regular.ttf
new file mode 100644
index 0000000..dfbece6
Binary files /dev/null and b/python3.7libs/searcher/fonts/JetBrainsMono-1.0.0/JetBrainsMono-Regular.ttf differ
diff --git a/python3.7libs/searcher/images/collapse_all.png b/python3.7libs/searcher/images/collapse_all.png
new file mode 100644
index 0000000..3adcc10
Binary files /dev/null and b/python3.7libs/searcher/images/collapse_all.png differ
diff --git a/python3.7libs/searcher/images/expand_all.png b/python3.7libs/searcher/images/expand_all.png
new file mode 100644
index 0000000..eecb11a
Binary files /dev/null and b/python3.7libs/searcher/images/expand_all.png differ
diff --git a/python3.7libs/searcher/images/help.png b/python3.7libs/searcher/images/help.png
new file mode 100644
index 0000000..a82dd24
Binary files /dev/null and b/python3.7libs/searcher/images/help.png differ
diff --git a/python3.7libs/searcher/images/help1.png b/python3.7libs/searcher/images/help1.png
new file mode 100644
index 0000000..7cd312e
Binary files /dev/null and b/python3.7libs/searcher/images/help1.png differ
diff --git a/python3.7libs/searcher/images/icon_branch_closed.png b/python3.7libs/searcher/images/icon_branch_closed.png
new file mode 100644
index 0000000..fa785cc
Binary files /dev/null and b/python3.7libs/searcher/images/icon_branch_closed.png differ
diff --git a/python3.7libs/searcher/images/icon_branch_end.png b/python3.7libs/searcher/images/icon_branch_end.png
new file mode 100644
index 0000000..d90a04c
Binary files /dev/null and b/python3.7libs/searcher/images/icon_branch_end.png differ
diff --git a/python3.7libs/searcher/images/icon_branch_more.png b/python3.7libs/searcher/images/icon_branch_more.png
new file mode 100644
index 0000000..bdbe4ed
Binary files /dev/null and b/python3.7libs/searcher/images/icon_branch_more.png differ
diff --git a/python3.7libs/searcher/images/icon_branch_open.png b/python3.7libs/searcher/images/icon_branch_open.png
new file mode 100644
index 0000000..9dd05d6
Binary files /dev/null and b/python3.7libs/searcher/images/icon_branch_open.png differ
diff --git a/python3.7libs/searcher/images/icon_vline.png b/python3.7libs/searcher/images/icon_vline.png
new file mode 100644
index 0000000..14228c8
Binary files /dev/null and b/python3.7libs/searcher/images/icon_vline.png differ
diff --git a/python3.7libs/searcher/images/icons/at-solid.svg b/python3.7libs/searcher/images/icons/at-solid.svg
new file mode 100644
index 0000000..8b72d6f
--- /dev/null
+++ b/python3.7libs/searcher/images/icons/at-solid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/python3.7libs/searcher/images/icons/bug-solid.svg b/python3.7libs/searcher/images/icons/bug-solid.svg
new file mode 100644
index 0000000..c7af707
--- /dev/null
+++ b/python3.7libs/searcher/images/icons/bug-solid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/python3.7libs/searcher/images/icons/firefox-browser-brands.svg b/python3.7libs/searcher/images/icons/firefox-browser-brands.svg
new file mode 100644
index 0000000..316a13c
--- /dev/null
+++ b/python3.7libs/searcher/images/icons/firefox-browser-brands.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/python3.7libs/searcher/images/icons/github-brands.svg b/python3.7libs/searcher/images/icons/github-brands.svg
new file mode 100644
index 0000000..7870c06
--- /dev/null
+++ b/python3.7libs/searcher/images/icons/github-brands.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/python3.7libs/searcher/images/icons/twitter-brands.svg b/python3.7libs/searcher/images/icons/twitter-brands.svg
new file mode 100644
index 0000000..9ac9e0b
--- /dev/null
+++ b/python3.7libs/searcher/images/icons/twitter-brands.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/python3.7libs/searcher/images/logo.png b/python3.7libs/searcher/images/logo.png
new file mode 100644
index 0000000..4292cea
Binary files /dev/null and b/python3.7libs/searcher/images/logo.png differ
diff --git a/python3.7libs/searcher/images/resizeleft.png b/python3.7libs/searcher/images/resizeleft.png
new file mode 100644
index 0000000..b3f4732
Binary files /dev/null and b/python3.7libs/searcher/images/resizeleft.png differ
diff --git a/python3.7libs/searcher/images/resizeright.png b/python3.7libs/searcher/images/resizeright.png
new file mode 100644
index 0000000..e984170
Binary files /dev/null and b/python3.7libs/searcher/images/resizeright.png differ
diff --git a/python3.7libs/searcher/inspect.py b/python3.7libs/searcher/inspect.py
new file mode 100644
index 0000000..0a6cfd7
--- /dev/null
+++ b/python3.7libs/searcher/inspect.py
@@ -0,0 +1,1066 @@
+# -*- coding: iso-8859-1 -*-
+"""Get useful information from live Python objects.
+
+This module encapsulates the interface provided by the internal special
+attributes (func_*, co_*, im_*, tb_*, etc.) in a friendlier fashion.
+It also provides some help for examining source code and class layout.
+
+Here are some of the useful functions provided by this module:
+
+ ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),
+ isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),
+ isroutine() - check object types
+ getmembers() - get members of an object that satisfy a given condition
+
+ getfile(), getsourcefile(), getsource() - find an object's source code
+ getdoc(), getcomments() - get documentation on an object
+ getmodule() - determine the module that an object came from
+ getclasstree() - arrange classes so as to represent their hierarchy
+
+ getargspec(), getargvalues(), getcallargs() - get info about function arguments
+ formatargspec(), formatargvalues() - format an argument spec
+ getouterframes(), getinnerframes() - get info about frames
+ currentframe() - get the current stack frame
+ stack(), trace() - get info about frames on the stack or in a traceback
+"""
+
+# This module is in the public domain. No warranties.
+
+__author__ = 'Ka-Ping Yee '
+__date__ = '1 Jan 2001'
+
+import sys
+import os
+import types
+import string
+import re
+import dis
+import imp
+import tokenize
+import linecache
+from operator import attrgetter
+from collections import namedtuple
+
+# These constants are from Include/code.h.
+CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 0x1, 0x2, 0x4, 0x8
+CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40
+# See Include/object.h
+TPFLAGS_IS_ABSTRACT = 1 << 20
+
+# ----------------------------------------------------------- type-checking
+def ismodule(object):
+ """Return true if the object is a module.
+
+ Module objects provide these attributes:
+ __doc__ documentation string
+ __file__ filename (missing for built-in modules)"""
+ return isinstance(object, types.ModuleType)
+
+def isclass(object):
+ """Return true if the object is a class.
+
+ Class objects provide these attributes:
+ __doc__ documentation string
+ __module__ name of module in which this class was defined"""
+ return isinstance(object, (type, types.ClassType))
+
+def ismethod(object):
+ """Return true if the object is an instance method.
+
+ Instance method objects provide these attributes:
+ __doc__ documentation string
+ __name__ name with which this method was defined
+ im_class class object in which this method belongs
+ im_func function object containing implementation of method
+ im_self instance to which this method is bound, or None"""
+ return isinstance(object, types.MethodType)
+
+def ismethoddescriptor(object):
+ """Return true if the object is a method descriptor.
+
+ But not if ismethod() or isclass() or isfunction() are true.
+
+ This is new in Python 2.2, and, for example, is true of int.__add__.
+ An object passing this test has a __get__ attribute but not a __set__
+ attribute, but beyond that the set of attributes varies. __name__ is
+ usually sensible, and __doc__ often is.
+
+ Methods implemented via descriptors that also pass one of the other
+ tests return false from the ismethoddescriptor() test, simply because
+ the other tests promise more -- you can, e.g., count on having the
+ im_func attribute (etc) when an object passes ismethod()."""
+ return (hasattr(object, "__get__")
+ and not hasattr(object, "__set__") # else it's a data descriptor
+ and not ismethod(object) # mutual exclusion
+ and not isfunction(object)
+ and not isclass(object))
+
+def isdatadescriptor(object):
+ """Return true if the object is a data descriptor.
+
+ Data descriptors have both a __get__ and a __set__ attribute. Examples are
+ properties (defined in Python) and getsets and members (defined in C).
+ Typically, data descriptors will also have __name__ and __doc__ attributes
+ (properties, getsets, and members have both of these attributes), but this
+ is not guaranteed."""
+ return (hasattr(object, "__set__") and hasattr(object, "__get__"))
+
+if hasattr(types, 'MemberDescriptorType'):
+ # CPython and equivalent
+ def ismemberdescriptor(object):
+ """Return true if the object is a member descriptor.
+
+ Member descriptors are specialized descriptors defined in extension
+ modules."""
+ return isinstance(object, types.MemberDescriptorType)
+else:
+ # Other implementations
+ def ismemberdescriptor(object):
+ """Return true if the object is a member descriptor.
+
+ Member descriptors are specialized descriptors defined in extension
+ modules."""
+ return False
+
+if hasattr(types, 'GetSetDescriptorType'):
+ # CPython and equivalent
+ def isgetsetdescriptor(object):
+ """Return true if the object is a getset descriptor.
+
+ getset descriptors are specialized descriptors defined in extension
+ modules."""
+ return isinstance(object, types.GetSetDescriptorType)
+else:
+ # Other implementations
+ def isgetsetdescriptor(object):
+ """Return true if the object is a getset descriptor.
+
+ getset descriptors are specialized descriptors defined in extension
+ modules."""
+ return False
+
+def isfunction(object):
+ """Return true if the object is a user-defined function.
+
+ Function objects provide these attributes:
+ __doc__ documentation string
+ __name__ name with which this function was defined
+ func_code code object containing compiled function bytecode
+ func_defaults tuple of any default values for arguments
+ func_doc (same as __doc__)
+ func_globals global namespace in which this function was defined
+ func_name (same as __name__)"""
+ return isinstance(object, types.FunctionType)
+
+def isgeneratorfunction(object):
+ """Return true if the object is a user-defined generator function.
+
+ Generator function objects provide the same attributes as functions.
+ See help(isfunction) for a list of attributes."""
+ return bool((isfunction(object) or ismethod(object)) and
+ object.func_code.co_flags & CO_GENERATOR)
+
+def isgenerator(object):
+ """Return true if the object is a generator.
+
+ Generator objects provide these attributes:
+ __iter__ defined to support iteration over container
+ close raises a new GeneratorExit exception inside the
+ generator to terminate the iteration
+ gi_code code object
+ gi_frame frame object or possibly None once the generator has
+ been exhausted
+ gi_running set to 1 when generator is executing, 0 otherwise
+ next return the next item from the container
+ send resumes the generator and "sends" a value that becomes
+ the result of the current yield-expression
+ throw used to raise an exception inside the generator"""
+ return isinstance(object, types.GeneratorType)
+
+def istraceback(object):
+ """Return true if the object is a traceback.
+
+ Traceback objects provide these attributes:
+ tb_frame frame object at this level
+ tb_lasti index of last attempted instruction in bytecode
+ tb_lineno current line number in Python source code
+ tb_next next inner traceback object (called by this level)"""
+ return isinstance(object, types.TracebackType)
+
+def isframe(object):
+ """Return true if the object is a frame object.
+
+ Frame objects provide these attributes:
+ f_back next outer frame object (this frame's caller)
+ f_builtins built-in namespace seen by this frame
+ f_code code object being executed in this frame
+ f_exc_traceback traceback if raised in this frame, or None
+ f_exc_type exception type if raised in this frame, or None
+ f_exc_value exception value if raised in this frame, or None
+ f_globals global namespace seen by this frame
+ f_lasti index of last attempted instruction in bytecode
+ f_lineno current line number in Python source code
+ f_locals local namespace seen by this frame
+ f_restricted 0 or 1 if frame is in restricted execution mode
+ f_trace tracing function for this frame, or None"""
+ return isinstance(object, types.FrameType)
+
+def iscode(object):
+ """Return true if the object is a code object.
+
+ Code objects provide these attributes:
+ co_argcount number of arguments (not including * or ** args)
+ co_code string of raw compiled bytecode
+ co_consts tuple of constants used in the bytecode
+ co_filename name of file in which this code object was created
+ co_firstlineno number of first line in Python source code
+ co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
+ co_lnotab encoded mapping of line numbers to bytecode indices
+ co_name name with which this code object was defined
+ co_names tuple of names of local variables
+ co_nlocals number of local variables
+ co_stacksize virtual machine stack space required
+ co_varnames tuple of names of arguments and local variables"""
+ return isinstance(object, types.CodeType)
+
+def isbuiltin(object):
+ """Return true if the object is a built-in function or method.
+
+ Built-in functions and methods provide these attributes:
+ __doc__ documentation string
+ __name__ original name of this function or method
+ __self__ instance to which a method is bound, or None"""
+ return isinstance(object, types.BuiltinFunctionType)
+
+def isroutine(object):
+ """Return true if the object is any kind of function or method."""
+ return (isbuiltin(object)
+ or isfunction(object)
+ or ismethod(object)
+ or ismethoddescriptor(object))
+
+def isabstract(object):
+ """Return true if the object is an abstract base class (ABC)."""
+ return bool(isinstance(object, type) and object.__flags__ & TPFLAGS_IS_ABSTRACT)
+
+def getmembers(object, predicate=None):
+ """Return all members of an object as (name, value) pairs sorted by name.
+ Optionally, only return members that satisfy a given predicate."""
+ results = []
+ for key in dir(object):
+ try:
+ value = getattr(object, key)
+ except AttributeError:
+ continue
+ if not predicate or predicate(value):
+ results.append((key, value))
+ results.sort()
+ return results
+
+Attribute = namedtuple('Attribute', 'name kind defining_class object')
+
+def classify_class_attrs(cls):
+ """Return list of attribute-descriptor tuples.
+
+ For each name in dir(cls), the return list contains a 4-tuple
+ with these elements:
+
+ 0. The name (a string).
+
+ 1. The kind of attribute this is, one of these strings:
+ 'class method' created via classmethod()
+ 'static method' created via staticmethod()
+ 'property' created via property()
+ 'method' any other flavor of method
+ 'data' not a method
+
+ 2. The class which defined this attribute (a class).
+
+ 3. The object as obtained directly from the defining class's
+ __dict__, not via getattr. This is especially important for
+ data attributes: C.data is just a data object, but
+ C.__dict__['data'] may be a data descriptor with additional
+ info, like a __doc__ string.
+ """
+
+ mro = getmro(cls)
+ names = dir(cls)
+ result = []
+ for name in names:
+ # Get the object associated with the name, and where it was defined.
+ # Getting an obj from the __dict__ sometimes reveals more than
+ # using getattr. Static and class methods are dramatic examples.
+ # Furthermore, some objects may raise an Exception when fetched with
+ # getattr(). This is the case with some descriptors (bug #1785).
+ # Thus, we only use getattr() as a last resort.
+ homecls = None
+ for base in (cls,) + mro:
+ if name in base.__dict__:
+ obj = base.__dict__[name]
+ homecls = base
+ break
+ else:
+ obj = getattr(cls, name)
+ homecls = getattr(obj, "__objclass__", homecls)
+
+ # Classify the object.
+ if isinstance(obj, staticmethod):
+ kind = "static method"
+ elif isinstance(obj, classmethod):
+ kind = "class method"
+ elif isinstance(obj, property):
+ kind = "property"
+ elif ismethoddescriptor(obj):
+ kind = "method"
+ elif isdatadescriptor(obj):
+ kind = "data"
+ else:
+ obj_via_getattr = getattr(cls, name)
+ if (ismethod(obj_via_getattr) or
+ ismethoddescriptor(obj_via_getattr)):
+ kind = "method"
+ else:
+ kind = "data"
+ obj = obj_via_getattr
+
+ result.append(Attribute(name, kind, homecls, obj))
+
+ return result
+
+# ----------------------------------------------------------- class helpers
+def _searchbases(cls, accum):
+ # Simulate the "classic class" search order.
+ if cls in accum:
+ return
+ accum.append(cls)
+ for base in cls.__bases__:
+ _searchbases(base, accum)
+
+def getmro(cls):
+ "Return tuple of base classes (including cls) in method resolution order."
+ if hasattr(cls, "__mro__"):
+ return cls.__mro__
+ else:
+ result = []
+ _searchbases(cls, result)
+ return tuple(result)
+
+# -------------------------------------------------- source code extraction
+def indentsize(line):
+ """Return the indent size, in spaces, at the start of a line of text."""
+ expline = string.expandtabs(line)
+ return len(expline) - len(string.lstrip(expline))
+
+def getdoc(object):
+ """Get the documentation string for an object.
+
+ All tabs are expanded to spaces. To clean up docstrings that are
+ indented to line up with blocks of code, any whitespace than can be
+ uniformly removed from the second line onwards is removed."""
+ try:
+ doc = object.__doc__
+ except AttributeError:
+ return None
+ if not isinstance(doc, types.StringTypes):
+ return None
+ return cleandoc(doc)
+
+def cleandoc(doc):
+ """Clean up indentation from docstrings.
+
+ Any whitespace that can be uniformly removed from the second line
+ onwards is removed."""
+ try:
+ lines = string.split(string.expandtabs(doc), '\n')
+ except UnicodeError:
+ return None
+ else:
+ # Find minimum indentation of any non-blank lines after first line.
+ margin = sys.maxint
+ for line in lines[1:]:
+ content = len(string.lstrip(line))
+ if content:
+ indent = len(line) - content
+ margin = min(margin, indent)
+ # Remove indentation.
+ if lines:
+ lines[0] = lines[0].lstrip()
+ if margin < sys.maxint:
+ for i in range(1, len(lines)): lines[i] = lines[i][margin:]
+ # Remove any trailing or leading blank lines.
+ while lines and not lines[-1]:
+ lines.pop()
+ while lines and not lines[0]:
+ lines.pop(0)
+ return string.join(lines, '\n')
+
+def getfile(object):
+ """Work out which source or compiled file an object was defined in."""
+ if ismodule(object):
+ if hasattr(object, '__file__'):
+ return object.__file__
+ raise TypeError('{!r} is a built-in module'.format(object))
+ if isclass(object):
+ object = sys.modules.get(object.__module__)
+ if hasattr(object, '__file__'):
+ return object.__file__
+ raise TypeError('{!r} is a built-in class'.format(object))
+ if ismethod(object):
+ object = object.im_func
+ if isfunction(object):
+ object = object.func_code
+ if istraceback(object):
+ object = object.tb_frame
+ if isframe(object):
+ object = object.f_code
+ if iscode(object):
+ return object.co_filename
+ raise TypeError('{!r} is not a module, class, method, '
+ 'function, traceback, frame, or code object'.format(object))
+
+ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type')
+
+def getmoduleinfo(path):
+ """Get the module name, suffix, mode, and module type for a given file."""
+ filename = os.path.basename(path)
+ suffixes = map(lambda info:
+ (-len(info[0]), info[0], info[1], info[2]),
+ imp.get_suffixes())
+ suffixes.sort() # try longest suffixes first, in case they overlap
+ for neglen, suffix, mode, mtype in suffixes:
+ if filename[neglen:] == suffix:
+ return ModuleInfo(filename[:neglen], suffix, mode, mtype)
+
+def getmodulename(path):
+ """Return the module name for a given file, or None."""
+ info = getmoduleinfo(path)
+ if info: return info[0]
+
+def getsourcefile(object):
+ """Return the filename that can be used to locate an object's source.
+ Return None if no way can be identified to get the source.
+ """
+ filename = getfile(object)
+ if string.lower(filename[-4:]) in ('.pyc', '.pyo'):
+ filename = filename[:-4] + '.py'
+ for suffix, mode, kind in imp.get_suffixes():
+ if 'b' in mode and string.lower(filename[-len(suffix):]) == suffix:
+ # Looks like a binary file. We want to only return a text file.
+ return None
+ if os.path.exists(filename):
+ return filename
+ # only return a non-existent filename if the module has a PEP 302 loader
+ if hasattr(getmodule(object, filename), '__loader__'):
+ return filename
+ # or it is in the linecache
+ if filename in linecache.cache:
+ return filename
+
+def getabsfile(object, _filename=None):
+ """Return an absolute path to the source or compiled file for an object.
+
+ The idea is for each object to have a unique origin, so this routine
+ normalizes the result as much as possible."""
+ if _filename is None:
+ _filename = getsourcefile(object) or getfile(object)
+ return os.path.normcase(os.path.abspath(_filename))
+
+modulesbyfile = {}
+_filesbymodname = {}
+
+def getmodule(object, _filename=None):
+ """Return the module an object was defined in, or None if not found."""
+ if ismodule(object):
+ return object
+ if hasattr(object, '__module__'):
+ return sys.modules.get(object.__module__)
+ # Try the filename to modulename cache
+ if _filename is not None and _filename in modulesbyfile:
+ return sys.modules.get(modulesbyfile[_filename])
+ # Try the cache again with the absolute file name
+ try:
+ file = getabsfile(object, _filename)
+ except TypeError:
+ return None
+ if file in modulesbyfile:
+ return sys.modules.get(modulesbyfile[file])
+ # Update the filename to module name cache and check yet again
+ # Copy sys.modules in order to cope with changes while iterating
+ for modname, module in sys.modules.items():
+ if ismodule(module) and hasattr(module, '__file__'):
+ f = module.__file__
+ if f == _filesbymodname.get(modname, None):
+ # Have already mapped this module, so skip it
+ continue
+ _filesbymodname[modname] = f
+ f = getabsfile(module)
+ # Always map to the name the module knows itself by
+ modulesbyfile[f] = modulesbyfile[
+ os.path.realpath(f)] = module.__name__
+ if file in modulesbyfile:
+ return sys.modules.get(modulesbyfile[file])
+ # Check the main module
+ main = sys.modules['__main__']
+ if not hasattr(object, '__name__'):
+ return None
+ if hasattr(main, object.__name__):
+ mainobject = getattr(main, object.__name__)
+ if mainobject is object:
+ return main
+ # Check builtins
+ builtin = sys.modules['__builtin__']
+ if hasattr(builtin, object.__name__):
+ builtinobject = getattr(builtin, object.__name__)
+ if builtinobject is object:
+ return builtin
+
+def findsource(object):
+ """Return the entire source file and starting line number for an object.
+
+ The argument may be a module, class, method, function, traceback, frame,
+ or code object. The source code is returned as a list of all the lines
+ in the file and the line number indexes a line in that list. An IOError
+ is raised if the source code cannot be retrieved."""
+
+ file = getfile(object)
+ sourcefile = getsourcefile(object)
+ if not sourcefile and file[:1] + file[-1:] != '<>':
+ raise IOError('source code not available')
+ file = sourcefile if sourcefile else file
+
+ module = getmodule(object, file)
+ if module:
+ lines = linecache.getlines(file, module.__dict__)
+ else:
+ lines = linecache.getlines(file)
+ if not lines:
+ raise IOError('could not get source code')
+
+ if ismodule(object):
+ return lines, 0
+
+ if isclass(object):
+ name = object.__name__
+ pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
+ # make some effort to find the best matching class definition:
+ # use the one with the least indentation, which is the one
+ # that's most probably not inside a function definition.
+ candidates = []
+ for i in range(len(lines)):
+ match = pat.match(lines[i])
+ if match:
+ # if it's at toplevel, it's already the best one
+ if lines[i][0] == 'c':
+ return lines, i
+ # else add whitespace to candidate list
+ candidates.append((match.group(1), i))
+ if candidates:
+ # this will sort by whitespace, and by line number,
+ # less whitespace first
+ candidates.sort()
+ return lines, candidates[0][1]
+ else:
+ raise IOError('could not find class definition')
+
+ if ismethod(object):
+ object = object.im_func
+ if isfunction(object):
+ object = object.func_code
+ if istraceback(object):
+ object = object.tb_frame
+ if isframe(object):
+ object = object.f_code
+ if iscode(object):
+ if not hasattr(object, 'co_firstlineno'):
+ raise IOError('could not find function definition')
+ lnum = object.co_firstlineno - 1
+ pat = re.compile(r'^(\s*def\s)|(.*(? 0:
+ if pat.match(lines[lnum]): break
+ lnum = lnum - 1
+ return lines, lnum
+ raise IOError('could not find code object')
+
+def getcomments(object):
+ """Get lines of comments immediately preceding an object's source code.
+
+ Returns None when source can't be found.
+ """
+ try:
+ lines, lnum = findsource(object)
+ except (IOError, TypeError):
+ return None
+
+ if ismodule(object):
+ # Look for a comment block at the top of the file.
+ start = 0
+ if lines and lines[0][:2] == '#!': start = 1
+ while start < len(lines) and string.strip(lines[start]) in ('', '#'):
+ start = start + 1
+ if start < len(lines) and lines[start][:1] == '#':
+ comments = []
+ end = start
+ while end < len(lines) and lines[end][:1] == '#':
+ comments.append(string.expandtabs(lines[end]))
+ end = end + 1
+ return string.join(comments, '')
+
+ # Look for a preceding block of comments at the same indentation.
+ elif lnum > 0:
+ indent = indentsize(lines[lnum])
+ end = lnum - 1
+ if end >= 0 and string.lstrip(lines[end])[:1] == '#' and \
+ indentsize(lines[end]) == indent:
+ comments = [string.lstrip(string.expandtabs(lines[end]))]
+ if end > 0:
+ end = end - 1
+ comment = string.lstrip(string.expandtabs(lines[end]))
+ while comment[:1] == '#' and indentsize(lines[end]) == indent:
+ comments[:0] = [comment]
+ end = end - 1
+ if end < 0: break
+ comment = string.lstrip(string.expandtabs(lines[end]))
+ while comments and string.strip(comments[0]) == '#':
+ comments[:1] = []
+ while comments and string.strip(comments[-1]) == '#':
+ comments[-1:] = []
+ return string.join(comments, '')
+
+class EndOfBlock(Exception): pass
+
+class BlockFinder:
+ """Provide a tokeneater() method to detect the end of a code block."""
+ def __init__(self):
+ self.indent = 0
+ self.islambda = False
+ self.started = False
+ self.passline = False
+ self.last = 1
+
+ def tokeneater(self, type, token, srow_scol, erow_ecol, line):
+ srow, scol = srow_scol
+ erow, ecol = erow_ecol
+ if not self.started:
+ # look for the first "def", "class" or "lambda"
+ if token in ("def", "class", "lambda"):
+ if token == "lambda":
+ self.islambda = True
+ self.started = True
+ self.passline = True # skip to the end of the line
+ elif type == tokenize.NEWLINE:
+ self.passline = False # stop skipping when a NEWLINE is seen
+ self.last = srow
+ if self.islambda: # lambdas always end at the first NEWLINE
+ raise EndOfBlock
+ elif self.passline:
+ pass
+ elif type == tokenize.INDENT:
+ self.indent = self.indent + 1
+ self.passline = True
+ elif type == tokenize.DEDENT:
+ self.indent = self.indent - 1
+ # the end of matching indent/dedent pairs end a block
+ # (note that this only works for "def"/"class" blocks,
+ # not e.g. for "if: else:" or "try: finally:" blocks)
+ if self.indent <= 0:
+ raise EndOfBlock
+ elif self.indent == 0 and type not in (tokenize.COMMENT, tokenize.NL):
+ # any other token on the same indentation level end the previous
+ # block as well, except the pseudo-tokens COMMENT and NL.
+ raise EndOfBlock
+
+def getblock(lines):
+ """Extract the block of code at the top of the given list of lines."""
+ blockfinder = BlockFinder()
+ try:
+ tokenize.tokenize(iter(lines).next, blockfinder.tokeneater)
+ except (EndOfBlock, IndentationError):
+ pass
+ return lines[:blockfinder.last]
+
+def getsourcelines(object):
+ """Return a list of source lines and starting line number for an object.
+
+ The argument may be a module, class, method, function, traceback, frame,
+ or code object. The source code is returned as a list of the lines
+ corresponding to the object and the line number indicates where in the
+ original source file the first line of code was found. An IOError is
+ raised if the source code cannot be retrieved."""
+ lines, lnum = findsource(object)
+
+ if ismodule(object): return lines, 0
+ else: return getblock(lines[lnum:]), lnum + 1
+
+def getsource(object):
+ """Return the text of the source code for an object.
+
+ The argument may be a module, class, method, function, traceback, frame,
+ or code object. The source code is returned as a single string. An
+ IOError is raised if the source code cannot be retrieved."""
+ lines, lnum = getsourcelines(object)
+ return string.join(lines, '')
+
+# --------------------------------------------------- class tree extraction
+def walktree(classes, children, parent):
+ """Recursive helper function for getclasstree()."""
+ results = []
+ classes.sort(key=attrgetter('__module__', '__name__'))
+ for c in classes:
+ results.append((c, c.__bases__))
+ if c in children:
+ results.append(walktree(children[c], children, c))
+ return results
+
+def getclasstree(classes, unique=0):
+ """Arrange the given list of classes into a hierarchy of nested lists.
+
+ Where a nested list appears, it contains classes derived from the class
+ whose entry immediately precedes the list. Each entry is a 2-tuple
+ containing a class and a tuple of its base classes. If the 'unique'
+ argument is true, exactly one entry appears in the returned structure
+ for each class in the given list. Otherwise, classes using multiple
+ inheritance and their descendants will appear multiple times."""
+ children = {}
+ roots = []
+ for c in classes:
+ if c.__bases__:
+ for parent in c.__bases__:
+ if not parent in children:
+ children[parent] = []
+ if c not in children[parent]:
+ children[parent].append(c)
+ if unique and parent in classes: break
+ elif c not in roots:
+ roots.append(c)
+ for parent in children:
+ if parent not in classes:
+ roots.append(parent)
+ return walktree(roots, children, None)
+
+# ------------------------------------------------ argument list extraction
+Arguments = namedtuple('Arguments', 'args varargs keywords')
+
+def getargs(co):
+ """Get information about the arguments accepted by a code object.
+
+ Three things are returned: (args, varargs, varkw), where 'args' is
+ a list of argument names (possibly containing nested lists), and
+ 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
+
+ if not iscode(co):
+ raise TypeError('{!r} is not a code object'.format(co))
+
+ nargs = co.co_argcount
+ names = co.co_varnames
+ args = list(names[:nargs])
+ step = 0
+
+ # The following acrobatics are for anonymous (tuple) arguments.
+ for i in range(nargs):
+ if args[i][:1] in ('', '.'):
+ stack, remain, count = [], [], []
+ while step < len(co.co_code):
+ op = ord(co.co_code[step])
+ step = step + 1
+ if op >= dis.HAVE_ARGUMENT:
+ opname = dis.opname[op]
+ value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
+ step = step + 2
+ if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
+ remain.append(value)
+ count.append(value)
+ elif opname in ('STORE_FAST', 'STORE_DEREF'):
+ if opname == 'STORE_FAST':
+ stack.append(names[value])
+ else:
+ stack.append(co.co_cellvars[value])
+
+ # Special case for sublists of length 1: def foo((bar))
+ # doesn't generate the UNPACK_TUPLE bytecode, so if
+ # `remain` is empty here, we have such a sublist.
+ if not remain:
+ stack[0] = [stack[0]]
+ break
+ else:
+ remain[-1] = remain[-1] - 1
+ while remain[-1] == 0:
+ remain.pop()
+ size = count.pop()
+ stack[-size:] = [stack[-size:]]
+ if not remain: break
+ remain[-1] = remain[-1] - 1
+ if not remain: break
+ args[i] = stack[0]
+
+ varargs = None
+ if co.co_flags & CO_VARARGS:
+ varargs = co.co_varnames[nargs]
+ nargs = nargs + 1
+ varkw = None
+ if co.co_flags & CO_VARKEYWORDS:
+ varkw = co.co_varnames[nargs]
+ return Arguments(args, varargs, varkw)
+
+ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
+
+def getargspec(func):
+ """Get the names and default values of a function's arguments.
+
+ A tuple of four things is returned: (args, varargs, varkw, defaults).
+ 'args' is a list of the argument names (it may contain nested lists).
+ 'varargs' and 'varkw' are the names of the * and ** arguments or None.
+ 'defaults' is an n-tuple of the default values of the last n arguments.
+ """
+
+ if ismethod(func):
+ func = func.im_func
+ if not isfunction(func):
+ raise TypeError('{!r} is not a Python function'.format(func))
+ args, varargs, varkw = getargs(func.func_code)
+ return ArgSpec(args, varargs, varkw, func.func_defaults)
+
+ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')
+
+def getargvalues(frame):
+ """Get information about arguments passed into a particular frame.
+
+ A tuple of four things is returned: (args, varargs, varkw, locals).
+ 'args' is a list of the argument names (it may contain nested lists).
+ 'varargs' and 'varkw' are the names of the * and ** arguments or None.
+ 'locals' is the locals dictionary of the given frame."""
+ args, varargs, varkw = getargs(frame.f_code)
+ return ArgInfo(args, varargs, varkw, frame.f_locals)
+
+def joinseq(seq):
+ if len(seq) == 1:
+ return '(' + seq[0] + ',)'
+ else:
+ return '(' + string.join(seq, ', ') + ')'
+
+def strseq(object, convert, join=joinseq):
+ """Recursively walk a sequence, stringifying each element."""
+ if type(object) in (list, tuple):
+ return join(map(lambda o, c=convert, j=join: strseq(o, c, j), object))
+ else:
+ return convert(object)
+
+def formatargspec(args, varargs=None, varkw=None, defaults=None,
+ formatarg=str,
+ formatvarargs=lambda name: '*' + name,
+ formatvarkw=lambda name: '**' + name,
+ formatvalue=lambda value: '=' + repr(value),
+ join=joinseq):
+ """Format an argument spec from the 4 values returned by getargspec.
+
+ The first four arguments are (args, varargs, varkw, defaults). The
+ other four arguments are the corresponding optional formatting functions
+ that are called to turn names and values into strings. The ninth
+ argument is an optional function to format the sequence of arguments."""
+ specs = []
+ if defaults:
+ firstdefault = len(args) - len(defaults)
+ for i, arg in enumerate(args):
+ spec = strseq(arg, formatarg, join)
+ if defaults and i >= firstdefault:
+ spec = spec + formatvalue(defaults[i - firstdefault])
+ specs.append(spec)
+ if varargs is not None:
+ specs.append(formatvarargs(varargs))
+ if varkw is not None:
+ specs.append(formatvarkw(varkw))
+ return '(' + string.join(specs, ', ') + ')'
+
+def formatargvalues(args, varargs, varkw, locals,
+ formatarg=str,
+ formatvarargs=lambda name: '*' + name,
+ formatvarkw=lambda name: '**' + name,
+ formatvalue=lambda value: '=' + repr(value),
+ join=joinseq):
+ """Format an argument spec from the 4 values returned by getargvalues.
+
+ The first four arguments are (args, varargs, varkw, locals). The
+ next four arguments are the corresponding optional formatting functions
+ that are called to turn names and values into strings. The ninth
+ argument is an optional function to format the sequence of arguments."""
+ def convert(name, locals=locals,
+ formatarg=formatarg, formatvalue=formatvalue):
+ return formatarg(name) + formatvalue(locals[name])
+ specs = []
+ for i in range(len(args)):
+ specs.append(strseq(args[i], convert, join))
+ if varargs:
+ specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))
+ if varkw:
+ specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
+ return '(' + string.join(specs, ', ') + ')'
+
+def getcallargs(func, *positional, **named):
+ """Get the mapping of arguments to values.
+
+ A dict is returned, with keys the function argument names (including the
+ names of the * and ** arguments, if any), and values the respective bound
+ values from 'positional' and 'named'."""
+ args, varargs, varkw, defaults = getargspec(func)
+ f_name = func.__name__
+ arg2value = {}
+
+ # The following closures are basically because of tuple parameter unpacking.
+ assigned_tuple_params = []
+ def assign(arg, value):
+ if isinstance(arg, str):
+ arg2value[arg] = value
+ else:
+ assigned_tuple_params.append(arg)
+ value = iter(value)
+ for i, subarg in enumerate(arg):
+ try:
+ subvalue = next(value)
+ except StopIteration:
+ raise ValueError('need more than %d %s to unpack' %
+ (i, 'values' if i > 1 else 'value'))
+ assign(subarg,subvalue)
+ try:
+ next(value)
+ except StopIteration:
+ pass
+ else:
+ raise ValueError('too many values to unpack')
+ def is_assigned(arg):
+ if isinstance(arg,str):
+ return arg in arg2value
+ return arg in assigned_tuple_params
+ if ismethod(func) and func.im_self is not None:
+ # implicit 'self' (or 'cls' for classmethods) argument
+ positional = (func.im_self,) + positional
+ num_pos = len(positional)
+ num_total = num_pos + len(named)
+ num_args = len(args)
+ num_defaults = len(defaults) if defaults else 0
+ for arg, value in zip(args, positional):
+ assign(arg, value)
+ if varargs:
+ if num_pos > num_args:
+ assign(varargs, positional[-(num_pos-num_args):])
+ else:
+ assign(varargs, ())
+ elif 0 < num_args < num_pos:
+ raise TypeError('%s() takes %s %d %s (%d given)' % (
+ f_name, 'at most' if defaults else 'exactly', num_args,
+ 'arguments' if num_args > 1 else 'argument', num_total))
+ elif num_args == 0 and num_total:
+ if varkw:
+ if num_pos:
+ # XXX: We should use num_pos, but Python also uses num_total:
+ raise TypeError('%s() takes exactly 0 arguments '
+ '(%d given)' % (f_name, num_total))
+ else:
+ raise TypeError('%s() takes no arguments (%d given)' %
+ (f_name, num_total))
+ for arg in args:
+ if isinstance(arg, str) and arg in named:
+ if is_assigned(arg):
+ raise TypeError("%s() got multiple values for keyword "
+ "argument '%s'" % (f_name, arg))
+ else:
+ assign(arg, named.pop(arg))
+ if defaults: # fill in any missing values with the defaults
+ for arg, value in zip(args[-num_defaults:], defaults):
+ if not is_assigned(arg):
+ assign(arg, value)
+ if varkw:
+ assign(varkw, named)
+ elif named:
+ unexpected = next(iter(named))
+ try:
+ unicode
+ except NameError:
+ pass
+ else:
+ if isinstance(unexpected, unicode):
+ unexpected = unexpected.encode(sys.getdefaultencoding(), 'replace')
+ raise TypeError("%s() got an unexpected keyword argument '%s'" %
+ (f_name, unexpected))
+ unassigned = num_args - len([arg for arg in args if is_assigned(arg)])
+ if unassigned:
+ num_required = num_args - num_defaults
+ raise TypeError('%s() takes %s %d %s (%d given)' % (
+ f_name, 'at least' if defaults else 'exactly', num_required,
+ 'arguments' if num_required > 1 else 'argument', num_total))
+ return arg2value
+
+# -------------------------------------------------- stack frame extraction
+
+Traceback = namedtuple('Traceback', 'filename lineno function code_context index')
+
+def getframeinfo(frame, context=1):
+ """Get information about a frame or traceback object.
+
+ A tuple of five things is returned: the filename, the line number of
+ the current line, the function name, a list of lines of context from
+ the source code, and the index of the current line within that list.
+ The optional second argument specifies the number of lines of context
+ to return, which are centered around the current line."""
+ if istraceback(frame):
+ lineno = frame.tb_lineno
+ frame = frame.tb_frame
+ else:
+ lineno = frame.f_lineno
+ if not isframe(frame):
+ raise TypeError('{!r} is not a frame or traceback object'.format(frame))
+
+ filename = getsourcefile(frame) or getfile(frame)
+ if context > 0:
+ start = lineno - 1 - context//2
+ try:
+ lines, lnum = findsource(frame)
+ except IOError:
+ lines = index = None
+ else:
+ start = max(start, 1)
+ start = max(0, min(start, len(lines) - context))
+ lines = lines[start:start+context]
+ index = lineno - 1 - start
+ else:
+ lines = index = None
+
+ return Traceback(filename, lineno, frame.f_code.co_name, lines, index)
+
+def getlineno(frame):
+ """Get the line number from a frame object, allowing for optimization."""
+ # FrameType.f_lineno is now a descriptor that grovels co_lnotab
+ return frame.f_lineno
+
+def getouterframes(frame, context=1):
+ """Get a list of records for a frame and all higher (calling) frames.
+
+ Each record contains a frame object, filename, line number, function
+ name, a list of lines of context, and index within the context."""
+ framelist = []
+ while frame:
+ framelist.append((frame,) + getframeinfo(frame, context))
+ frame = frame.f_back
+ return framelist
+
+def getinnerframes(tb, context=1):
+ """Get a list of records for a traceback's frame and all lower frames.
+
+ Each record contains a frame object, filename, line number, function
+ name, a list of lines of context, and index within the context."""
+ framelist = []
+ while tb:
+ framelist.append((tb.tb_frame,) + getframeinfo(tb, context))
+ tb = tb.tb_next
+ return framelist
+
+if hasattr(sys, '_getframe'):
+ currentframe = sys._getframe
+else:
+ currentframe = lambda _=None: None
+
+def stack(context=1):
+ """Return a list of records for the stack above the caller's frame."""
+ return getouterframes(sys._getframe(1), context)
+
+def trace(context=1):
+ """Return a list of records for the stack below the current exception."""
+ return getinnerframes(sys.exc_info()[2], context)
diff --git a/python3.7libs/searcher/language_en.py b/python3.7libs/searcher/language_en.py
new file mode 100644
index 0000000..6c49b7b
--- /dev/null
+++ b/python3.7libs/searcher/language_en.py
@@ -0,0 +1,69 @@
+# SECTION Language US
+language = "en"
+
+
+# NOTE Tooltips
+TT_MW = {
+ "searchbox": "Begin typing to search or click magnifying glass icon to display options",
+ "contexttoggle": "Toggle to enable or disable the 'context' column in the search results",
+ "pinwindow": "Pin the search window to keep it from closing automatically when losing focus",
+ "searchfilter": "Select a predefined filter",
+ "opensettingstool": "General application settings",
+ "searchresultstree": "Press tab to highlight or double click an action to attempt to perform it. Some actions only work in specific contexts",
+ "helpButton": "Open help panel",
+ "metricposmain": "Change the position of metrics to Houdinis main window",
+ "metricposself": "Change the position of metrics to Searchers window",
+ "expand_all": "Expand all tree items",
+ "collapse_all": "Collapse all tree items",
+}
+
+# NOTE Tooltops Settings
+TT_SETTINGS = {
+ "about": "Contact and other info",
+ "projectTitle": "Thanks for using Searcher!",
+ "lang_cbox": "When translations become available they can be selected here",
+ "inmemory_chk": "Enable to use an in-memory database instead of SQLite file",
+ "windowsize_chk": "Enable to save the size and location of the main window upon closing. Defaults to center (1000px, 600px)",
+ "maxresults_lbl": "Maximum results to load per query as you type your search term. (Too many can make results feel sluggish)",
+ "maxresults_txt": "Maximum results to load per query as you type your search term (Too many can make results feel sluggish)",
+ "animatedsettings_chk": "Enables animated menus",
+ "dbpath_icon": "Select the location to store the Searcher database",
+ "dbpath_lbl": "The location in which Searcher stores it's database file",
+ "databasepath_txt": "The location in which Searcher stores it's database file",
+ "defaulthotkey_lbl": "Key used to trigger unbound actions",
+ "defaulthotkey_txt": "Key used to trigger unbound actions",
+ "cleardata_btn": "If, for some reason, Searcher is having issues this function will clear out the database and start fresh",
+ "save_btn": "Save your settings",
+ "discard_btn": "Disgard settings changes",
+ "debugflag_chk": "Toggle debug messages",
+ "debuglevel_cbx": "Select level of debugging",
+ "bugreport": "Bug report form",
+ "theme": "Change colors",
+ "metrics_chk": "Enable performance metrics to view query and render times",
+}
+
+# NOTE database - General Errors
+DBERRORMSG = {
+ "cleardatabase": "Could not clear db for refresh: ",
+ "updatecontext": "Could not update Searcher context database: ",
+ "updatechangeindex": "Could not update Searcher context database: ",
+ "getlastusedhk1": "Could not query last assigned temp hotkey: ",
+ "getlastusedhk2": "Could not clear last assigned temp hotkey: ",
+ "getlastusedh3": "Could not clear last assigned temp hotkey on last attempt: ",
+ "getchangeindex": "Could not get Searcher changeindex: ",
+}
+
+# NOTE 456 - Initial setup
+MESSAGES = {
+ "initialsetup1": "Searcher database created",
+ "initialsetup2": "Searcher database created and populated",
+ "createdefaults": "Searcher database created and populated",
+}
+
+# NOTE settings_data - Save/Load
+SETTINGSMESSAGES = {
+ "savesettings": "Could not save settings: ",
+ "loadsettings": "Could not load settings: ",
+}
+
+# !SECTION
diff --git a/python3.7libs/searcher/nodegraphhooks.py b/python3.7libs/searcher/nodegraphhooks.py
new file mode 100644
index 0000000..c6a0a9c
--- /dev/null
+++ b/python3.7libs/searcher/nodegraphhooks.py
@@ -0,0 +1,62 @@
+import os
+
+import sys
+
+sys.dont_write_bytecode = True
+
+import hou
+
+from PySide2 import QtWidgets
+
+from houdini_markingmenu import markingmenu as mm
+
+from canvaseventtypes import *
+
+import nodegraphbase as base
+
+sys.path.insert(0, os.path.join(hou.getenv('HOUDINI_USER_PREF_DIR'),
+ 'python2.7libs',
+ 'houdini_markingmenu'))
+
+import buttonfunctions as cmds
+
+def buildHandler(uievent, pending_actions):
+ import nodegraph # to avoid circular imports
+ class MarkingMenuMouseHandler(nodegraph.NodeMouseHandler):
+ def handleEvent(self, uievent, pending_actions):
+ if isinstance(uievent, MouseEvent) and uievent.eventtype == 'mousedrag':
+ reload(mm)
+ for entry in QtWidgets.QApplication.instance().allWidgets():
+ if type(entry).__name__ == 'NEMarkingMenu':
+ entry.setParent(None)
+ entry.close()
+ markingMenu = mm.NEMarkingMenu(uievent.editor)
+ # return None if we handled event and launched a marking menu
+ return None
+ # Return traditional nodegraph rmb handling if we didn't launch a marking menu
+ # If an input, output, or dependancy arrow was right clicked, for example.
+ return nodegraph.NodeMouseHandler.handleEvent(
+ self, uievent, pending_actions)
+ return MarkingMenuMouseHandler(uievent)
+
+# We catch the mousedown event and then further handling is done by our custom class
+# createEventHandler catches mouse events and either does stuff
+# and/or returns an eventHandler class with a handleEvent() method that
+# handles the events until completion of the event or hands it off to a different handler
+
+# createEventHandler catches events (see "Extending the Network Editor docs page")
+# every time an event is registered, we check to see if it's a right mouse button being held down
+# if it is, we check to see if our menu variable is set to 1
+# if our menu is on, then we call our custom function that wil ultimately open our menu window
+
+
+def createEventHandler(uievent, pending_actions):
+ if isinstance(uievent, MouseEvent) and uievent.eventtype == 'mousedown' and uievent.mousestate.rmb:
+ reload(cmds)
+ if uievent.selected.item is None:
+ if cmds.MENU_ACTIVATE:
+ a = buildHandler(uievent, pending_actions)
+ return a, True
+ else:
+ return None, False
+ return None, False
\ No newline at end of file
diff --git a/python3.7libs/searcher/platformselect.py b/python3.7libs/searcher/platformselect.py
new file mode 100644
index 0000000..4e44bd2
--- /dev/null
+++ b/python3.7libs/searcher/platformselect.py
@@ -0,0 +1,31 @@
+import os
+import sys
+import platform
+import ctypes
+
+PLATFORM = None
+SEARCHER_PATH = os.environ["SEARCHER"]
+
+def get_platform():
+ """Returns a string for the current platform"""
+ global PLATFORM
+
+ if PLATFORM is None:
+ p = sys.platform
+ if p == 'darwin':
+ PLATFORM = 'darwin'
+ elif p.startswith('win'):
+ PLATFORM = 'windows'
+ else:
+ PLATFORM = 'unix'
+
+ return PLATFORM
+
+def get_sqlite():
+ if get_platform() == "windows":
+ path_sqlite_dll = os.path.join(SEARCHER_PATH, 'dso/sqlite3.dll')
+ ctypes.cdll.LoadLibrary(path_sqlite_dll)
+ elif get_platform() == "Darwin":
+ path_sqlite_dll = os.path.join(SEARCHER_PATH, 'python27/dlls/sqlite3.dll')
+ else:
+ path_sqlite_dll = os.path.join(SEARCHER_PATH, 'python27/dlls/sqlite3.dll')
diff --git a/python3.7libs/searcher/ptime.py b/python3.7libs/searcher/ptime.py
new file mode 100644
index 0000000..450e6fd
--- /dev/null
+++ b/python3.7libs/searcher/ptime.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+"""
+ptime.py - Precision time function made os-independent (should have been taken care of by python)
+Copyright 2010 Luke Campagnola
+Distributed under MIT/X11 license. See license.txt for more infomation.
+"""
+
+
+import sys
+
+if sys.version_info[0] < 3:
+ from time import clock
+ from time import time as system_time
+else:
+ from time import perf_counter as clock
+ from time import time as system_time
+
+START_TIME = None
+time = None
+
+def winTime():
+ """Return the current time in seconds with high precision (windows version, use Manager.time() to stay platform independent)."""
+ return clock() - START_TIME
+ #return systime.time()
+
+def unixTime():
+ """Return the current time in seconds with high precision (unix version, use Manager.time() to stay platform independent)."""
+ return system_time()
+
+if sys.platform.startswith('win'):
+ cstart = clock() ### Required to start the clock in windows
+ START_TIME = system_time() - cstart
+
+ time = winTime
+else:
+ time = unixTime
\ No newline at end of file
diff --git a/python3.7libs/searcher/searcher.py b/python3.7libs/searcher/searcher.py
new file mode 100644
index 0000000..527c13e
--- /dev/null
+++ b/python3.7libs/searcher/searcher.py
@@ -0,0 +1,1685 @@
+# ---------------------------------------------------------------- Imports
+# SECTION Imports --------------------------------------------------------
+from __future__ import print_function
+from __future__ import absolute_import
+from __future__ import division
+
+from searcher import util
+from searcher import style
+from searcher import ptime
+from searcher import animator
+from searcher import database
+from searcher import HelpButton
+from searcher import datahandler
+from searcher import searcher_ui
+from searcher import settings_data
+from searcher import searcher_settings
+from searcher import searcher_settings_ui
+from searcher import language_en as la
+
+import os
+import re
+import sys
+import hou
+import threading
+import hdefereval as hd
+from hutil.py23 import reload
+# noinspection PyUnresolvedReferences
+from canvaseventtypes import *
+from collections import Iterable
+
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.')+1:])
+ from hutil.Qt import QtGui
+ from hutil.Qt import QtCore
+ from hutil.Qt import QtWidgets
+else:
+ from qtpy import QtGui
+ from qtpy import QtCore
+ from qtpy import QtWidgets
+
+reload(searcher_settings_ui)
+reload(searcher_settings)
+reload(settings_data)
+reload(searcher_ui)
+reload(datahandler)
+reload(HelpButton)
+reload(animator)
+reload(database)
+reload(style)
+reload(ptime)
+reload(util)
+reload(la)
+
+# !SECTION Imports
+
+
+# ---------------------------------------------------------------- Globals
+# SECTION Globals --------------------------------------------------------
+# ----------------------------------------------- Variables
+# NOTE Variables ------------------------------------------
+kwargs = {}
+settings = {}
+hasran = False
+mousePos = None
+cur_screen = QtWidgets.QDesktopWidget().screenNumber(
+ QtWidgets.QDesktopWidget().cursor().pos()
+)
+screensize = QtWidgets.QDesktopWidget().screenGeometry(cur_screen)
+centerPoint = QtWidgets.QDesktopWidget().availableGeometry(cur_screen).center()
+
+sys.path.append(os.path.join(os.path.dirname(__file__)))
+script_path = os.path.dirname(os.path.realpath(__file__))
+name = "Searcher"
+
+parent_widget = hou.qt.mainWindow()
+
+
+# ----------------------------------------------- Functions
+# NOTE Functions ------------------------------------------
+def get_settings():
+ return getattr(hou.session, "SETTINGS", None)
+
+
+def get_dbhandler():
+ return getattr(hou.session, "DBHANDLER", None)
+
+
+def keyconversion(key):
+ for i in range(len(key)):
+ if key[i] in util.KEYCONVERSIONS:
+ key[i] = util.KEYCONVERSIONS[key[i]]
+ return key
+
+
+# !SECTION Globals
+
+# --------------------------------------------------------- Searcher Class
+# SECTION Searcher Class -------------------------------------------------
+# noinspection PyUnresolvedReferences
+class Searcher(QtWidgets.QWidget):
+ """instance.id Searcher for Houdini"""
+
+ # --------------------------------------------------------- Class init
+ # SECTION Class init -------------------------------------------------
+ def __init__(self, settings, windowsettings, animated, kwargs):
+ super(Searcher, self).__init__(parent=hou.qt.mainWindow())
+ # self.timerprofile = None # ANCHOR hou perf timer
+ # self.loadhevent = None # ANCHOR hou perf timer
+
+ # -------------------------- Constructed
+ # NOTE Constructed ----------------------
+ self.goalnum = 7
+ self.kwargs = kwargs
+ self.animated = animated
+ self.settingdata = settings
+ self.searcher_window = self
+ self.parentwindow = hou.qt.mainWindow()
+ self.windowsettings = windowsettings
+
+ # -------------------------- Setting vars
+ # NOTE Setting vars----------------------
+ self.isdebug = util.Dbug(
+ self.settingdata[util.SETTINGS_KEYS[4]],
+ str(self.settingdata[util.SETTINGS_KEYS[10]]),
+ self.settingdata[util.SETTINGS_KEYS[12]],
+ self.settingdata[util.SETTINGS_KEYS[13]],
+ )
+
+ self._drag_active = False
+ self.animationDuration = 200
+ self.app = QtWidgets.QApplication.instance()
+ self.settingslayout = QtWidgets.QVBoxLayout()
+ self.showctx = self.settingdata[util.SETTINGS_KEYS[7]]
+ self.windowispin = self.settingdata[util.SETTINGS_KEYS[5]]
+ self.originalsize = self.settingdata[util.SETTINGS_KEYS[3]]
+ self.expanditems = self.settingdata[util.SETTINGS_KEYS[15]]
+ self.animatedsettings = self.settingdata[util.SETTINGS_KEYS[8]]
+ self.appcolors = util.AppColors(self.settingdata[util.SETTINGS_KEYS[14]])
+
+ if self.animatedsettings:
+ self.uiwidth = int(520)
+ self.uiheight = int(300)
+ else:
+ self.uiwidth = int(520)
+ self.uiheight = int(242)
+
+ # ------------------------------------ Function Vars
+ # NOTE Function Vars -------------------------------
+ self.hotkeys = []
+ self.lastused = {}
+ self.context_list = []
+ self.hcontext_tli = {}
+
+ self.tmpkey = None
+ self.getpane = None
+ self.tiptimer = None
+ self.resizing = False
+ self.mouseout = False
+ self.tmpsymbol = None
+ self.searching = False
+ self.ctxsearch = False
+ self.showglobal = True
+ self.menuopened = False
+ self.overhandle = False
+ self.previous_pos = None
+ self.searchprefix = False
+ self.keys_changed = False
+ self.holdinfobanner = False
+ self.searchdescription = False
+ self.searchcurrentcontext = False
+
+ # --------------------------------- Performance Vars
+ # NOTE Performance Vars ----------------------------
+ self.endtime = 0
+ self.starttime = 0
+ self.treecatnum = 0
+ self.hotkeystime = 0
+ self.regtimetotal = 0
+ self.hcontexttime = 0
+ self.treeitemsnum = 0
+ self.threadtimer = None
+
+ # ---------------------------------- Init Functions
+ # NOTE Init Functionss -----------------------------
+ self.handler = self.initialsetup()
+ self.ui = searcher_settings.SearcherSettings(
+ self.handler,
+ self.uiwidth,
+ self.uiheight,
+ self
+ )
+ if self.animatedsettings:
+ self.anim = animator.Animator(self.ui, self.anim_complete)
+
+ hou.hotkeys._createBackupTables()
+ self.uisetup()
+ self.addshortcuts()
+ self.buildsettingsmenu()
+
+ # !SECTION Class init
+
+ def getwidgets(self):
+ from searcher import debugutils as dbug
+ reload(dbug)
+ data = ""
+
+ for shelf in hou.shelves.shelves().values():
+ data += ("Shelf name: %s -------------------------- \n" % shelf)
+ for tool in shelf.tools():
+ data += ("Tool name: %s \n" % tool.name())
+ data += ("Tool label: %s \n" % tool.label())
+ data += ("Tool keywords: %s \n" % tool.script())
+ # data += ("Tool toolMenuLocations: %s \n" % tool.toolMenuOpType())
+
+ outputpath = os.path.join(
+ hou.homeHoudiniDirectory(), 'Searcher', "output.json"
+ )
+ # info = hou.ui.viewerStateInfo()
+ sample = open(outputpath, 'w')
+ print(data, file=sample)
+ sample.close()
+ # print(info)
+
+ # shelfkeys = hou.shelves.tools().keys()
+ # tools = hou.shelves.tools()
+
+ # for i in range(0, 10):
+ # tool = tools[shelfkeys[i]]
+ # print("Tool: %s" % tool)
+ # for t in tool:
+ # print("Tool data: %s" % t)
+ # tools = tools[shelfkeys[t]]
+ # print("Tool data: %s" % tool[t])
+
+ # toolkeys = tool.keys()
+ # print("Tool keys: %s" % toolkeys)
+ # print(shelfkeys[i])
+
+ # runningtool = hou.shelves.runningTool()
+ # print(runningtool)
+
+ print(self.kwargs)
+ if "editor" in self.kwargs:
+ print(self.kwargs["editor"].pwd())
+
+ # print(hou.shelves.tools().keys())
+
+ pos = QtGui.QCursor.pos()
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Position: X:%d Y: %d" % (pos.x(), pos.y()))
+
+ mainwin = QtWidgets.QApplication
+ undermouse = util.widgets_at(mainwin, pos)
+
+ widgetdata = ""
+ outputpath2 = os.path.join(
+ hou.homeHoudiniDirectory(), 'Searcher', "widgets.json"
+ )
+ sample2 = open(outputpath2, 'w')
+ for w in undermouse:
+ print(dbug.dumpWidgetLayout(w, "_____"), file=sample2)
+ if w.windowTitle() != "":
+ print("Title: %s" % w.windowTitle())
+
+ sample2.close()
+
+ # allWidgets = QtWidgets.QApplication.allWidgets()
+ # for w in allWidgets:
+ # if w.windowTitle() != "":
+ # print("Title: %s" % w.windowTitle())
+
+ # outputpath = os.path.join(
+ # hou.homeHoudiniDirectory(), 'Searcher', "output.json"
+ # )
+ # info = hou.ui.viewerStateInfo()
+ # sample = open(outputpath, 'w')
+ # print(info, file = sample)
+ # sample.close()
+ # print(info)
+
+ # ------------------------------------------------------ Settings Menu
+ # SECTION Settings Menu ----------------------------------------------
+ # ----------------------------------- buildsettingsmenu
+ # NOTE buildsettingsmenu ------------------------------
+ def buildsettingsmenu(self):
+ self.ui.setWindowFlags(
+ QtCore.Qt.Tool
+ | QtCore.Qt.CustomizeWindowHint
+ | QtCore.Qt.FramelessWindowHint
+ )
+ self.ui.setAttribute(QtCore.Qt.WA_StyledBackground, True)
+ if self.settingdata[util.SETTINGS_KEYS[8]]:
+ self.ui.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
+ self.ui.setStyleSheet(style.SETTINGSMENU)
+
+ self.settingslayout = self.ui.settingslayout
+ if self.animatedsettings:
+ self.anim.setContentLayout(self.settingslayout)
+ self.anim.resize(
+ self.uiwidth,
+ self.uiheight
+ )
+ self.ui.resize(
+ self.uiwidth,
+ self.uiheight
+ )
+
+ # !SECTION Settings Menu
+
+ # ----------------------------------------------------------------- UI
+ # SECTION UI ---------------------------------------------------------
+ # -------------------------------------------- UI Setup
+ # SECTION UI Setup ------------------------------------
+ def uisetup(self):
+ names = ["open", "save", "hotkey", "perference"]
+ # self.completer = QtWidgets.QCompleter(names)
+ self.completer = QtWidgets.QCompleter(names)
+ self.completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
+ self.completer.setModel(QtWidgets.QDirModel(self.completer))
+ self.completer.setCompletionMode(self.completer.InlineCompletion)
+
+ self.sui = searcher_ui.Ui_Searcher()
+ self.sui.setupUi(self, self.animated)
+ self.sui.mainlayout.addLayout(self.sui.gridLayout)
+ self.setLayout(self.sui.mainlayout)
+
+ # ---------------------------------- UI Connections
+ # NOTE UI Connections -----------------------------
+ self.helpButton = self.sui.helpButton
+
+ # ------------------------------------- Result Tree
+ # NOTE Result Tree --------------------------------
+ self.searchresultstree = self.sui.searchresults_tree
+ self.searchresultstree.itemActivated.connect(self.searchclick_cb)
+
+ # -------------------------------------- Search Box
+ # NOTE Search Box ---------------------------------
+ self.searchbox = self.sui.searchbox_txt
+ self.searchbox.textChanged.connect(self.textchange_cb)
+ self.searchbox.customContextMenuRequested.connect(self.openmenu)
+ self.searchbox.setPlaceholderText(" Begin typing to search..")
+ self.searchbox.setFocusPolicy(QtCore.Qt.StrongFocus)
+ self.searchbox.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
+ self.searchbox.setClearButtonEnabled(True)
+ self.searchbox.setCompleter(self.completer)
+
+ # ----------------------------------- Search Filter
+ # NOTE Search Filter ------------------------------
+ self.searchfilter = self.sui.searchfilter_btn
+ self.searchfilter.clicked.connect(self.searchfilter_cb)
+ self.searchfilter.setFixedWidth(26)
+ self.searchfilter.setFixedHeight(26)
+ self.searchfilter.setProperty("flat", True)
+ self.searchfilter.setIcon(util.SEARCH_ICON)
+ self.searchfilter.setIconSize(QtCore.QSize(
+ hou.ui.scaledSize(16),
+ hou.ui.scaledSize(16)
+ ))
+
+ # ----------------------------------- Item Expander
+ # NOTE Item Expander ------------------------------
+ self.expander = self.sui.expander
+ self.setexpandericon()
+ self.expander.clicked.connect(self.expander_cb)
+ expander_button_size = hou.ui.scaledSize(18)
+ self.expander.setProperty("flat", True)
+ self.expander.setIconSize(QtCore.QSize(
+ expander_button_size,
+ expander_button_size
+ ))
+
+ # -------------------------------------- Metric Pos
+ # NOTE Metric Pos ---------------------------------
+ self.metricpos = self.sui.metricpos
+ self.setmetricicon()
+ self.metricpos.clicked.connect(self.metricpos_cb)
+ metricpos_button_size = hou.ui.scaledSize(16)
+ self.metricpos.setProperty("flat", True)
+ self.metricpos.setIconSize(QtCore.QSize(
+ metricpos_button_size,
+ metricpos_button_size
+ ))
+ self.metricpos.setVisible(self.settingdata[util.SETTINGS_KEYS[12]])
+
+ # ---------------------------------- Context Toggle
+ # NOTE Context Toggle -----------------------------
+ self.contexttoggle = self.sui.contexttoggle
+ self.contexttoggle.clicked[bool].connect(self.showctx_cb)
+ self.contexttoggle.setCheckable(True)
+ self.contexttoggle.setChecked(self.showctx)
+ self.contexttoggle.setFixedWidth(20)
+ self.contexttoggle.setFixedHeight(20)
+ contexttoggle_button_size = hou.ui.scaledSize(16)
+ self.contexttoggle.setProperty("flat", True)
+ self.contexttoggle.setIconSize(QtCore.QSize(
+ contexttoggle_button_size,
+ contexttoggle_button_size
+ ))
+ self.setctxicon()
+ self.contexttoggle.setStyleSheet(style.CONTEXTTOGGLE)
+
+ # -------------------------------------- Pin Window
+ # NOTE Pin Window ---------------------------------
+ self.pinwindow = self.sui.pinwindow_btn
+ self.setpinicon()
+ self.pinwindow.clicked.connect(self.pinwindow_cb)
+ pinwindow_button_size = hou.ui.scaledSize(16)
+ self.pinwindow.setProperty("flat", True)
+ self.pinwindow.setIconSize(QtCore.QSize(
+ pinwindow_button_size,
+ pinwindow_button_size
+ ))
+
+ # ----------------------------------- Settings Menu
+ # NOTE Settings Menu ------------------------------
+ self.opensettingstool = self.sui.opensettings_btn
+ self.opensettingstool.setCheckable(True)
+ self.opensettingstool.setChecked(False)
+ self.opensettingstool.clicked.connect(self.opensettings_cb)
+ opensettingstool_button_size = hou.ui.scaledSize(16)
+ self.opensettingstool.setProperty("flat", True)
+ self.opensettingstool.setIcon(util.SETTINGS_ICON)
+ self.opensettingstool.setIconSize(QtCore.QSize(
+ opensettingstool_button_size,
+ opensettingstool_button_size
+ ))
+
+ # ---------------------------------------- Info Bar
+ # NOTE Info Bar -----------------------------------
+ self.infolbl = self.sui.info_lbl
+ self.treetotal_lbl = self.sui.treetotal_lbl
+
+ # ---------------------------------- Resize Handles
+ # NOTE Resize Handles -----------------------------
+ self.leftresize = self.sui.leftresize
+ self.rightresize = self.sui.rightresize
+
+ # ---------------------------------------- Tooltips
+ # NOTE Tooltips -----------------------------------
+ self.searchbox.setToolTip(la.TT_MW[self.searchbox.objectName()])
+ self.contexttoggle.setToolTip(la.TT_MW[self.contexttoggle.objectName()])
+ self.pinwindow.setToolTip(la.TT_MW[self.pinwindow.objectName()])
+ self.searchfilter.setToolTip(la.TT_MW[self.searchfilter.objectName()])
+ self.opensettingstool.setToolTip(la.TT_MW[self.opensettingstool.objectName()])
+ self.searchresultstree.setToolTip(la.TT_MW[self.searchresultstree.objectName()])
+
+ self.setupresulttree()
+ self.searchbox.setFocus()
+ self.searchbox.grabKeyboard()
+
+ # !SECTION UI Setup
+
+ # ----------------------------------- Setup Result Tree
+ # NOTE Setup Result Tree ------------------------------
+ def setupresulttree(self):
+ cols = 4
+ self.searchresultstree.setColumnCount(cols)
+ self.searchresultstree.setColumnWidth(0, 250)
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ self.searchresultstree.setColumnWidth(1, 350)
+ else:
+ self.searchresultstree.setColumnWidth(1, 450)
+ self.searchresultstree.setColumnWidth(2, 100)
+ self.searchresultstree.setColumnWidth(3, 150)
+ self.searchresultstree.setColumnWidth(4, 150)
+ self.searchresultstree.setHeaderLabels([
+ "Label",
+ "Description",
+ "Assignments",
+ "Symbol",
+ "Context"
+ ])
+ self.searchresultstree.setColumnHidden(3, self.showctx)
+ if not self.isdebug.level in {"ALL"}:
+ self.searchresultstree.hideColumn(4)
+
+ self.searchresultstree.header().setMinimumSectionSize(85)
+ self.searchresultstree.header().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
+ self.searchresultstree.header().setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
+ self.searchresultstree.header().setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
+ self.searchresultstree.header().setSectionResizeMode(3, QtWidgets.QHeaderView.Stretch)
+ self.searchresultstree.header().setSectionResizeMode(4, QtWidgets.QHeaderView.ResizeToContents)
+ self.searchresultstree.setStyleSheet(style.gettreeviewstyle())
+
+ # --------------------------------------------------- Search Menu
+ # SECTION Search Menu -------------------------------------------
+ # -------------------------------------------- openmenu
+ # NOTE openmenu ---------------------------------------
+ def openmenu(self):
+ self.menuopened = True
+ self.searchmenu = QtWidgets.QMenu()
+ self.searchmenu.setProperty('flat', True)
+ self.searchmenu.setStyleSheet(style.MENUSTYLE)
+ self.searchmenu.setWindowFlags(
+ self.searchmenu.windowFlags() |
+ QtCore.Qt.NoDropShadowWindowHint |
+ QtCore.Qt.X11BypassWindowManagerHint
+ )
+ self.globalprefix = self.searchmenu.addAction("Global items")
+ self.contextprefix = self.searchmenu.addAction("Context items")
+ self.viewprefix = self.searchmenu.addAction("View items")
+
+ self.globalprefix.setToolTip(
+ "View application-wide actions")
+
+ self.contextprefix.setToolTip(
+ "Shows possible actions for the view in which the mouse was in when the window was opened")
+
+ self.viewprefix.setToolTip(
+ "Shows the available view panes (ex. Scene View, Render View, Composit View, etc")
+
+ self.searchmenu.hovered.connect(self.handlemenuhovered)
+
+ self.action = self.searchmenu.exec_(
+ self.searchbox.mapToGlobal(QtCore.QPoint(0, 29)))
+ if self.action == self.globalprefix:
+ self.searchbox.setText(":g")
+ if self.action == self.contextprefix:
+ self.searchbox.setText(":c")
+ if self.action == self.viewprefix:
+ self.searchbox.setText(":v")
+
+ self.searchmenu.installEventFilter(self)
+
+ # ----------------------------------- handlemenuhovered
+ # NOTE handlemenuhovered ------------------------------
+ def handlemenuhovered(self, action):
+ self.setinfotext(200, action.toolTip())
+
+ # !SECTION Search Menu
+ # !SECTION UI
+
+ # ---------------------------------------------------------- Functions
+ # SECTION Functions --------------------------------------------------
+ # ---------------------------------------- setstatusmsg
+ # NOTE setstatusmsg -----------------------------------
+ def setstatusmsg(self, msg, severity):
+ if self.isdebug.mainwindow:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ message=(str(msg)), severity=severity)
+ else:
+ print(str(msg))
+ else:
+ styledmsg, severitytype = style.setstatusmsg(msg, severity)
+ self.setinfotext(200, styledmsg, True)
+
+ # ----------------------------------------- setinfotext
+ # NOTE setinfotext ------------------------------------
+ def setinfotext(self, duration, text, status=False):
+ if not status: text = style.gettooltipstyle(text)
+ self.infolbl.setStyleSheet(style.INFOLABEL)
+ self.infolbl.setText(text)
+ self.fade_in(self.infolbl, duration)
+
+ # ----------------------------------------- count_chars
+ # NOTE count_chars ------------------------------------
+ def count_chars(self, txt):
+ result = 0
+ for char in txt:
+ result += 1 # same as result = result + 1
+ return result
+
+ # --------------------------------------- Initial Setup
+ # NOTE Initial Setup ----------------------------------
+ def initialsetup(self):
+ self.handler = get_dbhandler()
+ if not self.handler:
+ hou.session.DBHANDLER = datahandler.DataHandler(self.isdebug)
+ self.handler = get_dbhandler()
+
+ currentidx = hou.hotkeys.changeIndex()
+ chindex = self.handler.getchangeindex()
+
+ if len(chindex) == 0:
+ chindex = int(currentidx)
+ self.handler.updatechangeindex(chindex, True)
+ self.handler.updatedataasync(self.isdebug)
+ hou.ui.setStatusMessage(
+ "Searcher database created",
+ severity=hou.severityType.Message
+ )
+ else:
+ chindex = int(chindex[0][0])
+
+ if int(currentidx) != chindex:
+ self.handler.updatedataasync(self.isdebug)
+ self.handler.updatechangeindex(int(currentidx))
+
+ return self.handler
+
+ # --------------------------------------------- getnode
+ # NOTE getnode ----------------------------------------
+ def getnode(self):
+ nodeSelect = hou.selectedNodes()
+ for node in nodeSelect:
+ getName = node.name()
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print(getName)
+
+ # ---------------------------------------------- getpane
+ # NOTE getpane -----------------------------------------
+ def getpanedata(self):
+ try:
+ return hou.ui.paneTabUnderCursor()
+ except (AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(
+ ("No context options to display: " + str(e)),
+ severity=hou.severityType.Message
+ )
+
+ # !SECTION Functions
+
+ # ---------------------------------------------------------- Callbacks
+ # SECTION Callbacks --------------------------------------------------
+ # ------------------------------------- searchfilter_cb
+ # NOTE searchfilter_cb --------------------------------
+ def searchfilter_cb(self):
+ self.openmenu()
+
+ # ------------------------------------- setexpandericon
+ # NOTE setexpandericon --------------------------------
+ def setexpandericon(self):
+ if self.expanditems:
+ self.expander.setIcon(util.COLLAPSE_ALL_ICON)
+ self.expander.setToolTip(la.TT_MW['collapse_all'])
+ else:
+ self.expander.setIcon(util.EXPAND_ALL_ICON)
+ self.expander.setToolTip(la.TT_MW['expand_all'])
+
+ # ----------------------------------------- expander_cb
+ # NOTE expander_cb ------------------------------------
+ def expander_cb(self):
+ if self.expanditems:
+ self.searchresultstree.collapseAll()
+ else:
+ self.searchresultstree.expandAll()
+
+ self.expanditems = not self.expanditems
+ self.setexpandericon()
+ self.settingdata[util.SETTINGS_KEYS[15]] = self.expanditems
+ settings_data.savesettings(self.settingdata)
+
+ # --------------------------------------- setmetricicon
+ # NOTE setmetricicon ----------------------------------
+ def setmetricicon(self):
+ if self.isdebug.mainwindow:
+ self.metricpos.setIcon(util.UP_ICON)
+ self.metricpos.setToolTip(la.TT_MW['metricposself'])
+
+ else:
+ self.metricpos.setIcon(util.DOWN_ICON)
+ self.metricpos.setToolTip(la.TT_MW['metricposmain'])
+
+ # ---------------------------------------- metricpos_cb
+ # NOTE metricpos_cb -----------------------------------
+ def metricpos_cb(self):
+ self.isdebug.mainwindow = not self.isdebug.mainwindow
+ self.settingdata[util.SETTINGS_KEYS[13]] = self.isdebug.mainwindow
+ settings_data.savesettings(self.settingdata)
+ self.setmetricicon()
+
+ # ------------------------------------------ setctxicon
+ # NOTE setctxicon -------------------------------------
+ def setctxicon(self):
+ if self.showctx:
+ self.contexttoggle.setIcon(util.COLLAPSE_ICON)
+ else:
+ self.contexttoggle.setIcon(util.EXPAND_ICON)
+ self.searchresultstree.setColumnHidden(3, self.showctx)
+
+ # ------------------------------------------ showctx_cb
+ # NOTE showctx_cb -------------------------------------
+ def showctx_cb(self, pressed):
+ self.showctx = True if pressed else False
+ self.settingdata[util.SETTINGS_KEYS[7]] = self.showctx
+ settings_data.savesettings(self.settingdata)
+ self.setctxicon()
+
+ # ---------------------------------------- pinwindow_cb
+ # NOTE pinwindow_cb -----------------------------------
+ def pinwindow_cb(self):
+ self.windowispin = not self.windowispin
+ self.settingdata[util.SETTINGS_KEYS[5]] = self.windowispin
+ settings_data.savesettings(self.settingdata)
+ self.setpinicon()
+
+ # ------------------------------------------ setpinicon
+ # NOTE setpinicon -------------------------------------
+ def setpinicon(self):
+ if self.windowispin:
+ self.pinwindow.setIcon(util.PIN_IN_ICON)
+ else:
+ self.pinwindow.setIcon(util.PIN_OUT_ICON)
+
+ # ------------------------------------- opensettings_cb
+ # NOTE opensettings_cb --------------------------------
+ def opensettings_cb(self, doopen):
+ self.ui.isopened = self.ui.isVisible()
+
+ if self.animatedsettings:
+ self.open_settings(doopen)
+ elif self.ui.isopened:
+ self.open_settings(False)
+ else:
+ self.open_settings(True)
+
+ # --------------------------------------- open_settings
+ # NOTE open_settings ----------------------------------
+ def open_settings(self, doopen):
+ if doopen:
+ pos = self.opensettingstool.mapToGlobal(
+ QtCore.QPoint(-self.ui.width() + 31, 28))
+ self.ui.setGeometry(
+ pos.x(),
+ pos.y(),
+ self.ui.width(),
+ self.ui.height()
+ )
+ self.ui.updatecurrentvalues()
+ self.ui.show()
+ self.ui.activateWindow()
+ self.ui.setFocus()
+ if self.animatedsettings:
+ self.anim.start_animation(True)
+ else:
+ if self.ui.performcheck:
+ if self.ui.checkforchanges():
+ self.ui.savecheck()
+ if self.animatedsettings and not self.ui.waitforclose:
+ self.ui.closewindows()
+ _ = self.anim.start_animation(False)
+ else:
+ self.ui.isopened = True
+ self.ui.closewindows()
+ self.ui.close()
+ if self.ui.waitforclose:
+ self.close()
+
+ def anim_complete(self):
+ if self.ui.isopened:
+ self.ui.close()
+ self.ui.isopened = False
+ self.opensettingstool.setChecked(False)
+
+ # --------------------------------------- textchange_cb
+ # NOTE textchange_cb ----------------------------------
+ def textchange_cb(self, text):
+ self.starttime = ptime.time() # ----------------------------- # ANCHOR Search Timer Start
+ if len(text) > 0 and not self.holdinfobanner:
+ self.setinfotext(200, self.searchresultstree.toolTip())
+ if text in util.CTXSHOTCUTS:
+ self.ctxsearcher(text)
+ elif len(text) > 1 and text not in util.CTXSHOTCUTS:
+ self.searching = True
+ allowed = re.compile(r'[^a-zA-Z ]+')
+ text = re.sub(allowed, '', text)
+ str = text.split()
+ searchstring = ['%s*' % (x,) for x in str]
+ regtime = ptime.time() # ----------------------------- # ANCHOR Regex Timer Start
+ self.regtimetotal = ((regtime - self.starttime) * 1000.0)
+ if searchstring:
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print(searchstring)
+ txt, timer = self.handler.searchtext(
+ ' '.join(searchstring),
+ self.isdebug,
+ self.settingdata[util.SETTINGS_KEYS[9]]
+ )
+ self.hotkeystime = timer
+ self.searchtablepopulate(txt)
+ else:
+ self.getpane = None
+ self.holdinfobanner = False
+ self.searching = False
+ self.treetotal_lbl.setText("")
+ self.searchresultstree.clear()
+ self.setinfotext(200, self.searchbox.toolTip())
+
+ # -------------------------------------- searchclick_cb
+ # NOTE searchclick_cb ---------------------------------
+ def searchclick_cb(self, item, column):
+ hk = item.text(2)
+ self.tmpsymbol = item.text(3)
+
+ if hk == "":
+ self.chindex = hou.hotkeys.changeIndex()
+ result = self.createtemphotkey(self.tmpsymbol)
+ if result is True:
+ self.chindex = hou.hotkeys.changeIndex()
+ hk = hou.hotkeys.assignments(self.tmpsymbol)
+ self.processkey(hk, True)
+ else:
+ hk = hou.hotkeys.assignments(self.tmpsymbol)
+ self.processkey(hk)
+ self.tmpsymbol = None
+ return
+
+ # ---------------------------------------- ctxhotkey_cb
+ # NOTE ctxhotkey_cb -----------------------------------
+ def ctxhotkey_cb(self):
+ if self.menuopened:
+ self.searchmenu.setFocus()
+ else:
+ self.searchbox.setFocus()
+ self.searchbox.blockSignals(True)
+ self.searchbox.setText(":c")
+ self.searchbox.blockSignals(False)
+ self.ctxsearcher()
+
+ # ------------------------------------------ getContext
+ # NOTE getContext -------------------------------------
+ def getContext(self, ctx):
+ """Return Houdini context string."""
+ try:
+ hou_context = ctx.pwd().childTypeCategory().name()
+ except:
+ return None
+
+ print("Hou Context: ", hou_context)
+ return util.CONTEXTTYPE[hou_context]
+
+ # !SECTION Callbacks
+
+ # -------------------------------------------------- Hotkey Processing
+ # SECTION Hotkey Processing ------------------------------------------
+ # ------------------------------------- savelastkey
+ # NOTE savelastkey --------------------------------
+ def savelastkey(self, symbol, key):
+ self.settingdata[util.SETTINGS_KEYS[11]] = (str(symbol) + " " + str(key[0]))
+ settings_data.savesettings(self.settingdata)
+
+ # -------------------------------------- processkey
+ # NOTE processkey ---------------------------------
+ def processkey(self, key, tmphk=False):
+ if tmphk:
+ self.savelastkey(self.tmpsymbol, key)
+
+ if (key[0] is not '+'):
+ key = key[0].split('+')
+
+ skey = None
+ ikey = None
+ key = keyconversion(key)
+ modifiers = util.MODIFIERS
+ mod_flag = QtCore.Qt.KeyboardModifiers()
+ for i in range(len(key)):
+ if str(key[i]) in modifiers:
+ mod_flag = mod_flag | util.MODIFIERS[str(key[i])]
+ else:
+ skey = key[i]
+ ikey = util.KEY_DICT[str(key[i])]
+
+ keypress = QtGui.QKeyEvent(
+ QtGui.QKeyEvent.KeyPress, # Keypress event identifier
+ ikey, # Qt key identifier
+ mod_flag, # Qt key modifier
+ skey # String of Qt key identifier
+ )
+
+ focustarget = self.getpane if self.getpane else hou.ui.mainQtWindow()
+ if self.getpane:
+ for pane_tab in hou.ui.curDesktop().paneTabs():
+ if pane_tab.name() == focustarget.name():
+ pane_tab.setIsCurrentTab()
+
+ try:
+ if sys.platform == "darwin":
+ hou.qt.mainWindow().setFocus()
+ hd.executeDeferredAfterWaiting(self.app.sendEvent, 5, hou.qt.mainWindow(), keypress)
+ else:
+ hou.qt.mainWindow().setFocus()
+ hd.executeDeferred(self.app.sendEvent, hou.qt.mainWindow(), keypress)
+ # event = QtWidgets.QApplication.postEvent(hou.ui.mainQtWindow(), keypress)
+ self.close()
+
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(
+ ("Could not trigger hotkey event: " + str(e)),
+ severity=hou.severityType.Warning
+ )
+ print("Could not trigger hotkey event: " + str(e))
+
+ # ---------------------------------- setKeysChanged
+ # NOTE setKeysChanged -----------------------------
+ def setKeysChanged(self, changed):
+ if self.keys_changed and not changed:
+ if not hou.hotkeys.saveOverrides():
+ print("ERROR: Couldn't save hotkey override file.")
+ self.keys_changed = changed
+ self.chindex = hou.hotkeys.changeIndex()
+ self.handler.updatechangeindex(self.chindex)
+
+ # -------------------------------- createtemphotkey
+ # NOTE createtemphotkey ---------------------------
+ def createtemphotkey(self, symbol):
+ hkeys = util.gethotkeys()
+ hou.hotkeys._createBackupTables()
+ for i in range(len(hkeys)):
+ result = hou.hotkeys.findConflicts(symbol, hkeys[i])
+ if not result:
+ assignresult = hou.hotkeys.addAssignment(symbol, hkeys[i])
+ if assignresult:
+ self.tmpkey = hkeys[i]
+ break
+ else:
+ pass
+ else:
+ pass
+
+ self.keys_changed = True
+ self.setKeysChanged(False)
+ return assignresult
+
+ # -------------------------------- removetemphotkey
+ # NOTE removetemphotkey ---------------------------
+ def removetemphotkey(self, symbol, tmpkey):
+ hou.hotkeys._restoreBackupTables()
+ hou.hotkeys.revertToDefaults(symbol, True)
+ self.keys_changed = True
+ self.setKeysChanged(False)
+ hkcheck = hou.hotkeys.assignments(str(symbol))
+ if len(hkcheck) is 0:
+ self.settingdata[util.SETTINGS_KEYS[11]] = ""
+ settings_data.savesettings(self.settingdata)
+
+ # !SECTION Hotkey Processing
+
+ # ------------------------------------------------------------- Search
+ # SECTION Search -----------------------------------------------------
+ # ---------------------------------- createcontextitems
+ # TODO createcontextitems -----------------------------
+ def createcontextitems(self, result, hc):
+ result[2] = (QtWidgets.QTreeWidgetItem(self.searchresultstree, [result[hc][0], result[hc][1]]))
+
+ # -------------------------------------------- openmenu
+ # TODO openmenu ---------------------------------------
+ def appendcontextlist(self, list):
+ if list[4] not in self.context_list:
+ return self.context_list.append(list[4])
+
+ # ------------------------------------- globalkeysearch
+ # NOTE globalkeysearch --------------------------------
+ def globalkeysearch(self):
+ self.ctxsearch = True
+ ctx = ["h"]
+ results = self.handler.searchctx(ctx)
+ self.searchtablepopulate(results)
+ self.ctxsearch = False
+
+ def processdesktop(self, ran, result):
+ print("---- %s" % ran)
+ print(result)
+ print("Window Name: %s | Whats This?: %s | Type: %s" % (
+ result.windowTitle(), result.whatsThis(), result.accessibleName()))
+ if isinstance(result, Iterable):
+ print("Item amount: %d" % len(result))
+ try:
+ for i in result:
+ print(i.windowTitle())
+ if ran == "hou.ui.paneTabs()":
+ print("Name : %s | Item: %s | Type: %s" % (i.name(), i, i.type))
+ elif ran == "util.widgets_at(mainwin, pos)":
+ print("Window Name: %s | Item: %s | Type: %s" % (i.windowTitle(), i.type, i.type))
+ else:
+ print(i)
+
+ except(AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ (("Error in %s : " % ran) + str(e)), severity=hou.severityType.Warning)
+ pass
+ else:
+ print(("Error in %s : " % ran) + str(e))
+ pass
+
+ # ------------------------------------------------------ Context Terms
+ # SECTION Context Terms ----------------------------------------------
+ # ----------------------------------------- ctxsearcher
+ # NOTE ctxsearcher ------------------------------------
+ def ctxsearcher(self, ctx=None):
+ self.starttime = ptime.time()
+ results = None
+ ctxresult = []
+
+ # ---------------------------- None or :c
+ # NOTE None or :c -----------------------
+ if ctx is None or ctx == ":c":
+ self.ctxsearch = True
+ self.getpane = None
+ skipelse = False
+ undermouse = None
+ pane = ""
+ mainwin = QtWidgets.QApplication
+
+ try:
+ selected_node = hou.selectedNodes()
+ if selected_node:
+ print("#1 - Selected Node: %s" % selected_node)
+ print(selected_node[0].parmTuples())
+ for i in selected_node[0].parmTuples():
+ print(i)
+ skipelse = True
+ else:
+ pass
+ except(AttributeError, TypeError) as e:
+ self.setstatusmsg(str(e), "Warning")
+
+ if not skipelse:
+ try:
+ self.getpane = self.getpanedata()
+ if self.isdebug and self.isdebug.level in {"ALL"}: print(self.getpane)
+ if self.getpane:
+ panetype = self.getpane.type()
+ ctxresult = util.PANETYPES[self.getpane.type()]
+ results = self.handler.searchctx(ctxresult[0])
+ self.searchbox.blockSignals(True)
+ self.searchbox.setText(":c %s" % ctxresult[1])
+ self.searchbox.blockSignals(False)
+ skipelse = True
+ else:
+ pass
+ except(AttributeError, TypeError) as e:
+ self.setstatusmsg(str(e), "Warning")
+
+ if not skipelse:
+ try:
+ pos = QtGui.QCursor.pos()
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Position: X:%d Y: %d" % (pos.x(), pos.y()))
+
+ undermouse = util.widgets_at(QtWidgets.QApplication, pos)
+ if undermouse:
+ for w in undermouse:
+ if w.windowTitle() != "":
+ ctxresult = util.PANETYPES.get(
+ w.windowTitle()) if w.windowTitle() in util.PANETYPES else None
+ if ctxresult is not None:
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Title: %s HContext: %s" % (ctxresult[0], ctxresult[1]))
+ results = self.handler.searchctx(ctxresult[0])
+ self.searchbox.blockSignals(True)
+ self.searchbox.setText(":c %s" % ctxresult[1])
+ self.searchbox.blockSignals(False)
+ break
+ else:
+ e = "#3 - Object under mouse cannot be queried"
+ self.setstatusmsg(str(e), "ImportantMessage")
+ pass
+
+ except(AttributeError, TypeError) as e:
+ self.setstatusmsg(str(e), "Warning")
+ return
+
+ # ------------------------------------ :v
+ # NOTE :v -------------------------------
+ elif ctx == ":v":
+ self.ctxsearch = True
+ ctxresult.append("h.pane")
+ results = self.handler.searchctx(ctxresult)
+
+ # ------------------------------------ :g
+ # NOTE :g -------------------------------
+ elif ctx == ":g":
+ self.ctxsearch = True
+ ctxresult.append("h")
+ results = self.handler.searchctx(ctxresult)
+ # !SECTION Context Terms
+ if results:
+ self.searchtablepopulate(results)
+ self.ctxsearch = False
+ self.searchbox.clearFocus()
+ self.searchresultstree.setFocus()
+ self.searchresultstree.setCurrentItem(
+ self.searchresultstree.topLevelItem(0).child(0)
+ )
+ # endtime = ptime.time() -------------------------------------- # ANCHOR CTXHotkey Performance Timer
+ # timetotal = ((endtime - self.starttime) * 1000.0)
+ # print("CTX Timer: %0.4f" % timetotal)
+ else:
+ e = "Unable to locate usable context item"
+ self.setstatusmsg(str(e), "ImportantMessage")
+
+ # --------------------------------- searchtablepopulate
+ # NOTE searchtablepopulate ----------------------------
+ def searchtablepopulate(self, data):
+ if len(data) > 0:
+ # tabletimer = hou.perfMon.startEvent("Table_Populate") ------- # ANCHOR hou perf timer
+ self.treecatnum = 0
+ self.treeitemsnum = 0
+ self.searchresultstree.clear()
+
+ self.hotkeys[:] = []
+ self.context_list[:] = []
+ self.hcontext_tli.clear()
+
+ # list(map(self.appendcontextlist, data))
+ for i in range(len(data)):
+ if data[i][4] not in self.context_list:
+ self.context_list.append(data[i][4])
+ # if self.ctxsearch:
+ # else:
+ # self.context_list.append(data[i][4])
+
+ result, hctimer = self.handler.gethcontextod(self.context_list)
+ self.hcontexttime = hctimer
+ treebuildtimer = ptime.time() # ------------------------------ # ANCHOR Tree builder Start
+ # TODO Test Map ---------
+ for hc in range(len(result)):
+ self.hcontext_tli[result[hc][2]] = (QtWidgets.QTreeWidgetItem(
+ self.searchresultstree, [
+ result[hc][0],
+ result[hc][1]
+ ]
+ ))
+ if self.expanditems:
+ self.searchresultstree.expandItem(self.hcontext_tli[result[hc][2]])
+ self.treecatnum += 1
+
+ base_keys = list(self.hcontext_tli.keys())
+ for i in range(len(data)):
+ for j in range(len(base_keys)):
+ if base_keys[j] == data[i][4]:
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ self.hotkeys.append(QtWidgets.QTreeWidgetItem(
+ self.hcontext_tli[base_keys[j]], [
+ data[i][0],
+ data[i][1],
+ data[i][2],
+ data[i][3],
+ data[i][4]
+ ]
+ ))
+ self.treeitemsnum += 1
+ else:
+ self.hotkeys.append(QtWidgets.QTreeWidgetItem(
+ self.hcontext_tli[base_keys[j]], [
+ data[i][0],
+ data[i][1],
+ data[i][2],
+ data[i][3]
+ ]
+ ))
+ self.treeitemsnum += 1
+
+ # tabletimer.stop() # ANCHOR hou perf timer ---------------------------------------- hou perf timer
+ # self.searchevent.stop() # ANCHOR hou perf timer ---------------------------------------- hou perf timer
+ # self.timerprofile.stop() # ANCHOR hou perf timer ---------------------------------------- hou perf timer
+
+ treebuildtimerend = ptime.time() # --------------------------- # ANCHOR Tree Builder End
+ treebuildtotal = ((treebuildtimerend - treebuildtimer) * 1000.0)
+
+ if not self.holdinfobanner:
+ try:
+ self.infolabeldelayasync()
+ except(AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(str(e), severity=hou.severityType.Message)
+ else:
+ print(e)
+
+ self.styleresultstotalasync(self.treecatnum, self.treeitemsnum)
+ self.endtime = ptime.time() # ----------------------------- # ANCHOR Search Timer End
+ totaltime = ((self.endtime - self.starttime) * 1000.0)
+ if self.isdebug.performance:
+ outdata = [self.regtimetotal, self.hcontexttime, self.hotkeystime, treebuildtotal, totaltime]
+ self.styletimersasync(outdata)
+
+ # !SECTION Search
+
+ # ------------------------------------------------------ Async Methods
+ # SECTION Async Methods ----------------------------------------------
+ # ------------------------------------------------- worker1
+ # SECTION Workers : NOTE worker1 --------------------------
+ def worker1(self, d1):
+ hd.executeInMainThreadWithResult(self.styletimers, d1)
+
+ # ------------------------------------------------- worker2
+ # NOTE worker2 --------------------------------------------
+ def worker2(self, d1, d2):
+ hd.executeInMainThreadWithResult(self.styletotals, d1, d2)
+
+ # ------------------------------------------------- worker3
+ # NOTE worker3 --------------------------------------------
+ def worker3(self):
+ hd.executeInMainThreadWithResult(self.infolabeldelay)
+
+ # !SECTION Workers
+
+ # ---------------------------------------- styletimersasync
+ # SECTION styletimers : NOTE styletimersasync -----------------------------------
+ def styletimersasync(self, d1):
+ thread = threading.Thread(target=self.worker1, args=(d1,))
+ thread.daemon = True
+ thread.start()
+
+ # --------------------------------------------- styletimers
+ # NOTE styletimers ----------------------------------------
+ def styletimers(self, d1):
+ if self.isdebug.mainwindow:
+ perftime = style.returntimers(d1)
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(perftime, severity=hou.severityType.Message)
+ else:
+ print(perftime)
+ else:
+ perftime = style.styletimers(d1)
+ self.infolbl.setStyleSheet(style.INFOLABEL)
+ self.infolbl.setText(perftime)
+
+ # !SECTION styletimers
+
+ # ---------------------------------- styleresultstotalasync
+ # SECTION styleresultstotal : NOTE styleresultstotalasync -
+ def styleresultstotalasync(self, d1, d2):
+ thread = threading.Thread(target=self.worker2, args=(d1, d2))
+ thread.daemon = True
+ thread.start()
+
+ # --------------------------------------------- styletotals
+ # NOTE styletotals ----------------------------------------
+ def styletotals(self, d1, d2):
+ result = style.styleresulttotal(d1, d2)
+ self.treetotal_lbl.setText(result)
+
+ # !SECTION styleresultstotal
+
+ # --------------------------------------infolabeldelayasync
+ # SECTION infolabeldelay : NOTE infolabeldelayasync ------
+ def infolabeldelayasync(self):
+ if self.threadtimer:
+ self.threadtimer.cancel()
+ self.holdinfobanner = True
+ self.infolbl.setStyleSheet(style.INFOLABEL)
+ self.threadtimer = threading.Timer(5, self.infolabeldelay)
+ self.threadtimer.start()
+
+ # ------------------------------------------ infolabeldelay
+ # NOTE infolabeldelay -------------------------------------
+ def infolabeldelay(self):
+ try:
+ self.infolbl.setText(style.gettooltipstyle(self.searchresultstree.toolTip()))
+ hd.executeDeferred(self.fade_in, self.infolbl, 200)
+ self.holdinfobanner = False
+ except(AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(e, severity=hou.severityType.Message)
+ else:
+ print(e)
+ else:
+ pass
+ # print(self.timerprofile.stats()) # ANCHOR hou perf timer ---------------------------------------- hou perf timer
+
+ # !SECTION infolabeldelay
+
+ # --------------------------------------------- createtimer
+ # NOTE createtimer ----------------------------------------
+ def createtimer(self, time, func, p):
+ if self.tiptimer:
+ if self.tiptimer.isAlive():
+ self.tiptimer.cancel()
+
+ self.tiptimer = threading.Timer(time, (func(p)))
+ self.tiptimer.start()
+
+ # !SECTION Async Methods
+
+ # --------------------------------------------------------- Animations
+ # SECTION Animations -------------------------------------------------
+ # ----------------------------------------- fade_in
+ # NOTE fade_in ------------------------------------
+ def fade_in(self, target, duration):
+ self.effect = QtWidgets.QGraphicsOpacityEffect()
+ self.tar = target
+ self.tar.setGraphicsEffect(self.effect)
+ self.an = QtCore.QPropertyAnimation(self.effect, b"opacity")
+ self.an.setDuration(duration)
+ self.an.setStartValue(0)
+ self.an.setEndValue(1)
+ self.an.start()
+
+ # ---------------------------------------- fade_out
+ # NOTE fade_out -----------------------------------
+ def fade_out(self, target, duration):
+ self.effect = QtWidgets.QGraphicsOpacityEffect()
+ self.tar = target
+ self.tar.setGraphicsEffect(self.effect)
+ self.an = QtCore.QPropertyAnimation(self.effect, b"opacity")
+ self.an.setDuration(duration)
+ self.an.setStartValue(1)
+ self.an.setEndValue(0)
+ self.an.start()
+
+ # !SECTION
+
+ # ------------------------------------------------------------- Events
+ # SECTION Events ----------------------------------------------------
+ # ------------------------------------- addeventfilters
+ # NOTE addeventfilters --------------------------------
+ def addeventfilters(self):
+ self.installEventFilter(self)
+ self.expander.installEventFilter(self)
+ self.metricpos.installEventFilter(self)
+ self.searchbox.installEventFilter(self)
+ self.pinwindow.installEventFilter(self)
+ self.helpButton.installEventFilter(self)
+ self.leftresize.installEventFilter(self)
+ self.rightresize.installEventFilter(self)
+ self.searchfilter.installEventFilter(self)
+ self.contexttoggle.installEventFilter(self)
+ self.opensettingstool.installEventFilter(self)
+ self.searchresultstree.installEventFilter(self)
+
+ # ---------------------------------- removeeventfilters
+ # NOTE removeeventfilters -----------------------------
+ def removeeventfilters(self):
+ self.removeEventFilter(self)
+ self.expander.removeEventFilter(self)
+ self.metricpos.removeEventFilter(self)
+ self.searchbox.removeEventFilter(self)
+ self.pinwindow.removeEventFilter(self)
+ self.helpButton.removeEventFilter(self)
+ self.leftresize.removeEventFilter(self)
+ self.rightresize.removeEventFilter(self)
+ self.searchfilter.removeEventFilter(self)
+ self.contexttoggle.removeEventFilter(self)
+ self.opensettingstool.removeEventFilter(self)
+ self.searchresultstree.removeEventFilter(self)
+
+ # --------------------------------------- cancelthreads
+ # NOTE cancelthreads ----------------------------------
+ def cancelthreads(self):
+ if self.threadtimer:
+ self.threadtimer.cancel()
+ if self.tiptimer:
+ self.tiptimer.cancel()
+
+ # ------------------------------ createdelayedinfolabel
+ # NOTE createdelayedinfolabel -------------------------
+ def createdelayedinfolabel(self, tiptext):
+ self.infolbl.setText(style.gettooltipstyle(tiptext))
+ self.fade_in(self.infolbl, 200)
+
+ # ---------------------------------------- checktooltip
+ # NOTE checktooltip -----------------------------------
+ def checktooltip(self, obj, hasleft=False):
+ if hasleft:
+ if self.searching and self.infolbl.text() != self.searchresultstree.toolTip():
+ self.setinfotext(700, self.searchresultstree.toolTip())
+ elif not self.searching and self.infolbl.text() != self.searchbox.toolTip():
+ self.setinfotext(700, self.searchbox.toolTip())
+ else:
+ if obj == self.searchresultstree or obj == self.searchbox:
+ if self.searching and self.infolbl.text() != self.searchresultstree.toolTip():
+ self.setinfotext(200, self.searchresultstree.toolTip())
+ elif not self.searching and self.infolbl.text() != self.searchbox.toolTip():
+ self.setinfotext(200, self.searchbox.toolTip())
+ elif self.infolbl.text() != obj.toolTip():
+ self.setinfotext(200, obj.toolTip())
+
+ # ---------------------------------------- addshortcuts
+ # NOTE addshortcuts -----------------------------------
+ def addshortcuts(self):
+ toggleexpand_shct = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+W"), self)
+ toggleexpand_shct.activated.connect(self.expander_cb)
+
+ opensettings_shct = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+S"), self)
+ opensettings_shct.activated.connect(self.opensettingstool.click)
+
+ getpanes_shct = QtWidgets.QShortcut(QtGui.QKeySequence("ALT+V"), self)
+ getpanes_shct.activated.connect(self.getwidgets)
+
+ getpanes_shct = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+Tab"), self)
+ getpanes_shct.activated.connect(self.ctxhotkey_cb)
+
+ # -------------------------------------------------------- Event Types
+ # SECTION Event Types ------------------------------------------------
+ # def createEventHandler(self, uievent, pending_actions):
+ # if isinstance(uievent, MouseEvent):
+ def onFocusWindowChanged(self, focusWindow):
+ if focusWindow is None:
+ print("None!")
+
+ def onMouseEvent(self, kwargs):
+ ui_event = kwargs["ui_event"]
+ print(ui_event)
+ reason = ui_event.reason()
+ device = ui_event.device()
+ if device.isLeftButton():
+ print("Clicked")
+
+ if reason == hou.uiEventReason.Picked:
+ print("LMB click")
+
+ elif reason == hou.uiEventReason.Start:
+ print("LMB was pressed down")
+
+ elif reason == hou.uiEventReason.Active:
+ print("Mouse dragged with LMB down")
+
+ elif reason == hou.uiEventReason.Changed:
+ print("LMB was released")
+
+ def eventFilter(self, obj, event):
+ event_type = event.type()
+
+ # ------------------------------------------- Mouse
+ # NOTE Mouse --------------------------------------
+ # --------------------------------- Enter
+ # NOTE Enter ----------------------------
+ if event_type == QtCore.QEvent.Enter:
+ if obj == self:
+ self.mouseout = False
+ if obj == self.leftresize or obj == self.rightresize:
+ self.overhandle = True
+ style.styleresizehandle(obj, True)
+ self.checktooltip(obj)
+
+ # --------------------------------- Leave
+ # NOTE Leave ----------------------------
+ if event_type == QtCore.QEvent.Leave:
+ if obj == self:
+ self.mouseout = True
+ if obj == self.leftresize or obj == self.rightresize:
+ self.overhandle = False
+ style.styleresizehandle(obj, False)
+ self.checktooltip(obj, True)
+
+ # ------------------------------- ToolTip
+ # NOTE ToolTip --------------------------
+ if event_type == QtCore.QEvent.ToolTip:
+ return True
+
+ # ---------------------- MouseButtonPress
+ # NOTE MouseButtonPress -----------------
+ if event_type == QtCore.QEvent.MouseButtonPress:
+ if obj == self.leftresize or obj == self.rightresize:
+ self.resizing = True
+ self.previous_pos = event.globalPos()
+
+ if obj == self.searchbox:
+ return QtCore.QObject.eventFilter(self, obj, event)
+ else:
+ if obj == self:
+ self.activateWindow()
+ self.previous_pos = event.globalPos()
+ if obj == self.parentwindow:
+ self.close()
+
+ # -------------------- MouseButtonRelease
+ # NOTE MouseButtonRelease ---------------
+ if event_type == QtCore.QEvent.MouseButtonRelease:
+ if obj == self.leftresize or obj == self.rightresize:
+ self.resizing = False
+
+ if self._drag_active:
+ self._drag_active = False
+
+ # ----------------------------- MouseMove
+ # NOTE MouseMove ------------------------
+ if event_type == QtCore.QEvent.MouseMove:
+ if obj == self:
+ delta = event.globalPos() - self.previous_pos
+ self.move(self.x() + delta.x(), self.y() + delta.y())
+
+ if self.ui.isVisible():
+ self.ui.move(self.ui.x() + delta.x(), self.ui.y() + delta.y())
+ self.ui.movesubwindows(delta)
+
+ self.previous_pos = event.globalPos()
+ self._drag_active = True
+
+ if self.resizing:
+ if obj == self.rightresize:
+ delta = event.globalPos() - self.previous_pos
+
+ if self.ui.isVisible():
+ self.ui.move(self.ui.x() + delta.x(), self.ui.y())
+ self.ui.movesubwindows(delta, True)
+ self.previous_pos = event.globalPos()
+ else:
+ return QtCore.QObject.eventFilter(self, obj, event)
+
+ # ---------------------------- MouseHover
+ # NOTE MouseHover -----------------------
+ if event_type == QtCore.QEvent.HoverMove:
+ pass
+
+ # ---------------------------------------- Keypress
+ # NOTE Keypress -----------------------------------
+ if event_type == QtCore.QEvent.KeyPress:
+ # # ----------------------------- Enter
+ # # NOTE Enter ------------------------
+ # if event.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
+ # print('Enter:')
+ # enter_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Enter, QtCore.Qt.NoModifier)
+ # QtWidgets.QApplication.postEvent(self, enter_event)
+ # return True
+
+ # ------------------------------- TAB
+ # NOTE TAB --------------------------
+ if event.key() == QtCore.Qt.Key_Tab:
+ if self.searching:
+ self.searchbox.releaseKeyboard()
+ self.searchbox.clearFocus()
+ self.searchresultstree.setFocus()
+ self.searchresultstree.setCurrentItem(
+ self.searchresultstree.topLevelItem(0).child(0))
+ return True
+ else:
+ pass
+
+ # ------------------------------- ESC
+ # NOTE ESC --------------------------
+ if event.key() == QtCore.Qt.Key_Escape:
+ if self.ui.isVisible():
+ self.ui.closeroutine()
+ return True
+ else:
+ if self.menuopened:
+ if self.searchmenu.isVisible():
+ self.searchmenu.setVisible(False)
+ return True
+ else:
+ self.menuopened = False
+ return True
+ else:
+ self.close()
+ return True
+
+ # ------------------------------- ":"
+ # NOTE ":" --------------------------
+ if event.key() == QtCore.Qt.Key_Colon:
+ if self.searchbox.text() == "":
+ self.searchbox.releaseKeyboard()
+ self.searchbox.clearFocus()
+ self.openmenu()
+ return True
+
+ # ------------------------------------------ Window
+ # NOTE Window -------------------------------------
+ # ------------------------------ Activate
+ # NOTE Activate -------------------------
+ if event_type == QtCore.QEvent.WindowActivate:
+ if obj == self:
+ self.searchbox.grabKeyboard()
+
+ # ---------------------------- Deactivate
+ # NOTE Deactivate -----------------------
+ if event_type == QtCore.QEvent.WindowDeactivate:
+ if self.ui.isVisible():
+ self.searchbox.releaseKeyboard()
+ return True
+ if self.windowispin:
+ return QtCore.QObject.eventFilter(self, obj, event)
+ if self.mouseout:
+ self.close()
+
+ # ------------------------------- FocusIn
+ # NOTE FocusIn --------------------------
+ if event_type == QtCore.QEvent.FocusIn:
+ if obj == self:
+ pass
+
+ # ------------------------------ FocusOut
+ # NOTE FocusOut -------------------------
+ if event_type == QtCore.QEvent.FocusOut:
+ if obj == self:
+ pass
+
+ # ------------------------------------------- Close
+ # NOTE Close --------------------------------------
+ if event_type == QtCore.QEvent.Close:
+ self.cancelthreads()
+ try:
+ if util.bc(self.settingdata[util.SETTINGS_KEYS[2]]):
+ self.windowsettings.setValue("geometry", self.saveGeometry())
+ except (AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(("Could not save window dimensions: " + str(e)),
+ severity=hou.severityType.Warning)
+ else:
+ print("Could not save window dimensions: " + str(e))
+
+ if self.menuopened:
+ self.searchmenu.setVisible(False)
+
+ if self.tmpsymbol is not None:
+ hd.executeDeferredAfterWaiting(
+ self.removetemphotkey,
+ 25,
+ self.tmpsymbol,
+ self.tmpkey)
+
+ self.searchbox.releaseKeyboard()
+ try:
+ self.parentwindow.activateWindow()
+ self.parentwindow.setFocus()
+ self.setParent(None)
+ self.deleteLater()
+ except:
+ self.parentwindow.activateWindow()
+ self.setParent(None)
+ self.deleteLater()
+ try:
+ return QtCore.QObject.eventFilter(self, obj, event)
+ except RuntimeError:
+ return True
+
+ # !SECTION Event Types
+ # !SECTION Events
+ # !SECTION Searcher Class
+
+
+# -------------------------------------------------------------- Setup
+# SECTION Setup ------------------------------------------------------
+# ----------------------------------- Center Window
+# NOTE Center Window ------------------------------
+def center():
+ return parent_widget.mapToGlobal(
+ QtCore.QPoint(
+ parent_widget.rect().center().x(),
+ parent_widget.rect().center().y()
+ )
+ )
+
+
+# ----------------------------------- Create Window
+# NOTE Create Window ------------------------------
+def CreateSearcherPanel(searcher_window=None, **kwargs):
+ # timerprofile = hou.perfMon.startProfile("Load_Timer") # ANCHOR hou perf timer ---------------- hou perf timer
+ # loadevent = hou.perfMon.startEvent("Start _Timer") # ANCHOR hou perf timer ---------------- hou perf timer
+ # starttime = ptime.time()
+
+ kwargs = kwargs
+ settings = get_settings()
+ windowsettings = QtCore.QSettings("instance.id", "Searcher")
+
+ animated = True
+ searcher_window = Searcher(settings, windowsettings, animated, kwargs)
+ searcher_window.addeventfilters()
+ searcher_window.setStyleSheet(style.MAINWINDOW)
+ searcher_window.setAttribute(QtCore.Qt.WA_StyledBackground, True)
+ searcher_window.setWindowFlags(
+ QtCore.Qt.Tool
+ | QtCore.Qt.CustomizeWindowHint
+ | QtCore.Qt.FramelessWindowHint
+ | QtCore.Qt.WindowStaysOnTopHint
+ )
+
+ if util.bc(settings[util.SETTINGS_KEYS[2]]) and windowsettings.value("geometry") is not None:
+ searcher_window.restoreGeometry(windowsettings.value("geometry"))
+ else:
+ searcher_window.resize(
+ int(settings[util.SETTINGS_KEYS[3]][0]),
+ int(settings[util.SETTINGS_KEYS[3]][1]),
+ )
+ spos = center()
+ searcher_window.setGeometry(
+ spos.x() - (searcher_window.width() / 2),
+ spos.y() - (searcher_window.height() / 2),
+ searcher_window.width(),
+ searcher_window.height(),
+ )
+ searcher_window.searchbox.setFocus()
+ searcher_window.setWindowTitle('Searcher')
+ if not searcher_window.isVisible():
+ searcher_window.show()
+ searcher_window.activateWindow()
+
+ # endtime = ptime.time()
+ # timetotal = ((endtime - starttime) * 1000.0)
+ # print("Time: %0.4f" % timetotal)
+ # loadevent.stop() # ANCHOR hou perf timer ---------------------------------------- hou perf timer
+ # timerprofile.stop() # ANCHOR hou perf timer ---------------------------------------- hou perf timer
+ # print(timerprofile.stats()) # ANCHOR hou perf timer ---------------------------------------- hou perf timer
+
+ # searcher_window.activateWindow()
+
+
+# !SECTION Setup
+
+
+__package__ = "searcher"
diff --git a/python3.7libs/searcher/searcher_settings.py b/python3.7libs/searcher/searcher_settings.py
new file mode 100644
index 0000000..8e75cd1
--- /dev/null
+++ b/python3.7libs/searcher/searcher_settings.py
@@ -0,0 +1,700 @@
+from __future__ import division
+from __future__ import print_function
+from __future__ import absolute_import
+
+from searcher import util
+from searcher import about
+from searcher import theme
+from searcher import about_ui
+from searcher import theme_ui
+from searcher import bugreport
+from searcher import bugreport_ui
+from searcher import settings_data
+from searcher import language_en as la
+from searcher import searcher_settings_ui
+
+from builtins import range
+import os
+
+import hou
+from hutil.py23 import reload
+
+hver = 0
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.') + 1:])
+ from hutil.Qt import QtGui
+ from hutil.Qt import QtCore
+ from hutil.Qt import QtWidgets
+else:
+ from qtpy import QtGui
+ from qtpy import QtCore
+ from qtpy import QtWidgets
+
+reload(about)
+reload(theme)
+reload(about_ui)
+reload(theme_ui)
+reload(bugreport)
+reload(bugreport_ui)
+reload(searcher_settings_ui)
+
+
+# --------------------------------------------- hou.session
+# NOTE hou.session ----------------------------------------
+def get_settings():
+ return getattr(hou.session, "SETTINGS", None)
+
+
+the_scaled_icon_size = hou.ui.scaledSize(16)
+the_icon_size = 16
+
+scriptpath = os.path.dirname(os.path.realpath(__file__))
+
+
+def bc(v):
+ return str(v).lower() in ("yes", "true", "t", "1")
+
+
+class SearcherSettings(QtWidgets.QWidget):
+ """ Searcher Settings and Debug Menu"""
+
+ def __init__(self, handler, width, height, parent=None):
+ super(SearcherSettings, self).__init__(parent=parent)
+ # -------------------------------------------- settings
+ # NOTE settings ---------------------------------------
+ self.parentwindow = parent
+ self.settings = {}
+ self.context_dict = {}
+ self.command_dict = {}
+ self.currentsettings = {}
+ self.performcheck = True
+ self.contexts = None
+ self.commands = None
+ self.addKeyWidget = None
+ self.context_data = None
+ self.command_data = None
+ self.keys_changed = False
+ self.keystring = ""
+ self.keyindex = 0
+ self.canedit = False
+ self.KeySequence = None
+ self.hkholder = ""
+ self.datahandler = handler
+ self.isopened = False
+ self.resetdb = False
+ self.waitforclose = False
+ self.modifylayout = False
+ self.uiwidth = width
+ self.uiheight = height
+ self.windowlist = ["about", "bugreport", "theme"]
+ self.parentwindow.oldPos = self.parentwindow.pos()
+
+ # --------------------------------------------- beginui
+ # NOTE beginui ----------------------------------------
+ self.setObjectName('searcher-settings')
+ self.setAutoFillBackground(True)
+ self.setBackgroundRole(QtGui.QPalette.Window)
+ self.settings = get_settings()
+ self.isdebug = util.Dbug(
+ self.settings[util.SETTINGS_KEYS[4]],
+ str(self.settings[util.SETTINGS_KEYS[10]]),
+ self.settings[util.SETTINGS_KEYS[12]],
+ self.settings[util.SETTINGS_KEYS[13]],
+ )
+
+ self.la = la.TT_SETTINGS
+ # Load UI File
+ self.ui = searcher_settings_ui.Ui_SearcherSettings()
+ self.ui.setupUi(self, self.uiwidth, self.uiheight, bc(self.settings[util.SETTINGS_KEYS[8]]))
+ self.ui.retranslateUi(self)
+
+ self.about = about.About(self)
+ self.about.setAttribute(QtCore.Qt.WA_StyledBackground, True)
+ self.about.setWindowFlags(
+ QtCore.Qt.Tool
+ | QtCore.Qt.FramelessWindowHint
+ | QtCore.Qt.CustomizeWindowHint
+ )
+ self.about.resize(width, height - 180)
+
+ self.bugreport = bugreport.BugReport(self)
+ self.bugreport.setAttribute(QtCore.Qt.WA_StyledBackground, True)
+ self.bugreport.setWindowFlags(
+ QtCore.Qt.Tool
+ | QtCore.Qt.FramelessWindowHint
+ | QtCore.Qt.CustomizeWindowHint
+ )
+ self.bugreport.resize(width, height - 300)
+
+ self.theme = theme.Theme(self)
+ self.theme.setAttribute(QtCore.Qt.WA_StyledBackground, True)
+ self.theme.setWindowFlags(
+ QtCore.Qt.Tool
+ | QtCore.Qt.FramelessWindowHint
+ | QtCore.Qt.CustomizeWindowHint
+ | QtCore.Qt.NoDropShadowWindowHint
+ )
+ self.theme.resize(width, height - 90)
+
+ self.settingslayout = QtWidgets.QVBoxLayout()
+
+ # Get UI Elements
+ self.hotkey_icon = self.ui.hotkey_icon
+
+ # headerrow
+ self.in_memory_db = self.ui.inmemory_chk
+ self.in_memory_db.setToolTip(la.TT_SETTINGS[self.in_memory_db.objectName()])
+ self.savewindowsize = self.ui.windowsize_chk
+ self.savewindowsize.setToolTip(la.TT_SETTINGS[self.savewindowsize.objectName()])
+
+ # secondrow
+ self.ui.maxresults_lbl.setToolTip(la.TT_SETTINGS[self.ui.maxresults_lbl.objectName()])
+ self.maxresults = self.ui.maxresults_txt
+ self.maxresults.setToolTip(la.TT_SETTINGS[self.maxresults.objectName()])
+ self.animatedsettings = self.ui.animatedsettings_chk
+ self.animatedsettings.setToolTip(la.TT_SETTINGS[self.animatedsettings.objectName()])
+
+ # thirdrow
+ self.ui.defaulthotkey_lbl.setToolTip(la.TT_SETTINGS[self.ui.defaulthotkey_lbl.objectName()])
+ self.defaulthotkey = self.ui.defaulthotkey_txt
+ self.defaulthotkey.setToolTip(la.TT_SETTINGS[self.defaulthotkey.objectName()])
+
+ # fourthrow
+ self.ui.dbpath_lbl.setToolTip(la.TT_SETTINGS[self.ui.dbpath_lbl.objectName()])
+ self.database_path = self.ui.databasepath_txt
+ self.database_path.setToolTip(la.TT_SETTINGS[self.database_path.objectName()])
+ self.dbpath_btn = self.ui.dbpath_icon
+ self.dbpath_btn.setToolTip(la.TT_SETTINGS[self.dbpath_btn.objectName()])
+ dbpath_button_size = hou.ui.scaledSize(16)
+ self.dbpath_btn.setProperty("flat", True)
+ self.dbpath_btn.setIcon(util.FILE_ICON)
+ self.dbpath_btn.setIconSize(QtCore.QSize(
+ dbpath_button_size,
+ dbpath_button_size
+ ))
+
+ # fifthrow
+ self.metrics = self.ui.metrics_chk
+ self.metrics.setVisible(bc(self.settings[util.SETTINGS_KEYS[4]]))
+ self.metrics.setToolTip(la.TT_SETTINGS[self.metrics.objectName()])
+ # self.cleardata = self.ui.cleardata_btn
+ # self.cleardata.setToolTip(la.TT_SETTINGS[self.cleardata.objectName()])
+
+ # sixthrow
+ self.aboutbtn = self.ui.about_btn
+ self.aboutbtn.setToolTip(la.TT_SETTINGS[self.aboutbtn.objectName()])
+ self.aboutbtn.setCheckable(True)
+ self.aboutbtn.setChecked(False)
+ about_button_size = hou.ui.scaledSize(32)
+ self.aboutbtn.setProperty("flat", True)
+ self.aboutbtn.setIcon(util.ABOUT_ICON1)
+ self.aboutbtn.setIconSize(QtCore.QSize(
+ about_button_size,
+ about_button_size
+ ))
+
+ self.bugreportbtn = self.ui.bug_btn
+ self.bugreportbtn.setToolTip(la.TT_SETTINGS[self.bugreportbtn.objectName()])
+ self.bugreportbtn.setCheckable(True)
+ self.bugreportbtn.setChecked(False)
+ bugreport_button_size = hou.ui.scaledSize(21)
+ self.bugreportbtn.setProperty("flat", True)
+ self.bugreportbtn.setIcon(util.BUG_ICON)
+ self.bugreportbtn.setIconSize(QtCore.QSize(
+ bugreport_button_size,
+ bugreport_button_size
+ ))
+
+ self.themebtn = self.ui.theme_btn
+ self.themebtn.setToolTip(la.TT_SETTINGS[self.themebtn.objectName()])
+ self.themebtn.setCheckable(True)
+ self.themebtn.setChecked(False)
+ theme_button_size = hou.ui.scaledSize(27)
+ self.themebtn.setProperty("flat", True)
+ self.themebtn.setIcon(util.COLOR_ICON)
+ self.themebtn.setIconSize(QtCore.QSize(
+ theme_button_size,
+ theme_button_size
+ ))
+
+ self.debuglevel = self.ui.debuglevel_cbx
+ for lvl in util.DEBUG_LEVEL:
+ self.debuglevel.addItem(str(lvl))
+ self.debuglevel.setToolTip(la.TT_SETTINGS[self.debuglevel.objectName()])
+ self.debugflag = self.ui.debugflag_chk
+ self.debugflag.setToolTip(la.TT_SETTINGS[self.debugflag.objectName()])
+ self.debuglevel.setVisible(bc(self.settings[util.SETTINGS_KEYS[4]]))
+ self.debugflag.setVisible(bc(self.settings[util.SETTINGS_KEYS[4]]))
+
+ self.savedata = self.ui.save_btn
+ self.savedata.setToolTip(la.TT_SETTINGS[self.savedata.objectName()])
+
+ self.discarddata = self.ui.discard_btn
+ self.discarddata.setToolTip(la.TT_SETTINGS[self.discarddata.objectName()])
+
+ # -------------------------------------------- sixthrow
+ # NOTE sixthrow ---------------------------------------
+ info_button_size = hou.ui.scaledSize(16)
+ self.hotkey_icon.setProperty("flat", True)
+ self.hotkey_icon.setIcon(util.INFO_ICON)
+ self.hotkey_icon.setIconSize(QtCore.QSize(
+ info_button_size,
+ info_button_size
+ ))
+
+ # --------------------------------------------- connect
+ # NOTE connect ----------------------------------------
+ self.hotkey_icon.clicked.connect(self.hotkeyicon_cb)
+ self.dbpath_btn.clicked.connect(self.dbpath_cb)
+ # self.cleardata.clicked.connect(self.cleardata_cb)
+ self.aboutbtn.clicked.connect(self.window_cb)
+ self.bugreportbtn.clicked.connect(self.window_cb)
+ self.themebtn.clicked.connect(self.window_cb)
+ self.savedata.clicked.connect(self.save_cb)
+ self.discarddata.clicked.connect(self.discard_cb)
+
+ # -------------------------------------------- about_cb
+ # NOTE about_cb ---------------------------------------
+ self.settingslayout = self.ui.verticallayout
+ self.setLayout(self.ui.gridLayout)
+
+ # ----------------------------------- Startup Functions
+ # NOTE Startup Functions ------------------------------
+ self.updatecurrentvalues()
+ self.fieldsetup()
+
+ # --------------------------------------------------------------- Functions
+ # SECTION Functions -------------------------------------------------------
+ def closewindows(self):
+ for i in range(len(self.windowlist)):
+ if getattr(self, self.windowlist[i]).isVisible():
+ getattr(self, self.windowlist[i]).close()
+ getattr(self, self.windowlist[i] + "btn").setChecked(False)
+
+ # ----------------------------------------- mapposition
+ # NOTE mapposition ------------------------------------
+ def mapposition(self, w, h, s):
+ parent = s.parent()
+ pos = parent.mapToGlobal(QtCore.QPoint(w, h))
+ getattr(self, s.objectName()).setGeometry(
+ pos.x(),
+ pos.y() + parent.height(),
+ getattr(self, s.objectName()).width(),
+ getattr(self, s.objectName()).height())
+ getattr(self, s.objectName()).show()
+
+ # !SECTION Functions
+
+ # --------------------------------------------------------------- Callbacks
+ # SECTION Callbacks -------------------------------------------------------
+ # ------------------------------------------- window_cb
+ # The sender is the actual button, but the button is
+ # the same as the window instance so that both can be
+ # sent and accessed in methods via one variable.
+ # NOTE window_cb --------------------------------------
+ def window_cb(self, toggled):
+ self.closewindows()
+ s = self.sender()
+
+ if toggled is True and not getattr(self, s.objectName()).isVisible():
+ self.mapposition(0, 0, s) if self.animatedsettings.isChecked() else self.mapposition(0, 0, s)
+ getattr(self, s.objectName()).initmenu()
+ else:
+ if s.objectName() in self.windowlist:
+ getattr(self, s.objectName()).close()
+
+ # --------------------------------------- hotkeyicon_cb
+ # NOTE hotkeyicon_cb ----------------------------------
+ def hotkeyicon_cb(self):
+ return
+ # self.settings['in_memory_db'] = self.in_memory_db.isChecked()
+ # print(self.settings['in_memory_db'])
+
+ # ------------------------------------------- dbpath_cb
+ # NOTE dbpath_cb --------------------------------------
+ def dbpath_cb(self):
+ path = os.path.normpath(self.database_path.text()).replace("\\", "/")
+ dbpath = hou.expandString(hou.ui.selectFile(
+ start_directory=os.path.dirname(path),
+ title="Save Database",
+ pattern="searcher.db",
+ file_type=hou.fileType.Clip,
+ default_value="searcher.db"))
+ if dbpath != "":
+ if not dbpath.endswith("searcher.db"):
+ dbpath = dbpath + "searcher.db"
+ self.database_path.setText((os.path.normpath(dbpath)))
+
+ # ---------------------------------------- defaulthk_cb
+ # NOTE defaulthk_cb -----------------------------------
+ def defaulthk_cb(self):
+ return
+
+ # -------------------------------------------- test1_cb
+ # NOTE test1_cb ---------------------------------------
+ def test1_cb(self):
+ hkeys = []
+ for i in range(len(util.HOTKEYLIST)):
+ result = hou.hotkeys.findConflicts("h", util.HOTKEYLIST[i])
+ if result:
+ print("Confliction found: {}".format(result))
+ else:
+ print("No Confliction: {}".format(result))
+ hkeys.append(result)
+ print(hkeys)
+
+ # --------------------------------------- cleardata_cb
+ # NOTE cleardata_cb ----------------------------------
+ # def cleardata_cb(self):
+ # self.datahandler.cleardb()
+
+ # --------------------------------------------- save_cb
+ # NOTE save_cb ----------------------------------------
+ def save_cb(self):
+ if self.defaulthotkey.text() == "":
+ _ = hou.ui.displayMessage("Please enter a hotkey")
+ self.activateWindow()
+ self.defaulthotkey.setFocus()
+ self.canedit = True
+ else:
+ self.checkforchanges()
+ for i in range(len(util.SETTINGS_KEYS)):
+ if util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "bool":
+ self.settings[util.SETTINGS_KEYS[i]] = getattr(self, util.SETTINGS_KEYS[i]).isChecked()
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "text":
+ self.settings[util.SETTINGS_KEYS[i]] = getattr(self, util.SETTINGS_KEYS[i]).text()
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "intval":
+ self.settings[util.SETTINGS_KEYS[i]] = getattr(self, util.SETTINGS_KEYS[i]).value()
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "cbx":
+ self.settings[util.SETTINGS_KEYS[i]] = getattr(self, util.SETTINGS_KEYS[i]).currentText()
+
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print(self.settings)
+
+ settings_data.savesettings(self.settings)
+
+ if self.resetdb:
+ hou.session.DBCONNECTION = None
+ hou.session.DATABASE = None
+ self.resetdb = False
+
+ if self.modifylayout:
+ self.parentwindow.sui.metricpos.setVisible(
+ self.settings[util.SETTINGS_KEYS[12]])
+
+ self.performcheck = False
+ self.closewindows()
+
+ if self.animatedsettings.isChecked() and not self.waitforclose:
+ self.parentwindow.anim.start_animation(False)
+ self.isopened = True
+ elif self.waitforclose:
+ if self.bugreport.isVisible():
+ self.bugreport.close()
+ self.close()
+ self.parentwindow.close()
+ else:
+ self.close()
+
+ # ------------------------------------------ discard_cb
+ # NOTE discard_cb -------------------------------------
+ def discard_cb(self):
+ self.closewindows()
+
+ if self.settings[util.SETTINGS_KEYS[8]]:
+ self.parentwindow.anim.start_animation(False)
+ self.isopened = True
+ self.performcheck = True
+ else:
+ self.close()
+
+ # !SECTION Callbacks
+
+ # ----------------------------------------------------------------- Actions
+ # SECTION Actions ---------------------------------------------------------
+ # --------------------------------- updatecurrentvalues
+ # NOTE updatecurrentvalues ----------------------------
+ def updatecurrentvalues(self):
+ for i in range(len(util.SETTINGS_KEYS)):
+ self.currentsettings[util.SETTINGS_KEYS[i]] = self.settings[util.SETTINGS_KEYS[i]]
+ if util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "bool":
+ getattr(self, util.SETTINGS_KEYS[i]).setChecked(bc(self.currentsettings[util.SETTINGS_KEYS[i]]))
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "text":
+ getattr(self, util.SETTINGS_KEYS[i]).setText(self.currentsettings[util.SETTINGS_KEYS[i]])
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "intval":
+ getattr(self, util.SETTINGS_KEYS[i]).setValue(int(self.currentsettings[util.SETTINGS_KEYS[i]]))
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "cbx":
+ getattr(self, util.SETTINGS_KEYS[i]).setCurrentText(str(self.currentsettings[util.SETTINGS_KEYS[i]]))
+
+ # ------------------------------------------ fieldsetup
+ # NOTE fieldsetup -------------------------------------
+ def fieldsetup(self):
+ for i in range(len(util.SETTINGS_KEYS)):
+ if util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "bool":
+ getattr(self, util.SETTINGS_KEYS[i]).setChecked(bc(self.currentsettings[util.SETTINGS_KEYS[i]]))
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "text":
+ getattr(self, util.SETTINGS_KEYS[i]).setText(self.currentsettings[util.SETTINGS_KEYS[i]])
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "intval":
+ getattr(self, util.SETTINGS_KEYS[i]).setValue(int(self.currentsettings[util.SETTINGS_KEYS[i]]))
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "cbx":
+ getattr(self, util.SETTINGS_KEYS[i]).setCurrentText(str(self.currentsettings[util.SETTINGS_KEYS[i]]))
+ try:
+ getattr(self, util.SETTINGS_KEYS[i]).installEventFilter(self)
+ except (AttributeError, TypeError):
+ pass
+
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print(self.currentsettings)
+
+ # ------------------------------------- checkforchanges
+ # NOTE checkforchanges --------------------------------
+ def checkforchanges(self):
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print(len(util.SETTINGS_KEYS))
+ for i in range(len(util.SETTINGS_KEYS)):
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print(i)
+ if util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "bool":
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Name: ", getattr(self, util.SETTINGS_KEYS[i]).objectName())
+ print("Shown settings: ", getattr(self, util.SETTINGS_KEYS[i]).isChecked())
+ print("Current settings: ", bc(self.currentsettings[util.SETTINGS_KEYS[i]]))
+ if getattr(self, util.SETTINGS_KEYS[i]).isChecked() != bc(self.currentsettings[util.SETTINGS_KEYS[i]]):
+ if util.SETTINGS_KEYS[i] == util.SETTINGS_KEYS[0]:
+ self.resetdb = True
+ elif util.SETTINGS_KEYS[i] == util.SETTINGS_KEYS[8]:
+ self.waitforclose = True
+ elif util.SETTINGS_KEYS[i] == util.SETTINGS_KEYS[12]:
+ self.modifylayout = True
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Offending item: ", i)
+ return True
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "text":
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Name: ", getattr(self, util.SETTINGS_KEYS[i]).objectName())
+ print("Shown settings: ", getattr(self, util.SETTINGS_KEYS[i]).text())
+ print("Current settings: ", self.currentsettings[util.SETTINGS_KEYS[i]])
+ if getattr(self, util.SETTINGS_KEYS[i]).text() != self.currentsettings[util.SETTINGS_KEYS[i]]:
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Offending item: ", i)
+ return True
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "intval":
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Name: ", getattr(self, util.SETTINGS_KEYS[i]).objectName())
+ print("Shown settings: ", getattr(self, util.SETTINGS_KEYS[i]).value())
+ print("Current settings: ", self.currentsettings[util.SETTINGS_KEYS[i]])
+ if getattr(self, util.SETTINGS_KEYS[i]).value() != int(self.currentsettings[util.SETTINGS_KEYS[i]]):
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Offending item: ", i)
+ return True
+ elif util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] == "cbx":
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Name: ", getattr(self, util.SETTINGS_KEYS[i]).objectName())
+ print("Shown settings: ", getattr(self, util.SETTINGS_KEYS[i]).currentText())
+ print("Current settings: ", str(self.currentsettings[util.SETTINGS_KEYS[i]]))
+ if getattr(self, util.SETTINGS_KEYS[i]).currentText() != str(
+ self.currentsettings[util.SETTINGS_KEYS[i]]):
+ if self.isdebug and self.isdebug.level in {"ALL"}:
+ print("Offending item: ", i)
+ return True
+ return False
+
+ # ------------------------------------------- savecheck
+ # NOTE savecheck --------------------------------------
+ def savecheck(self):
+ buttonindex = hou.ui.displayMessage(
+ "Save changes?",
+ buttons=('Save', 'Discard'),
+ default_choice=0,
+ title="Unsaved Changes:"
+ )
+ if buttonindex == 0:
+ self.save_cb()
+ self.hkholder = ""
+ elif buttonindex == 1:
+ self.hkholder = ""
+
+ # ------------------------------------ closeroutine
+ # NOTE closeroutine -------------------------------
+ def closeroutine(self):
+ if self.performcheck:
+ if self.checkforchanges():
+ self.savecheck()
+ if self.animatedsettings.isChecked() and not self.waitforclose:
+ self.closewindows()
+ self.parentwindow.anim.start_animation(False)
+ self.isopened = True
+ return True
+ elif self.waitforclose:
+ self.closewindows()
+ self.close()
+ self.parentwindow.close()
+ return True
+ else:
+ self.closewindows()
+ self.close()
+
+ # !SECTION Actions
+
+ # @formatter:off
+ def movesubwindows(self, pos, resize=False):
+ if self.about.isVisible():
+ if resize: self.about.move(self.about.x() + pos.x(), self.about.y())
+ else: self.about.move(self.about.x() + pos.x(), self.about.y() + pos.y())
+ if self.bugreport.isVisible():
+ if resize: self.bugreport.move(self.bugreport.x() + pos.x(), self.bugreport.y())
+ else: self.bugreport.move(self.bugreport.x() + pos.x(), self.bugreport.y() + pos.y())
+ if self.theme.isVisible():
+ if resize: self.theme.move(self.theme.x() + pos.x(), self.theme.y())
+ else: self.theme.move(self.theme.x() + pos.x(), self.theme.y() + pos.y())
+
+ # ------------------------------------------------------------- Events
+ # SECTION Events -----------------------------------------------------
+ # ------------------------------------- addeventfilters
+ # NOTE addeventfilters --------------------------------
+ def addeventfilters(self):
+ self.installEventFilter(self)
+ self.aboutbtn.installEventFilter(self)
+ self.themebtn.installEventFilter(self)
+ self.savedata.installEventFilter(self)
+ self.dbpath_btn.installEventFilter(self)
+ # self.cleardata.installEventFilter(self)
+ self.discarddata.installEventFilter(self)
+ self.bugreportbtn.installEventFilter(self)
+ self.ui.dbpath_lbl.installEventFilter(self)
+ self.ui.maxresults_lbl.installEventFilter(self)
+ self.ui.defaulthotkey_lbl.installEventFilter(self)
+
+ # ---------------------------------- removeeventfilters
+ # NOTE removeeventfilters -----------------------------
+ def removeeventfilters(self):
+ self.removeEventFilter(self)
+ self.aboutbtn.removeEventFilter(self)
+ self.themebtn.removeEventFilter(self)
+ self.savedata.removeEventFilter(self)
+ self.dbpath_btn.removeEventFilter(self)
+ # self.cleardata.removeEventFilter(self)
+ self.discarddata.removeEventFilter(self)
+ self.bugreportbtn.removeEventFilter(self)
+ self.ui.dbpath_lbl.removeEventFilter(self)
+ self.ui.maxresults_lbl.removeEventFilter(self)
+ self.ui.defaulthotkey_lbl.removeEventFilter(self)
+
+ def eventFilter(self, obj, event):
+ event_type = event.type()
+
+ # ------------------------------------------ Window
+ # NOTE Window -------------------------------------
+ if event_type == QtCore.QEvent.WindowActivate:
+ self.addeventfilters()
+ self.ui.isopened = True
+ self.performcheck = True
+
+ # ------------------------------------------- Mouse
+ # SECTION Mouse -----------------------------------
+ # ----------------------- MouseButtonPress
+ # NOTE MouseButtonPress ------------------
+ if event_type == QtCore.QEvent.MouseButtonPress:
+ if obj == self:
+ self.activateWindow()
+
+ # -------------------- MouseButtonDblClick
+ # NOTE MouseButtonDblClick ---------------
+ if event_type == QtCore.QEvent.MouseButtonDblClick:
+ if obj == self.defaulthotkey:
+ self.hkholder = self.defaulthotkey.text()
+ self.defaulthotkey.setText("")
+ self.defaulthotkey.setPlaceholderText("Input key sequence")
+ self.canedit = True
+
+ # ---------------------------------- Enter
+ # NOTE Enter -----------------------------
+ if event_type == QtCore.QEvent.Enter:
+ self.parentwindow.checktooltip(obj)
+
+ # ---------------------------------- Leave
+ # NOTE Leave -----------------------------
+ if event_type == QtCore.QEvent.Leave:
+ self.parentwindow.checktooltip(obj, True)
+
+ # -------------------------------- ToolTip
+ # NOTE ToolTip ---------------------------
+ if event_type == QtCore.QEvent.ToolTip:
+ return True
+ # !SECTION
+
+ # ---------------------------------------- Keypress
+ # SECTION Keypress --------------------------------
+ if event_type == QtCore.QEvent.KeyPress:
+ # ---------------------------------- Key_D
+ # NOTE Key_D -----------------------------
+ if event.key() == QtCore.Qt.Key_D:
+ if obj != self.defaulthotkey:
+ if not self.debugflag.isVisible():
+ self.debugflag.setVisible(True)
+
+ # ----------------------------- Key_Escape
+ # NOTE Key_Escape ------------------------
+ if event.key() == QtCore.Qt.Key_Escape:
+ if obj == self:
+ self.closeroutine()
+ return True
+
+ # ----------------------------------- else
+ # NOTE else ------------------------------
+ else:
+ if obj == self.defaulthotkey:
+ self.keyindex += 1
+ self.keystring = hou.qt.qtKeyToString(
+ event.key(),
+ int(event.modifiers()),
+ event.text()
+ )
+ if self.canedit:
+ if self.keystring not in ["Esc", "Backspace"]:
+ if self.defaulthotkey.hasFocus():
+ self.KeySequence = QtGui.QKeySequence(self.keystring).toString()
+ self.defaulthotkey.setText(self.KeySequence)
+ if self.keystring in ["Esc", "Backspace"]:
+ self.defaulthotkey.setText(self.hkholder)
+ # !SECTION
+
+ # -------------------------------------- Keyrelease
+ # SECTION Keyrelease ------------------------------
+ if event_type == QtCore.QEvent.KeyRelease:
+ if event.key() == QtCore.Qt.Key_Escape:
+ return QtCore.QObject.eventFilter(self, obj, event)
+ else:
+ self.keyindex -= 1
+ if self.keyindex == 0:
+ if self.defaulthotkey.text() == "":
+ self.defaulthotkey.setText(self.hkholder)
+ if self.defaulthotkey.text() != "":
+ self.canedit = False
+ # !SECTION
+
+ # ------------------------------------------- Close
+ # NOTE Close --------------------------------------
+ if event_type == QtCore.QEvent.Close:
+ self.ui.isopened = False
+ self.resetdb = False
+ self.parentwindow.opensettingstool.setChecked(False)
+ self.performcheck = True
+ if not self.parentwindow.isActiveWindow():
+ self.parentwindow.activateWindow()
+ self.removeeventfilters()
+
+ return QtCore.QObject.eventFilter(self, obj, event)
+
+ # !SECTION Events
+
+
+# class LinkLabel(QtWidgets.QLabel):
+# def __init__(self, parent, text):
+# super(LinkLabel, self).__init__(parent)
+#
+# self.setText(text)
+# self.setTextFormat(Qt.RichText)
+# self.setTextInteractionFlags(Qt.TextBrowserInteraction)
+# self.setOpenExternalLinks(True)
diff --git a/python3.7libs/searcher/searcher_settings_ui.py b/python3.7libs/searcher/searcher_settings_ui.py
new file mode 100644
index 0000000..f9e9ad0
--- /dev/null
+++ b/python3.7libs/searcher/searcher_settings_ui.py
@@ -0,0 +1,269 @@
+# -*- coding: utf-8 -*-
+import os
+hver = 0
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.')+1:])
+ from hutil.Qt import QtGui
+ from hutil.Qt import QtCore
+ from hutil.Qt import QtWidgets
+else:
+ from qtpy import QtGui
+ from qtpy import QtCore
+ from qtpy import QtWidgets
+
+def bc(v):
+ return str(v).lower() in ("yes", "true", "t", "1")
+
+
+class Ui_SearcherSettings(object):
+ def setupUi(self, SearcherSettings, width, height, animated):
+ self.width = width
+ self.height = height
+ self.animated = animated
+
+ SearcherSettings.setObjectName("SearcherSettings")
+ SearcherSettings.setWindowModality(QtCore.Qt.NonModal)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(SearcherSettings.sizePolicy().hasHeightForWidth())
+ SearcherSettings.setSizePolicy(sizePolicy)
+ SearcherSettings.setMinimumSize(QtCore.QSize(width, height))
+ SearcherSettings.setBaseSize(QtCore.QSize(0, 0))
+
+ self.gridLayout = QtWidgets.QGridLayout(SearcherSettings)
+ self.gridLayout.setContentsMargins(-1, -1, -1, -1)
+ self.gridLayout.setObjectName("gridLayout")
+ self.verticallayout = QtWidgets.QVBoxLayout()
+ self.verticallayout.setObjectName("verticalLayout")
+ self.verticallayout.setSpacing(10)
+
+ # ------------------------------------------------- headerrow
+ # NOTE headerrow --------------------------------------------
+ self.headerrow = QtWidgets.QHBoxLayout()
+ self.headerrow.setObjectName("headerrow")
+
+ self.projectTitle = QtWidgets.QLabel(SearcherSettings)
+ font = QtGui.QFont()
+ font.setPointSize(15)
+ self.projectTitle.setFont(font)
+ self.projectTitle.setAlignment(QtCore.Qt.AlignCenter)
+ self.projectTitle.setObjectName("projectTitle")
+ self.headerrow.addWidget(self.projectTitle)
+
+ spaceritem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.headerrow.addItem(spaceritem)
+
+ self.animatedsettings_chk = QtWidgets.QCheckBox(SearcherSettings)
+ self.animatedsettings_chk.setLayoutDirection(QtCore.Qt.RightToLeft)
+ self.animatedsettings_chk.setObjectName("animatedsettings_chk")
+ self.headerrow.addWidget(self.animatedsettings_chk)
+
+ self.windowsize_chk = QtWidgets.QCheckBox(SearcherSettings)
+ self.windowsize_chk.setLayoutDirection(QtCore.Qt.RightToLeft)
+ self.windowsize_chk.setObjectName("windowsize_chk")
+ self.headerrow.addWidget(self.windowsize_chk)
+ self.verticallayout.addLayout(self.headerrow)
+
+ self.line = QtWidgets.QFrame(SearcherSettings)
+ self.line.setFrameShape(QtWidgets.QFrame.HLine)
+ self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.line.setObjectName("line")
+ self.verticallayout.addWidget(self.line)
+
+ # ------------------------------------------------- secondrow
+ # NOTE Second Row -------------------------------------------
+ self.secondrow = QtWidgets.QHBoxLayout()
+ self.secondrow.setObjectName("secondrow")
+
+ # self.lang_cbox = QtWidgets.QComboBox(SearcherSettings)
+ # self.lang_cbox.setObjectName("lang_cbox")
+ # self.lang_cbox.addItem("")
+ # self.secondrow.addWidget(self.lang_cbox)
+
+ spaceritem = QtWidgets.QSpacerItem(
+ 40, 20,
+ QtWidgets.QSizePolicy.Expanding,
+ QtWidgets.QSizePolicy.Minimum
+ )
+ self.secondrow.addItem(spaceritem)
+
+ self.maxresults_lbl = QtWidgets.QLabel(SearcherSettings)
+ self.maxresults_lbl.setObjectName("maxresults_lbl")
+ self.secondrow.addWidget(self.maxresults_lbl)
+ self.maxresults_txt = QtWidgets.QSpinBox(SearcherSettings)
+ self.maxresults_txt.setMinimum(1)
+ self.maxresults_txt.setMaximum(9999)
+ self.maxresults_txt.setObjectName("maxresults_txt")
+ self.secondrow.addWidget(self.maxresults_txt)
+
+ self.inmemory_chk = QtWidgets.QCheckBox(SearcherSettings)
+ self.inmemory_chk.setLayoutDirection(QtCore.Qt.RightToLeft)
+ self.inmemory_chk.setTristate(False)
+ self.inmemory_chk.setObjectName("inmemory_chk")
+ self.secondrow.addWidget(self.inmemory_chk)
+
+ self.verticallayout.addLayout(self.secondrow)
+
+ # -------------------------------------------------- thirdrow
+ # NOTE Third Row --------------------------------------------
+ self.thirdrow = QtWidgets.QHBoxLayout()
+ self.thirdrow.setObjectName("thirdrow")
+
+ self.defaulthotkey_lbl = QtWidgets.QLabel(SearcherSettings)
+ self.defaulthotkey_lbl.setObjectName("defaulthotkey_lbl")
+ self.thirdrow.addWidget(self.defaulthotkey_lbl)
+
+ self.defaulthotkey_txt = QtWidgets.QLineEdit(SearcherSettings)
+ self.defaulthotkey_txt.setToolTip("")
+ self.defaulthotkey_txt.setReadOnly(True)
+ self.defaulthotkey_txt.setObjectName("defaulthotkey_txt")
+ self.thirdrow.addWidget(self.defaulthotkey_txt)
+
+ self.hotkey_icon = QtWidgets.QToolButton(SearcherSettings)
+ self.hotkey_icon.setPopupMode(QtWidgets.QToolButton.InstantPopup)
+ self.hotkey_icon.setObjectName("hotkey_icon")
+ self.thirdrow.addWidget(self.hotkey_icon)
+ self.verticallayout.addLayout(self.thirdrow)
+
+ # ------------------------------------------------- fourthrow
+ # NOTE Fourth Row -------------------------------------------
+ self.fourthrow = QtWidgets.QHBoxLayout()
+ self.fourthrow.setObjectName("fourthrow")
+
+ self.dbpath_lbl = QtWidgets.QLabel(SearcherSettings)
+ self.dbpath_lbl.setObjectName("dbpath_lbl")
+ self.fourthrow.addWidget(self.dbpath_lbl)
+
+ self.databasepath_txt = QtWidgets.QLineEdit(SearcherSettings)
+ self.databasepath_txt.setObjectName("databasepath_txt")
+ self.fourthrow.addWidget(self.databasepath_txt)
+
+ self.dbpath_icon = QtWidgets.QToolButton(SearcherSettings)
+ self.dbpath_icon.setObjectName("dbpath_icon")
+ self.fourthrow.addWidget(self.dbpath_icon)
+
+ self.verticallayout.addLayout(self.fourthrow)
+
+ # -------------------------------------------------- fifthrow
+ # NOTE Fifth Row --------------------------------------------
+ self.fifthrow = QtWidgets.QHBoxLayout()
+ self.fifthrow.setObjectName("fifthrow")
+
+ # self.maint_lbl = QtWidgets.QLabel(SearcherSettings)
+ # self.maint_lbl.setObjectName("maint_lbl")
+ # self.fifthrow.addWidget(self.maint_lbl)
+
+ # self.metrics_chk = QtWidgets.QCheckBox(SearcherSettings)
+ # self.metrics_chk.setLayoutDirection(QtCore.Qt.RightToLeft)
+ # self.metrics_chk.setTristate(False)
+ # self.metrics_chk.setObjectName("metrics_chk")
+ # self.fifthrow.addWidget(self.metrics_chk)
+
+ # self.cleardata_btn = QtWidgets.QPushButton(SearcherSettings)
+ # self.cleardata_btn.setObjectName("cleardata_btn")
+ # self.fifthrow.addWidget(self.cleardata_btn)
+
+ # self.verticallayout.addLayout(self.fifthrow)
+
+ # ---------------------------------------------------- Spacer
+ self.line2 = QtWidgets.QFrame(SearcherSettings)
+ self.line2.setFrameShape(QtWidgets.QFrame.HLine)
+ self.line2.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.line2.setObjectName("line2")
+ self.verticallayout.addWidget(self.line2)
+ # ---------------------------------------------------- Spacer
+
+ # -------------------------------------------------- sixthrow
+ # NOTE Sixth Row --------------------------------------------
+ self.sixthrow = QtWidgets.QHBoxLayout()
+ self.sixthrow.setObjectName("sixthrow")
+
+ self.about_btn = QtWidgets.QToolButton(SearcherSettings)
+ self.about_btn.setObjectName("about")
+ self.sixthrow.addWidget(self.about_btn)
+
+ self.bug_btn = QtWidgets.QToolButton(SearcherSettings)
+ self.bug_btn.setObjectName("bugreport")
+ self.sixthrow.addWidget(self.bug_btn)
+
+ self.theme_btn = QtWidgets.QToolButton(SearcherSettings)
+ self.theme_btn.setObjectName("theme")
+ self.sixthrow.addWidget(self.theme_btn)
+
+ spacerItem1 = QtWidgets.QSpacerItem(40, 25, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
+ self.sixthrow.addItem(spacerItem1)
+
+
+ self.metrics_chk = QtWidgets.QCheckBox(SearcherSettings)
+ self.metrics_chk.setLayoutDirection(QtCore.Qt.RightToLeft)
+ self.metrics_chk.setTristate(False)
+ self.metrics_chk.setObjectName("metrics_chk")
+ self.sixthrow.addWidget(self.metrics_chk)
+
+
+ self.debuglevel_cbx = QtWidgets.QComboBox(SearcherSettings)
+ self.debuglevel_cbx.setObjectName("debuglevel_cbx")
+ self.sixthrow.addWidget(self.debuglevel_cbx)
+
+ self.debugflag_chk = QtWidgets.QCheckBox(SearcherSettings)
+ self.debugflag_chk.setLayoutDirection(QtCore.Qt.RightToLeft)
+ self.debugflag_chk.setObjectName("debugflag_chk")
+ self.sixthrow.addWidget(self.debugflag_chk)
+
+ self.discard_btn = QtWidgets.QPushButton(SearcherSettings)
+ self.discard_btn.setObjectName("discard_btn")
+ self.sixthrow.addWidget(self.discard_btn)
+
+ self.save_btn = QtWidgets.QPushButton(SearcherSettings)
+ self.save_btn.setObjectName("save_btn")
+ self.sixthrow.addWidget(self.save_btn)
+
+ self.verticallayout.addLayout(self.sixthrow)
+
+ if not self.animated:
+ self.gridLayout.addLayout(self.verticallayout, 1, 0, 1, 1)
+
+ # -----------------------------------------------------------
+ self.retranslateUi(SearcherSettings)
+ QtCore.QMetaObject.connectSlotsByName(SearcherSettings)
+
+ def retranslateUi(self, SearcherSettings):
+ _translate = QtCore.QCoreApplication.translate
+ SearcherSettings.setWindowTitle(_translate("SearcherSettings", "Form"))
+
+ # ------------------------------------------------- headerrow
+ self.projectTitle.setText(_translate("SearcherSettings", "Settings"))
+ self.animatedsettings_chk.setText(_translate("SearcherSettings", "Use Animated Menus:"))
+ self.windowsize_chk.setText(_translate("SearcherSettings", "Remember Search Window Size"))
+
+ # ------------------------------------------------- secondrow
+ self.maxresults_lbl.setText(_translate("SearcherSettings", "Maximum Search Results"))
+ self.inmemory_chk.setText(_translate("SearcherSettings", "Use In-Memory Database"))
+
+ # -------------------------------------------------- thirdrow
+ # self.label_3.setText(_translate("SearcherSettings", "Language:"))
+ # self.lang_cbox.setCurrentText(_translate("SearcherSettings", "English"))
+ # self.lang_cbox.setItemText(0, _translate("SearcherSettings", "English"))
+ self.defaulthotkey_lbl.setText(_translate("SearcherSettings", "Hotkey to use for opening unassigned items: "))
+ self.defaulthotkey_txt.setPlaceholderText(_translate("SearcherSettings", "Double Click"))
+ self.hotkey_icon.setText(_translate("SearcherSettings", "..."))
+
+ # ------------------------------------------------- fourthrow
+ self.dbpath_lbl.setText(_translate("SearcherSettings", "Database location: "))
+ self.dbpath_icon.setText(_translate("SearcherSettings", "..."))
+
+ # -------------------------------------------------- fifthrow
+ # self.maint_lbl.setText(_translate("SearcherSettings", "Maintenance utilities:"))
+ # self.cleardata_btn.setText(_translate("SearcherSettings", "Clear Data"))
+
+ # ------------------------------------------------- sixthrow
+ self.about_btn.setText(_translate("SearcherSettings", "..."))
+ self.bug_btn.setText(_translate("SearcherSettings", "..."))
+ self.theme_btn.setText(_translate("SearcherSettings", "..."))
+ self.metrics_chk.setText(_translate("SearcherSettings", "Metrics"))
+ self.debugflag_chk.setText(_translate("SearcherSettings", "Debug Mode"))
+ self.discard_btn.setText(_translate("SearcherSettings", "Discard"))
+ self.save_btn.setText(_translate("SearcherSettings", "Save"))
+
diff --git a/python3.7libs/searcher/searcher_ui.py b/python3.7libs/searcher/searcher_ui.py
new file mode 100644
index 0000000..53bd43a
--- /dev/null
+++ b/python3.7libs/searcher/searcher_ui.py
@@ -0,0 +1,284 @@
+from __future__ import print_function
+from __future__ import absolute_import
+
+import os
+import sys
+from searcher import HelpButton
+from searcher import language_en as la
+
+hver = 0
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.')+1:])
+ from hutil.Qt import QtGui
+ from hutil.Qt import QtCore
+ from hutil.Qt import QtWidgets
+else:
+ from qtpy import QtGui
+ from qtpy import QtCore
+ from qtpy import QtWidgets
+
+
+# noinspection PyAttributeOutsideInit
+class Ui_Searcher(object):
+ def setupUi(self, Searcher, animated):
+ self.animated = animated
+ Searcher.setObjectName("Searcher")
+ Searcher.setWindowModality(QtCore.Qt.NonModal)
+ Searcher.setStyleSheet(u"background-color: rgb(42,42,42); border: 0px solid black")
+
+ self.mainlayout = QtWidgets.QVBoxLayout()
+ self.gridLayout = QtWidgets.QGridLayout()
+ self.gridLayout.setSpacing(0)
+ self.gridLayout.setContentsMargins(0, 0, 0, 0)
+
+ self.verticalLayout = QtWidgets.QVBoxLayout()
+ self.verticalLayout.setSpacing(0)
+
+ self.titlerow = QtWidgets.QHBoxLayout()
+ self.titlerow.setSpacing(5)
+
+ self.titlespacer1 = QtWidgets.QSpacerItem(
+ 8, 0,
+ QtWidgets.QSizePolicy.Fixed,
+ QtWidgets.QSizePolicy.Minimum
+ )
+
+ # ------------------------------------------ Header
+ # NOTE Header -------------------------------------
+ self.searcherlbl = QtWidgets.QLabel("Searcher")
+ font = QtGui.QFont()
+ font.setPointSize(15)
+ self.searcherlbl.setFont(font)
+ self.searcherlbl.setAlignment(QtCore.Qt.AlignCenter)
+
+ self.titlespacer2 = QtWidgets.QSpacerItem(
+ 40, 30,
+ QtWidgets.QSizePolicy.Expanding,
+ QtWidgets.QSizePolicy.Minimum
+ )
+
+ self.expander = QtWidgets.QToolButton()
+ self.expander.setObjectName("expander")
+
+ self.metricpos = QtWidgets.QToolButton()
+ self.metricpos.setObjectName("metricpos")
+
+ self.contexttoggle = QtWidgets.QPushButton()
+ self.contexttoggle.setObjectName("contexttoggle")
+
+ self.helpButton = HelpButton.HelpButton("main", la.TT_MW['helpButton'], 16, Searcher)
+ self.helpButton.setObjectName("helpButton")
+
+ self.pinwindow_btn = QtWidgets.QToolButton()
+ self.pinwindow_btn.setObjectName("pinwindow")
+
+ self.opensettings_btn = QtWidgets.QToolButton()
+ self.opensettings_btn.setObjectName("opensettingstool")
+
+ self.titlespacer3 = QtWidgets.QSpacerItem(
+ 8, 0,
+ QtWidgets.QSizePolicy.Fixed,
+ QtWidgets.QSizePolicy.Minimum
+ )
+
+ # ----------------------------------- Search Filter
+ # NOTE Search Filter ------------------------------
+ self.searchrow = QtWidgets.QHBoxLayout()
+ self.searchrow.setSpacing(0)
+ self.frame = QtWidgets.QFrame()
+ searchframe_details = QtWidgets.QSizePolicy(
+ QtWidgets.QSizePolicy.Expanding,
+ QtWidgets.QSizePolicy.Preferred
+ )
+ searchframe_details.setHorizontalStretch(0)
+ searchframe_details.setVerticalStretch(0)
+ searchframe_details.setHeightForWidth(
+ self.frame.sizePolicy().hasHeightForWidth())
+ self.frame.setSizePolicy(searchframe_details)
+ self.frame.setMinimumSize(QtCore.QSize(20, 20))
+ self.frame.setMaximumSize(QtCore.QSize(500, 200))
+ self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
+ self.frame.setFrameShadow(QtWidgets.QFrame.Plain)
+ self.frame.setStyleSheet(u"background-color: rgb(19, 19, 19); color: rgb(19, 19, 19);")
+ self.searchfilter_btn = QtWidgets.QToolButton(self.frame)
+ self.searchfilter_btn.setObjectName("searchfilter")
+ self.searchfilter_btn.setGeometry(QtCore.QRect(0, 0, 36, 36))
+ self.searchfilter_btn.setBaseSize(QtCore.QSize(30, 30))
+ self.searchfilter_btn.setStyleSheet(u"background-color: rgb(19, 19, 19);")
+ self.searchfilter_btn.setArrowType(QtCore.Qt.NoArrow)
+ self.searchfilter_btn.setParent(self.frame)
+
+ # -------------------------------------- Search Box
+ # NOTE Search Box ---------------------------------
+ self.searchbox_txt = QtWidgets.QLineEdit()
+ self.searchbox_txt.setObjectName("searchbox")
+ searchbox_details = QtWidgets.QSizePolicy(
+ QtWidgets.QSizePolicy.Expanding,
+ QtWidgets.QSizePolicy.Minimum
+ )
+ searchbox_details.setHorizontalStretch(99)
+ searchbox_details.setVerticalStretch(0)
+ # searchbox_details.setHeightForWidth(
+ # self.searchbox_txt.sizePolicy().hasHeightForWidth())
+ self.searchbox_txt.setSizePolicy(searchbox_details)
+ self.searchbox_txt.setMinimumSize(QtCore.QSize(50, 0))
+ self.searchbox_txt.setMouseTracking(False)
+ self.searchbox_txt.setStyleSheet(u"background-color: rgb(19, 19, 19);")
+ self.searchbox_txt.setFrame(False)
+
+ # ------------------------------------ Results Tree
+ # NOTE Results Tree -------------------------------
+ self.searchresults_tree = QtWidgets.QTreeWidget()
+ self.searchresults_tree.setObjectName("searchresultstree")
+
+ # Header ---------
+ __qtreewidgetitem = QtWidgets.QTreeWidgetItem()
+ __qtreewidgetitem.setText(0, u"1")
+ resultstree_header = QtGui.QFont()
+ resultstree_header.setPointSize(9)
+ __qtreewidgetitem.setFont(0, resultstree_header)
+ self.searchresults_tree.setHeaderItem(__qtreewidgetitem)
+
+ resultstree_details = QtWidgets.QSizePolicy(
+ QtWidgets.QSizePolicy.Preferred,
+ QtWidgets.QSizePolicy.Expanding
+ )
+ resultstree_details.setHorizontalStretch(0)
+ resultstree_details.setVerticalStretch(0)
+ self.searchresults_tree.setSizePolicy(resultstree_details)
+
+ resultstree_font = QtGui.QFont()
+ resultstree_font.setPointSize(9)
+ self.searchresults_tree.setFont(resultstree_font)
+
+ self.searchresults_tree.setMouseTracking(False)
+ self.searchresults_tree.setFocusPolicy(QtCore.Qt.NoFocus)
+ self.searchresults_tree.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.searchresults_tree.setLineWidth(0)
+
+ self.searchresults_tree.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
+ self.searchresults_tree.setAlternatingRowColors(True)
+ self.searchresults_tree.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
+ self.searchresults_tree.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
+
+ # -------------------------------------- Info Panel
+ # NOTE Info Panel ---------------------------------
+ self.infobar = QtWidgets.QHBoxLayout()
+ self.infobar.setObjectName("infobar")
+ self.infobargrid = QtWidgets.QGridLayout()
+ self.infobargrid.setObjectName("infobargrid")
+
+ # -------------------------------------- Info Panel
+ # NOTE Info Panel ---------------------------------
+ self.info_lbl = QtWidgets.QLabel()
+ self.infolbl_font = QtGui.QFont()
+ self.infolbl_font.setPointSize(9)
+ self.infolbl_font.setBold(False)
+ self.infolbl_font.setWeight(40)
+ self.info_lbl.setFont(self.infolbl_font)
+ self.info_lbl.setStyleSheet(
+ u"background-color: rgba(11, 11, 11, 0); border-bottom: 1px solid rgb(100, 100, 100);")
+ self.info_lbl.setMargin(3)
+ self.info_lbl.setIndent(5)
+
+ # -------------------------------------- Info Panel
+ # NOTE Info Panel ---------------------------------
+ self.overlay = overlayLabel(self.info_lbl)
+ self.overlay.setFont(self.infolbl_font)
+ self.overlay.setStyleSheet(u"background-color: rgb(11, 11, 11); border-bottom: 1px solid rgb(100, 100, 100); ")
+ self.overlay.setMargin(3)
+ self.overlay.setIndent(5)
+
+ # -------------------------------------- Info Panel
+ # NOTE Info Panel ---------------------------------
+ self.treetotal_lbl = QtWidgets.QLabel()
+ self.treetotal_lbl.setObjectName("treetotal_lbl")
+ # Size ----------
+ treetotal_size = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
+ treetotal_size.setHorizontalStretch(0)
+ treetotal_size.setVerticalStretch(0)
+ treetotal_size.setHeightForWidth(self.treetotal_lbl.sizePolicy().hasHeightForWidth())
+ self.treetotal_lbl.setSizePolicy(treetotal_size)
+ self.treetotal_lbl.setMinimumSize(QtCore.QSize(160, 0))
+ self.treetotal_lbl.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter)
+
+ # Style ---------
+ self.treetotallbl_font = QtGui.QFont()
+ self.treetotallbl_font.setPointSize(9)
+ self.treetotallbl_font.setBold(False)
+ self.treetotallbl_font.setWeight(50)
+ self.treetotal_lbl.setFont(self.treetotallbl_font)
+ self.treetotal_lbl.setStyleSheet(
+ u"background-color: rgb(11, 11, 11); border-bottom: 1px solid rgb(100, 100, 100); ")
+ self.treetotal_lbl.setMargin(3)
+ self.treetotal_lbl.setIndent(5)
+
+ # ------------------------------------------ Layout
+ # NOTE Layout -------------------------------------
+ self.titlerow.addItem(self.titlespacer1)
+ self.titlerow.addWidget(self.searcherlbl)
+ self.titlerow.addItem(self.titlespacer2)
+ self.titlerow.addWidget(self.expander)
+ self.titlerow.addWidget(self.metricpos)
+ self.titlerow.addWidget(self.contexttoggle)
+ self.titlerow.addWidget(self.helpButton)
+ self.titlerow.addWidget(self.pinwindow_btn)
+ self.titlerow.addWidget(self.opensettings_btn)
+ self.titlerow.addItem(self.titlespacer3)
+ self.verticalLayout.addLayout(self.titlerow)
+
+ # self.searchrow.addWidget(self.frame)
+ self.searchgrid = QtWidgets.QGridLayout()
+ self.searchgrid.addWidget(self.frame, 1, 0, 1, 1)
+ self.searchgrid.addWidget(self.searchfilter_btn, 1, 0, 1, 1)
+ self.searchgrid.addWidget(self.searchbox_txt, 1, 1, 1, 1)
+ self.searchrow.addLayout(self.searchgrid)
+ self.verticalLayout.addLayout(self.searchrow)
+
+ self.verticalLayout.addWidget(self.searchresults_tree)
+ self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1)
+
+ self.infobargrid.addWidget(self.overlay, 1, 0, 1, 1)
+ self.infobargrid.addWidget(self.info_lbl, 1, 0, 1, 1)
+ self.infobargrid.addWidget(self.treetotal_lbl, 1, 1, 1, 1)
+ self.infobar.addLayout(self.infobargrid)
+ self.gridLayout.addLayout(self.infobar, 3, 0, 1, 1)
+
+ self.mainlayout.setContentsMargins(0, 0, 0, 0)
+
+ # --------------------------------------- ResizeHandles
+ # NOTE ResizeHandles ----------------------------------
+ self.leftresize = QtWidgets.QSizeGrip(self.info_lbl)
+ self.leftresize.setObjectName("resizeleft")
+ self.leftresize.setMaximumSize(QtCore.QSize(25, 25))
+ self.leftresize.setStyleSheet(u"color: rgba(0, 0, 0, 0); background-color: rgba(0, 0, 0, 0);")
+ pos = self.info_lbl.mapToGlobal(
+ QtCore.QPoint(-3, 0))
+ self.leftresize.setGeometry(
+ pos.x(),
+ pos.y(),
+ self.leftresize.width(),
+ self.leftresize.height()
+ )
+
+ self.rightresize = QtWidgets.QSizeGrip(self.treetotal_lbl)
+ self.rightresize.setMaximumSize(QtCore.QSize(25, 25))
+ self.rightresize.setObjectName("resizeright")
+ self.rightresize.setStyleSheet(u"color: rgba(0, 0, 0, 0); background-color: rgba(0, 0, 0, 0);")
+ pos = self.treetotal_lbl.mapToGlobal(
+ QtCore.QPoint(138, 0))
+ self.rightresize.setGeometry(
+ pos.x(),
+ pos.y(),
+ self.rightresize.width(),
+ self.rightresize.height()
+ )
+ self.vlayout = self.gridLayout
+ # self.mainlayout.addLayout(self.gridLayout)
+
+
+class overlayLabel(QtWidgets.QLabel):
+ def __init__(self, parent=None):
+ super(overlayLabel, self).__init__(parent)
+ self.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
diff --git a/python3.7libs/searcher/searchersetup.py b/python3.7libs/searcher/searchersetup.py
new file mode 100644
index 0000000..06c3250
--- /dev/null
+++ b/python3.7libs/searcher/searchersetup.py
@@ -0,0 +1,465 @@
+from __future__ import print_function
+from __future__ import absolute_import
+
+from searcher import settings_data
+from searcher import util
+from searcher import platformselect
+from searcher import ptime as ptime
+from searcher import language_en as la
+
+from peewee import *
+from peewee import SQL
+from playhouse.sqlite_ext import SqliteExtDatabase, RowIDField, FTS5Model, SearchField
+# from playhouse.apsw_ext import APSWDatabase
+import inspect
+import threading
+import time
+import hou
+import hdefereval as hd
+import os
+import sys
+
+# info
+__author__ = "instance.id"
+__copyright__ = "2020 All rights reserved."
+__status__ = "Release Candidate"
+
+# current_file_path = os.path.abspath(
+# inspect.getsourcefile(lambda: 0)
+# )
+
+def get_platform():
+ return getattr(hou.session, "PLATFORM", None)
+
+
+def get_settings():
+ return getattr(hou.session, "SETTINGS", None)
+
+
+def get_dbconnection():
+ return getattr(hou.session, "DBCONNECTION", None)
+
+
+# scriptpath = os.path.dirname(current_file_path)
+dbfile = "searcher.db"
+dbpath = os.path.join(
+ hou.homeHoudiniDirectory(), 'Searcher', dbfile
+)
+
+hou.session.SETTINGS = {}
+hou.session.DBCONNECTION = DatabaseProxy()
+db = DatabaseProxy()
+
+
+# --------------------------------------------------------- DatabaseModels
+# SECTION DatabaseModels -------------------------------------------------
+# ------------------------------------------------ Settings
+# NOTE Settings -------------------------------------------
+class Settings(Model):
+ id = IntegerField(unique=True)
+ indexvalue = IntegerField()
+ defaulthotkey = TextField()
+ searchdescription = IntegerField()
+ searchprefix = IntegerField()
+ searchcurrentcontext = IntegerField()
+ lastused = TextField()
+
+ class Meta:
+ table_name = 'settings'
+ database = db
+
+
+# ------------------------------------------------ HContext
+# NOTE HContext -------------------------------------------
+class HContext(Model):
+ id = AutoField()
+ context = TextField(unique=True)
+ title = TextField()
+ description = TextField()
+
+ class Meta:
+ table_name = 'hcontext'
+ database = db
+
+
+# # ------------------------------------------- HContextIndex
+# # NOTE HContextIndex --------------------------------------
+# class HContextIndex(FTS5Model):
+# # rowid = RowIDField()
+# context = SearchField()
+# title = SearchField()
+# description = SearchField()
+
+# class Meta:
+# database = db
+# options = {'prefix': [2, 3], 'tokenize': 'porter'}
+
+# ------------------------------------------------- Hotkeys
+# NOTE Hotkeys --------------------------------------------
+class Hotkeys(Model):
+ hotkey_symbol = CharField(unique=True)
+ label = CharField()
+ description = TextField()
+ assignments = TextField()
+ context = TextField()
+
+ class Meta:
+ table_name = 'hotkeys'
+ database = db
+
+
+# -------------------------------------------- HotkeysIndex
+# NOTE HotkeysIndex ---------------------------------------
+class HotkeysIndex(FTS5Model):
+ # rowid = RowIDField()
+ hotkey_symbol = SearchField(unindexed=True)
+ label = SearchField()
+ description = SearchField()
+ assignments = SearchField(unindexed=True)
+ context = SearchField(unindexed=True)
+
+ class Meta:
+ # table_name = 'hotkeysindex'
+ database = db
+ options = {'prefix': [2, 3], 'tokenize': 'porter'}
+
+
+# !SECTION DatabaseModels
+
+def create_tables(dbc):
+ dbc.create_tables([Settings, HContext, Hotkeys, HotkeysIndex])
+
+
+def worker():
+ hd.executeInMainThreadWithResult(updatecontext)
+
+
+def py_unique(data):
+ return list(set(data))
+
+
+# ------------------------------------------------- getdata
+# NOTE getdata --------------------------------------------
+def getdata():
+ rval = []
+ contextdata = []
+ hotkeydata = []
+
+ def getcontexts(r, context_symbol, root):
+ keys = None
+ branches = hou.hotkeys.contextsInContext(context_symbol)
+ for branch in branches:
+ branch_path = "%s/%s" % (r, branch['label'])
+ contextdata.append({
+ 'context': branch['symbol'],
+ 'title': branch['label'],
+ 'description': branch['help']
+ })
+ commands = hou.hotkeys.commandsInContext(branch['symbol'])
+ for command in commands:
+ keys = hou.hotkeys.assignments(command['symbol'])
+ ctx = command['symbol'].rsplit('.', 1)
+ hotkeydata.append({
+ 'hotkey_symbol': command['symbol'],
+ 'label': command['label'],
+ 'description': command['help'],
+ 'assignments': " ".join(keys),
+ 'context': ctx[0]
+ })
+ getcontexts(branch_path, branch['symbol'], root)
+
+ getcontexts("", "", rval)
+ return contextdata, hotkeydata
+
+
+# -------------------------------------------- initialsetup
+# NOTE initialsetup ---------------------------------------
+def initialsetup(cur):
+ currentidx = hou.hotkeys.changeIndex()
+ chindex = getchangeindex(cur)
+
+ if len(chindex) == 0:
+ chindex = int(currentidx)
+ updatechangeindex(chindex, True)
+ updatedataasync()
+ if hou.isUIAvailable():
+ try:
+ hou.ui.setStatusMessage(
+ la.MESSAGES['initialsetup1'], severity=hou.severityType.Message)
+ except:
+ print(la.MESSAGES['initialsetup1'])
+ else:
+ print(la.MESSAGES['initialsetup1'])
+ else:
+ chindex = int(chindex[0][0])
+
+ if int(currentidx) != chindex:
+ getlastusedhk(cur)
+ updatedataasync()
+ updatechangeindex(int(currentidx))
+
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ la.MESSAGES['initialsetup2'], severity=hou.severityType.Message)
+
+
+# --------------------------------------------------------------- Retrieve
+# SECTION Retrieve -------------------------------------------------------
+# ------------------------------------------ getchangeindex
+# NOTE getchangeindex -------------------------------------
+def getchangeindex(cur):
+ try:
+ cur.execute("SELECT indexvalue FROM settings")
+ result = cur.fetchall()
+ return result
+ except(AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ (la.DBERRORMSG['getchangeindex'] + str(e)), severity=hou.severityType.Warning)
+ else:
+ print(la.DBERRORMSG['getchangeindex'] + str(e))
+
+
+# ------------------------------------------- getlastusedhk
+# NOTE getlastusedhk --------------------------------------
+def getlastusedhk(cur):
+ settingdata = get_settings()
+ lastkey = settingdata[util.SETTINGS_KEYS[11]]
+ try:
+ if str(lastkey) != "":
+ lasthk = str(lastkey).split(' ')
+ hkcheck = hou.hotkeys.assignments(str(lasthk[0]))
+
+ if len(hkcheck) is 0:
+ settingdata[util.SETTINGS_KEYS[11]] = ""
+ settings_data.savesettings(settingdata)
+ return
+
+ rmresult = hou.hotkeys.removeAssignment(str(lasthk[0]).strip(), str(lasthk[1]).strip())
+ if rmresult:
+ hkcheck = hou.hotkeys.assignments(str(lasthk[0]))
+ hou.hotkeys.saveOverrides()
+ if len(hkcheck) is 0:
+ settingdata[util.SETTINGS_KEYS[11]] = ""
+ settings_data.savesettings(settingdata)
+ currentidx = hou.hotkeys.changeIndex()
+ updatechangeindex(int(currentidx))
+ else:
+ hou.hotkeys.clearAssignments(str(lasthk[0]))
+ hou.hotkeys.saveOverrides()
+ hkcheck = hou.hotkeys.assignments(str(lasthk[0]))
+ if len(hkcheck) is 0:
+ settingdata[util.SETTINGS_KEYS[11]] = ""
+ settings_data.savesettings(settingdata)
+ currentidx = hou.hotkeys.changeIndex()
+ updatechangeindex(int(currentidx))
+ else:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ (la.DBERRORMSG['getlastusedhk3']), severity=hou.severityType.Warning)
+ else:
+ print(la.DBERRORMSG['getlastusedhk3'])
+ else:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ (la.DBERRORMSG['getlastusedhk2']), severity=hou.severityType.Warning)
+ else:
+ print(la.DBERRORMSG['getlastusedhk2'])
+
+ except(AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ (la.DBERRORMSG['getlastusedhk1'] + str(e)), severity=hou.severityType.Warning)
+ else:
+ print(la.DBERRORMSG['getlastusedhk1'] + str(e))
+
+
+# !SECTION
+
+# ----------------------------------------------------------------- Update
+# SECTION Update ---------------------------------------------------------
+# ------------------------------------------------ dbupdate
+# NOTE dbupdate -------------------------------------------
+def dbupdate(cur):
+ currentidx = hou.hotkeys.changeIndex()
+ chindex = getchangeindex(cur)
+
+ if int(currentidx) != chindex:
+ getlastusedhk(cur)
+ updatedataasync()
+ updatechangeindex(int(currentidx))
+
+
+# ----------------------------------------- updatedataasync
+# NOTE updatedataasync ------------------------------------
+def updatedataasync():
+ thread = threading.Thread(target=worker)
+ thread.daemon = True
+ thread.start()
+
+
+# --------------------------------------- updatechangeindex
+# NOTE updatechangeindex ----------------------------------
+def updatechangeindex(indexval, new=False):
+ try:
+ if new is True:
+ defaultkey = ""
+ for i in range(len(util.HOTKEYLIST)):
+ result = hou.hotkeys.findConflicts("h", util.HOTKEYLIST[i])
+ if not result:
+ defaultkey = util.HOTKEYLIST[i]
+
+ Settings.insert(
+ indexvalue=indexval,
+ defaulthotkey=defaultkey,
+ searchdescription=0,
+ searchprefix=0,
+ searchcurrentcontext=0,
+ lastused="",
+ id=1).execute()
+ else:
+ Settings.update(indexvalue=indexval).where(
+ Settings.id == 1).execute()
+ except(AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ (la.DBERRORMSG['updatechangeindex'] + str(e)), severity=hou.severityType.Warning)
+ else:
+ print(la.DBERRORMSG['updatechangeindex'] + str(e))
+
+
+# ------------------------------------------- updatecontext
+# NOTE updatecontext --------------------------------------
+def updatecontext(debug=False):
+ try:
+ cleardatabase()
+ ctxdata, hkeydata = getdata()
+ with db.atomic():
+ for data_dict in ctxdata:
+ HContext.replace_many(data_dict).execute()
+ with db.atomic():
+ for idx in hkeydata:
+ Hotkeys.replace_many(idx).execute()
+ HotkeysIndex.replace_many(idx).execute()
+
+ except(AttributeError, TypeError) as e:
+ hou.ui.setStatusMessage(
+ (la.DBERRORMSG['updatecontext'] + str(e)), severity=hou.severityType.Warning)
+
+
+# endregion
+
+# ------------------------------------------- cleardatabase
+# NOTE cleardatabase --------------------------------------
+def cleardatabase():
+ try:
+ delhk = "DELETE FROM hotkeys"
+ delctx = "DELETE FROM hcontext"
+ delhkindex = "DELETE FROM hotkeysindex"
+ db.cursor().execute(delhk)
+ db.cursor().execute(delctx)
+ db.cursor().execute(delhkindex)
+ result = db.cursor().fetchall()
+ return result
+
+ except(AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ (la.DBERRORMSG['cleardatabase'] + str(e)), severity=hou.severityType.Warning)
+ else:
+ print(la.DBERRORMSG['cleardatabase'] + str(e))
+
+
+# !SECTION
+
+def contextsetup():
+ searcher_context = "h.tool"
+ hou.hotkeys.addContext(searcher_context, "Searcher", "These keys apply to Searcher operations")
+
+ open_symbol = searcher_context + ":searcher::searcher"
+ hou.hotkeys.addCommand(
+ open_symbol,
+ "Searcher",
+ "Open the main Searcher interface window",
+ ["Ctrl+`"]
+ )
+
+
+def deferaction(action, val):
+ hd.executeDeferred(action, val)
+
+
+def checklasthk(cur):
+ getlastusedhk(cur)
+
+
+def main():
+ platform = platformselect.get_platform()
+
+ if not os.path.exists(settings_data.searcher_path):
+ os.mkdir(settings_data.searcher_path)
+ if not os.path.isfile(settings_data.searcher_settings):
+ if platform == "unix":
+ os.system(("touch %s" % settings_data.searcher_settings))
+ else:
+ open(settings_data.searcher_settings, "wt").close()
+ settings_data.createdefaults(platform)
+
+ hou.session.SETTINGS = settings_data.loadsettings()
+ settingdata = get_settings()
+
+ isdebug = util.Dbug(
+ settingdata[util.SETTINGS_KEYS[4]],
+ str(settingdata[util.SETTINGS_KEYS[10]]),
+ settingdata[util.SETTINGS_KEYS[12]],
+ settingdata[util.SETTINGS_KEYS[13]],
+ )
+
+ inmemory = (settingdata[util.SETTINGS_KEYS[0]])
+ if inmemory:
+ val = ':memory:'
+ else:
+ val = str(settingdata[util.SETTINGS_KEYS[1]])
+
+ db.initialize(
+ SqliteExtDatabase(
+ val,
+ pragmas=(
+ ("cache_size", -1024 * 64),
+ ("journal_mode", "off"),
+ ("temp_store", "memory"),
+ ("synchronous", 0)
+ )))
+
+ hou.session.DBCONNECTION = db
+ dbc = get_dbconnection()
+
+ time1 = ptime.time()
+ if inmemory:
+ create_tables(dbc)
+ cur = dbc.cursor()
+ initialsetup(cur)
+ else:
+ if not os.path.isfile(settingdata[util.SETTINGS_KEYS[1]]):
+ create_tables(dbc)
+ cur = dbc.cursor()
+ deferaction(initialsetup, cur)
+ else:
+ cur = dbc.cursor()
+ deferaction(dbupdate, cur)
+
+ time2 = ptime.time()
+
+ contextsetup()
+
+ if isdebug and isdebug.level in {"TIMER", "ALL"}:
+ res = ((time2 - time1) * 1000.0)
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ ('Startup took %0.4f ms' % res), severity=hou.severityType.Message)
+ else:
+ print('Startup took %0.4f ms' % res)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/python3.7libs/searcher/settings_data.py b/python3.7libs/searcher/settings_data.py
new file mode 100644
index 0000000..4c4a353
--- /dev/null
+++ b/python3.7libs/searcher/settings_data.py
@@ -0,0 +1,100 @@
+# region Imports
+from __future__ import print_function
+from __future__ import absolute_import
+
+from searcher import util
+from searcher import language_en as la
+
+import os
+import hou
+
+hver = 0
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.') + 1:])
+ from hutil.Qt import QtCore
+
+# ------------------------------------------------------ Setting Paths
+# SECTION Setting Paths ----------------------------------------------
+scriptpath = os.path.dirname(os.path.realpath(__file__))
+app_name = "Searcher"
+settingsfile = "searcher_settings.ini"
+dbfile = "searcher.db"
+searcher_path = os.path.join(
+ hou.homeHoudiniDirectory(), app_name
+)
+searcher_settings = os.path.join(
+ searcher_path, settingsfile
+)
+defaultdbpath = os.path.join(
+ searcher_path, dbfile
+)
+settingsdata = QtCore.QSettings(searcher_settings, QtCore.QSettings.IniFormat)
+
+
+# !SECTION Setting Paths
+
+# -------------------------------------------------- Setting Functions
+# SECTION Setting Functions ------------------------------------------
+# -------------------------------------- createdefaults
+# NOTE createdefaults ---------------------------------
+def createdefaults(platform):
+ def_set = util.DEFAULT_SETTINGS
+ def_set[util.SETTINGS_KEYS[1]] = str(defaultdbpath)
+ if platform == "unix":
+ def_set[util.SETTINGS_KEYS[8]] = True
+ settingsdata.beginGroup('Searcher')
+ try:
+ for i in range(len(util.SETTINGS_KEYS)):
+ settingsdata.setValue(util.SETTINGS_KEYS[i], def_set[util.SETTINGS_KEYS[i]])
+ except (AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ (la.SETTINGSMESSAGES['createdefaults'] + str(e)), severity=hou.severityType.Warning)
+ else:
+ print(la.SETTINGSMESSAGES['createdefaults'] + str(e))
+ settingsdata.endGroup()
+ settingsdata.setIniCodec('UTF-8')
+ settingsdata.sync()
+
+
+# ---------------------------------------- savesettings
+# NOTE savesettings -----------------------------------
+def savesettings(settingdict):
+ print("Save Settings?")
+ try:
+ settingsdata.beginGroup('Searcher')
+ keys = list(settingdict.keys())
+ for i in range(len(keys)):
+ settingsdata.setValue(keys[i], settingdict[keys[i]])
+ settingsdata.endGroup()
+ settingsdata.sync()
+ except (AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ (la.SETTINGSMESSAGES['savesettings'] + str(e)), severity=hou.severityType.Warning)
+ else:
+ print(la.SETTINGSMESSAGES['savesettings'] + str(e))
+
+
+# ---------------------------------------- loadsettings
+# NOTE loadsettings -----------------------------------
+def loadsettings():
+ results = {}
+ try:
+ settingsdata.beginGroup('Searcher')
+ for i in range(len(util.SETTINGS_KEYS)):
+ if util.SETTINGS_TYPES[util.SETTINGS_KEYS[i]] in {"bool", "flag"}:
+ results.update({util.SETTINGS_KEYS[i]: util.bc(settingsdata.value(util.SETTINGS_KEYS[i]))})
+ else:
+ results.update({util.SETTINGS_KEYS[i]: settingsdata.value(util.SETTINGS_KEYS[i])})
+
+ settingsdata.endGroup()
+ return results
+ except (AttributeError, TypeError) as e:
+ if hou.isUIAvailable():
+ hou.ui.setStatusMessage(
+ (la.SETTINGSMESSAGES['loadsettings'] + str(e)), severity=hou.severityType.Warning)
+ else:
+ print(la.SETTINGSMESSAGES['loadsettings'] + str(e))
+# !SECTION Setting Functions
diff --git a/python3.7libs/searcher/style.py b/python3.7libs/searcher/style.py
new file mode 100644
index 0000000..22d6d76
--- /dev/null
+++ b/python3.7libs/searcher/style.py
@@ -0,0 +1,334 @@
+from __future__ import print_function
+from __future__ import absolute_import
+
+import hou
+import os
+from searcher import util
+
+hver = 0
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.')+1:])
+ from hutil.Qt import QtGui
+else:
+ from qtpy import QtGui
+
+# --------------------------------------------------- Paths
+# NOTE Paths ----------------------------------------------
+script_path = os.path.dirname(os.path.realpath(__file__))
+PATH = os.path.join(script_path, "images")
+imgroot = PATH.replace("\\", "/")
+
+settings = util.get_settings()
+
+
+# ----------------------------------------------- Functions
+# NOTE Functions ------------------------------------------
+def count_chars(txt):
+ result = 0
+ for char in txt:
+ result += 1
+ return result
+
+
+# --------------------------------------------------------------- UI Style
+# SECTION UI Style -------------------------------------------------------
+# ---------------------------------------------- MAINWINDOW
+# NOTE MAINWINDOW -----------------------------------------
+# @formatter:off
+MAINWINDOW = """ background-color: rgb(42, 42, 42); """
+
+# ------------------------------------------- CONTEXTTOGGLE
+# NOTE CONTEXTTOGGLE --------------------------------------
+# @formatter:off
+CONTEXTTOGGLE = """ QPushButton { width: 8px; border: none; }
+ QPushButton:checked { width: 8px; border: none;} """
+
+# ----------------------------------------------- INFOLABEL
+# NOTE INFOLABEL ------------------------------------------
+INFOLABEL = """ background-color: rgba(11,11,11,1); border-bottom: 1px solid rgb(100, 100, 100); """
+
+# ----------------------------------------------- MENUSTYLE
+# NOTE MENUSTYLE ------------------------------------------
+# @formatter:off
+MENUSTYLE = """QMenu { background-color: rgb(64,64,64); menu-scrollable: 1; margin: 0px; }
+ QMenu:item { background-color: rgb(46,46,46); padding: 5px 25px; margin: 1px; height:16px; }
+ QMenu:item:selected { background-color: rgb(64,64,64); }
+ QMenu:separator { background-color: rgb(0,0,0); height: 1px; margin: 5px; }
+ QMenu:icon { padding: 5px; }
+ QMenu:icon:checked { flat: true; }"""
+
+# ------------------------------------------------- TOOLTIP
+# NOTE TOOLTIP --------------------------------------------
+# @formatter:off
+TOOLTIP = """QToolTip { background-color: rgb(64,64,64); menu-scrollable: 1; margin: 0px; }
+ QToolTip:item { background-color: rgb(46,46,46); padding: 5px 25px ; margin: 1px; height:16px; }
+ QToolTip:icon { padding: 5px; }
+ QToolTip:icon:checked { flat: true; }"""
+
+# -------------------------------------------- SETTINGSMENU
+# NOTE SETTINGSMENU ---------------------------------------
+# @formatter:off
+SETTINGSMENU = """ QWidget { background: rgb(58, 58, 58); }
+ QWidget#SearcherSettings { border: 0px solid rgb(35, 35, 35); } """
+
+# --------------------------------------- styleresizehandle
+# NOTE styleresizehandle ----------------------------------
+# @formatter:off
+def styleresizehandle(obj, enter):
+ if enter:
+ resizeimg = (imgroot + "/%s.png" % obj.objectName())
+ sheet = ""
+ sheet += (
+ """QSizeGrip {
+ background-image: url(%s);
+ background-repeat: no-repeat;
+ background-position: center;
+ padding-bottom: 15px;
+ width: 25px;
+ height: 25px;
+ background-color: rgba(0, 0, 0, 0);
+ }"""
+ % resizeimg
+ )
+ obj.setStyleSheet(sheet)
+ else:
+ sheet = ""
+ sheet += (
+ """QSizeGrip {
+ image: url(None);
+ width: 15px;
+ height: 15px;
+ background-color: rgba(0, 0, 0, 0);
+ }"""
+ )
+ obj.setStyleSheet(sheet)
+
+# ---------------------------------------- styleresulttotal
+# NOTE styleresulttotal -----------------------------------
+# @formatter:off
+def styleresulttotal(treecatnum, treeitemsnum):
+ appcolors = settings[util.SETTINGS_KEYS[14]]
+ return (("%s : Contexts | " % (appcolors[util.COLORFIELDS[2]], treecatnum, appcolors[util.COLORFIELDS[0]]))
+ + ("%s : Results " % (appcolors[util.COLORFIELDS[2]], treeitemsnum, appcolors[util.COLORFIELDS[0]])))
+
+# --------------------------------------------- styletimers
+# NOTE styletimers ----------------------------------------
+# @formatter:off
+def styletimers(outdata):
+ appcolors = settings[util.SETTINGS_KEYS[14]]
+ return (("Search Regex %0.4f ms | " % (str(appcolors[util.COLORFIELDS[0]]), str(appcolors[util.COLORFIELDS[2]]), outdata[0]))
+ + ("Context Search %0.4f ms | " % (str(appcolors[util.COLORFIELDS[0]]), str(appcolors[util.COLORFIELDS[2]]), outdata[1]))
+ + ("Hotkey Search %0.4f ms | " % (str(appcolors[util.COLORFIELDS[0]]), str(appcolors[util.COLORFIELDS[2]]), outdata[2]))
+ + ("Tree build %0.4f ms | " % (str(appcolors[util.COLORFIELDS[0]]), str(appcolors[util.COLORFIELDS[2]]), outdata[3]))
+ + ("Total : %0.4f ms " % (str(appcolors[util.COLORFIELDS[0]]), str(appcolors[util.COLORFIELDS[2]]), outdata[4])))
+
+# -------------------------------------------- returntimers
+# NOTE returntimers ---------------------------------------
+# @formatter:off
+def returntimers(outdata):
+ return (("Search Regex %0.4f ms | " % outdata[0])
+ + ("Context Search %0.4f ms | " % outdata[1])
+ + ("Hotkey Search %0.4f ms | " % outdata[2])
+ + ("Tree build %0.4f ms | " % outdata[3])
+ + ("Total : %0.4f ms " % outdata[4]))
+
+# -------------------------------------------- setstatusmsg
+# NOTE setstatusmsg ---------------------------------------
+# @formatter:off
+def setstatusmsg(text, severity):
+ stype, scolor = util.SEVERITY[severity]
+ msg = (("%s" % (scolor, text)))
+ return msg, stype
+
+# ----------------------------------------- gettooltipstyle
+# NOTE gettooltipstyle ------------------------------------
+# @formatter:off
+def gettooltipstyle(text):
+ return (("%s" % (settings[util.SETTINGS_KEYS[14]][util.COLORFIELDS[4]], text)))
+
+# ---------------------------------------- gettreeviewstyle
+# NOTE gettreeviewstyle -----------------------------------
+# @formatter:off
+def gettreeviewstyle():
+ PATH = os.path.join(script_path, "images")
+ root = PATH.replace("\\", "/")
+
+ sheet = ""
+ sheet += ("""QTreeWidget {
+ background: rgb(32, 32, 32);
+ alternate-background-color: rgb(39, 39, 39);
+ border: 0px solid rgb(19, 19, 19);
+ } """
+ )
+ sheet += (
+ """QHeaderView::section {
+ background: rgb(53, 53, 53);
+ color: rgb(200, 200, 200);
+ border: 0px solid rgb(150, 150, 150);
+ border-bottom: 1px solid rgb(150, 150, 150);
+ border-left:1px solid rgb(35, 35, 35);
+ border-right:0px solid rgb(35, 35, 35);
+ height:20px;
+ resize:both;
+ overflow:auto;
+ padding: 4px;
+ }
+ QScrollBar:vertical {
+ background: rgb(19, 19, 19);
+ border: 0px solid rgb(25, 25, 25);
+ width: 10px;
+ margin: 0px 0px 0px 0px;
+ }
+ QScrollBar::handle:vertical {
+ background: rgb(53,53,53)
+ }
+ QScrollBar::add-line:vertical {
+ background: rgb(19, 19, 19);
+ border: 0px solid rgb(25, 25, 25);
+ height: 0px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+ }
+ QScrollBar::sub-line:vertical {
+ background: rgb(19, 19, 19);
+ border: 0px solid rgb(25,25,25);
+ height: 0px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+ }
+ QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {
+ color: rgba(255, 193, 7, 0.8);
+ background: rgb(19, 19, 19);
+ width: 0px;
+ height: 0px;
+ }
+ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
+ background: none;
+ }
+ QScrollBar:horizontal {
+ background: rgb(19, 19, 19);
+ border: 0px solid rgb(25, 25, 25);
+ height: 10px;
+ margin: 0x 0px 0px 0px;
+ }
+ QScrollBar::handle:horizontal {
+ background: rgb(53, 53, 53);
+ }
+ QScrollBar::add-line:horizontal {
+ background: rgb(19, 19, 19);
+ border: 0px solid rgb(25, 25, 25);
+ width: 0px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+ }
+ QScrollBar::sub-line:horizontal {
+ background: rgb(19, 19, 19);
+ border: 0px solid rgb(25, 25, 25);
+ width: 0px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+ }
+ QScrollBar::left-arrow:horizontal, QScrollBar::right-arrow:horizontal {
+ background: rgb(19, 19, 19);
+ width: 0px;
+ height: 0px;
+ }
+ QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
+ background: none;
+ }
+ """
+ )
+ sheet += (
+ """QTreeWidget::item::has-children {
+ text-align: center;
+ color: %s;
+ border: 0px solid rgba(71, 71, 71, 0.8);
+ padding-left: 0px; padding-bottom: 0px;
+ padding-top: 0px;
+ border-radius: 0px;
+ } """
+ % str(settings[util.SETTINGS_KEYS[14]][util.COLORFIELDS[1]])
+ )
+ sheet += (
+ """QTreeWidget::branch:has-siblings:!adjoins-item {
+ border-image: url(%s/icon_vline.png) 0;
+ }"""
+ % root
+ )
+ sheet += (
+ """QTreeWidget::branch:has-siblings:adjoins-item {
+ border-image: url(%s/icon_branch_more.png) 0;
+ }"""
+ % root
+ )
+ sheet += (
+ """QTreeWidget::branch:!has-children:!has-siblings:adjoins-item {
+ border-image: url(%s/icon_branch_end.png) 0;
+ }"""
+ % root
+ )
+ sheet += (
+ """QTreeWidget::branch:has-children:!has-siblings:closed,"""
+ )
+ sheet += (
+ """QTreeWidget::branch:closed:has-children:has-siblings {
+ margin: 4px;
+ border-image: none;
+ image: url(%s/icon_branch_closed.png);
+ }"""
+ % root
+ )
+ sheet += (
+ """QTreeWidget::branch:open:has-children:!has-siblings,"""
+ )
+ sheet += (
+ """QTreeWidget::branch:open:has-children:has-siblings {
+ margin: 4px;
+ border-image: none;
+ image: url(%s/icon_branch_open.png);
+ }"""
+ % root
+ )
+ sheet += (
+ """QTreeWidget::indicator:unchecked {
+ image: url(%s/icon_branch_closed.png);
+ padding-left: 15px;
+ }"""
+ % root
+ )
+ sheet += (
+ """QTreeWidget::indicator:checked {
+ image: url(%s/icon_branch_open.png);
+ padding-left: 15px;
+ }"""
+ % root
+ )
+ sheet += """QTreeWidget::indicator {
+ width: 16px;
+ height: 16px;
+ }"""
+ sheet += (
+ """QGroupBox::indicator:unchecked {
+ image: url(%s/icon_branch_closed.png);
+ padding-left: 15px;
+ }"""
+ % root
+ )
+ sheet += (
+ """QGroupBox::indicator:checked {
+ image: url(%s/icon_branch_open.png);
+ padding-left: 15px;
+ }"""
+ % root
+ )
+ sheet += (
+ """QGroupBox::indicator {
+ width: 16px;
+ height: 16px;
+ }"""
+ )
+
+ return sheet
+
+# !SECTION UI Style
\ No newline at end of file
diff --git a/python3.7libs/searcher/theme.py b/python3.7libs/searcher/theme.py
new file mode 100644
index 0000000..5f5e43a
--- /dev/null
+++ b/python3.7libs/searcher/theme.py
@@ -0,0 +1,248 @@
+from __future__ import print_function
+from __future__ import absolute_import
+
+from searcher import theme_ui
+from searcher import util
+from searcher import settings_data
+from searcher import style
+
+import os
+import sys
+
+import hou
+import hdefereval as hd
+hver = 0
+if os.environ["HFS"] != "":
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.')+1:])
+ from hutil.Qt import QtGui
+ from hutil.Qt import QtCore
+ from hutil.Qt import QtWidgets
+else:
+ from qtpy import QtGui
+ from qtpy import QtCore
+ from qtpy import QtWidgets
+
+scriptpath = os.path.dirname(os.path.realpath(__file__))
+
+def name(**variables):
+ return [x for x in variables]
+
+def getHexColor(color):
+ if isinstance(color, hou.Color):
+ color = color.rgb()
+
+ rgb = [('00' + hex(int(v * 0xff))[2:])[-2:] for v in color[:3]]
+ return "#" + ''.join(rgb)
+
+def getRGBColor(hex):
+ hex = hex.lstrip('#')
+ hlen = len(hex)
+ return tuple(int(hex[i:i+hlen/3], 16) / 255.0 for i in range(0, hlen, hlen/3))
+
+class Theme(QtWidgets.QWidget):
+ """ Searcher coloring"""
+
+ # --------------------------------------------------------------- Init
+ # SECTION Init -------------------------------------------------------
+ def __init__(self, parent=None):
+ super(Theme, self).__init__(parent=parent)
+ self.setParent(parent)
+ self.parentwindow = parent
+ self.ui = theme_ui.Ui_Theme()
+ # !SECTION Init
+
+
+ self.ui.setupUi(self)
+ self.ui.retranslateUi(self)
+ self.colorfield = {}
+ self.settings = util.get_settings()
+ self.colors = self.settings[util.SETTINGS_KEYS[14]]
+ self.coloreditor = None
+
+ self.tabpanel = self.ui.tabWidget
+ self.tabpanel.currentChanged.connect(self.curTabChange)
+
+ self.tab1 = self.ui.tab
+ self.tab1.setLayout(self.ui.r1)
+
+ # --------------------------------------------------- Build Fields
+ # SECTION Build Fields -------------------------------------------
+ for i in range(len(util.COLORFIELDS)):
+ # ---------------------------------- Colorfield
+ # NOTE Colorfield -----------------------------
+ v = getattr(self.ui, util.COLORFIELDS[i])
+ v.setText(self.settings[util.SETTINGS_KEYS[14]][util.COLORFIELDS[i]])
+ v.setVisible(True)
+
+ # --------------------------- Colorfield Button
+ # NOTE Colorfield Button ----------------------
+ v_btn = getattr(self.ui, util.COLORFIELDS[i] + '_btn')
+ v_btn.setStyleSheet("background-color:" + v.text())
+ v_btn.setAutoFillBackground(True)
+ v_btn.clicked.connect(self.chooseColor)
+ v_btn.setObjectName(util.COLORFIELDS[i])
+ v_btn.setVisible(True)
+
+ # ---------------------------- Colorfield Label
+ # NOTE Colorfield Label -----------------------
+ v_lbl = getattr(self.ui, util.COLORFIELDS[i] + '_lbl')
+ v_lbl.setVisible(True)
+
+ # !SECTION Build Fields
+
+ self.save = self.ui.savetheme
+ self.save.pressed.connect(self.save_cb)
+
+ self.discard = self.ui.discardtheme
+ self.discard.pressed.connect(self.discard_cb)
+
+ def initmenu(self):
+ self.curTabChange(0)
+ self.installEventFilter(self)
+
+ # ------------------------------------------------------------- Callbacks
+ # SECTION Callbacks -----------------------------------------------------
+ # ---------------------------------------- curTabChange
+ # NOTE curTabChange -----------------------------------
+ def curTabChange(self, index):
+ for i in range(self.tabpanel.count()):
+ if i == index:
+ self.tabpanel.widget(i).setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ else:
+ self.tabpanel.widget(i).setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Ignored)
+
+ # --------------------------------------------- save_cb
+ # NOTE save_cb ----------------------------------------
+ def save_cb(self):
+ for i in range(len(util.COLORFIELDS)):
+ self.settings[util.SETTINGS_KEYS[14]][util.COLORFIELDS[i]] = getattr(self.ui, util.COLORFIELDS[i]).text()
+
+ settings_data.savesettings(self.settings)
+ self.parentwindow.themebtn.setChecked(False)
+ self.close()
+
+ # ------------------------------------------ discard_cb
+ # NOTE discard_cb -------------------------------------
+ def discard_cb(self):
+ self.parentwindow.themebtn.setChecked(False)
+ self.close()
+
+ #-------------------------------------- colorchange_cb
+ # NOTE colorchange_cb ---------------------------------
+ def colorchange_cb(self, color, alpha=1.0):
+ rgb = color.rgb()
+ newcolor = QtGui.QColor(
+ rgb[0]*255,
+ rgb[1]*255,
+ rgb[2]*255
+ )
+
+ if newcolor.isValid():
+ demotext = ""
+ self.colorfield[self.name][0].setText(newcolor.name())
+ self.colorfield[self.name][1].setStyleSheet("background-color:" + self.colorfield[self.name][0].text())
+
+ if self.colorfield[self.name][0] == getattr(self.ui, util.COLORFIELDS[0]):
+ outdata = [0.100, 0.200, 0.300, 0.400, 0.500]
+ demotxt = (("Search Regex %0.4f ms | " % (str(self.colorfield[self.name][0].text()), str(getattr(self.ui, util.COLORFIELDS[2]).text()), outdata[0]))
+ + ("Context Search %0.4f ms | " % (str(self.colorfield[self.name][0].text()), str(getattr(self.ui, util.COLORFIELDS[2]).text()), outdata[1]))
+ + ("Hotkey Search %0.4f ms | " % (str(self.colorfield[self.name][0].text()), str(getattr(self.ui, util.COLORFIELDS[2]).text()), outdata[2]))
+ + ("Tree build %0.4f ms | " % (str(self.colorfield[self.name][0].text()), str(getattr(self.ui, util.COLORFIELDS[2]).text()), outdata[3]))
+ + ("Total : %0.4f ms " % (str(self.colorfield[self.name][0].text()), str(getattr(self.ui, util.COLORFIELDS[2]).text()), outdata[4])))
+ self.parentwindow.parentwindow.infolbl.setText(demotxt)
+
+ elif self.colorfield[self.name][0] == getattr(self.ui, util.COLORFIELDS[2]):
+ outdata = [0.100, 0.200, 0.300, 0.400, 0.500]
+ demotxt = (("Search Regex %0.4f ms | " % (str(getattr(self.ui, util.COLORFIELDS[0]).text()), str(self.colorfield[self.name][0].text()), outdata[0]))
+ + ("Context Search %0.4f ms | " % (str(getattr(self.ui, util.COLORFIELDS[0]).text()), str(self.colorfield[self.name][0].text()), outdata[1]))
+ + ("Hotkey Search %0.4f ms | " % (str(getattr(self.ui, util.COLORFIELDS[0]).text()), str(self.colorfield[self.name][0].text()), outdata[2]))
+ + ("Tree build %0.4f ms | " % (str(getattr(self.ui, util.COLORFIELDS[0]).text()), str(self.colorfield[self.name][0].text()), outdata[3]))
+ + ("Total : %0.4f ms " % (str(getattr(self.ui, util.COLORFIELDS[0]).text()), str(self.colorfield[self.name][0].text()), outdata[4])))
+ self.parentwindow.parentwindow.infolbl.setText(demotxt)
+
+ elif self.colorfield[self.name][0] == getattr(self.ui, util.COLORFIELDS[4]):
+ text = "This is an example of how the ToolTip text will look with this particular color"
+ demotxt = ("%s" % (self.colorfield[self.name][0].text(), text))
+ self.parentwindow.parentwindow.infolbl.setText(demotxt)
+
+
+ def _opencoloreditor(self, color):
+ allWidgets = QtWidgets.QApplication.allWidgets()
+ for w in allWidgets:
+ if "Select Color" in w.windowTitle():
+ self.coloreditor = w
+ break
+
+ if self.coloreditor:
+ pos = self.parentwindow.mapToGlobal(
+ QtCore.QPoint(self.parentwindow.width(), self.parentwindow.height()))
+ self.coloreditor.setGeometry(
+ pos.x() - ((self.parentwindow.width() * 1.55 ) + 20 ),
+ pos.y() - self.parentwindow.height(),
+ ((self.parentwindow.width() * 0.5) + 44),
+ ((self.parentwindow.height() * 1.2) + 86)
+ )
+ self.parentwindow.parentwindow.activateWindow()
+
+ # ----------------------------------------- chooseColor
+ # NOTE chooseColor ------------------------------------
+ def chooseColor(self):
+ sender = self.sender()
+
+ self.name = sender.objectName()
+ self.colorfield[self.name] = (getattr(self.ui, self.name), sender)
+
+ qcolor = QtGui.QColor()
+ qcolor.setNamedColor(self.colorfield[self.name][0].text())
+
+ colord = QtWidgets.QColorDialog(self)
+ colord.setModal(False)
+ pos = self.parentwindow.mapToGlobal(
+ QtCore.QPoint(self.parentwindow.width(), self.parentwindow.height()))
+ colord.move(
+ pos.x() + 300,
+ pos.y(),
+ )
+ c = colord.getColor(
+ initial=qcolor,
+ parent=self,
+ options=QtWidgets.QColorDialog.DontUseNativeDialog
+ )
+ hcolor = hou.qt.fromQColor(c)
+
+ self.colorchange_cb(hcolor[0])
+
+ # !SECTION Callbacks
+
+ # ------------------------------------------------------------- Events
+ # SECTION Events -----------------------------------------------------
+ def eventFilter(self, obj, event):
+ event_type = event.type()
+
+ # ------------------------------------------- Mouse
+ # SECTION Mouse -----------------------------------
+ # ----------------------- MouseButtonPress
+ # NOTE MouseButtonPress ------------------
+ # --- Empty for now ---
+ # !SECTION Mouse
+
+ # ------------------------------------------ Window
+ # NOTE Window -------------------------------------
+ if event_type == QtCore.QEvent.Show:
+ self.parentwindow.ui.save_btn.setVisible(False)
+ self.parentwindow.ui.discard_btn.setVisible(False)
+ if event_type == QtCore.QEvent.Close:
+ self.parentwindow.ui.save_btn.setVisible(True)
+ self.parentwindow.ui.discard_btn.setVisible(True)
+
+ # ---------------------------------------- Keypress
+ # NOTE Keypress -----------------------------------
+ if event_type == QtCore.QEvent.KeyPress:
+ if event.key() == QtCore.Qt.Key_Escape:
+ self.parentwindow.closeroutine()
+ return True
+
+ return QtCore.QObject.eventFilter(self, obj, event)
+
+ # !SECTION Events
\ No newline at end of file
diff --git a/python3.7libs/searcher/theme_ui.py b/python3.7libs/searcher/theme_ui.py
new file mode 100644
index 0000000..e7782cf
--- /dev/null
+++ b/python3.7libs/searcher/theme_ui.py
@@ -0,0 +1,298 @@
+from hutil.Qt import QtCore, QtGui, QtWidgets
+import os
+
+scriptpath = os.path.dirname(os.path.realpath(__file__))
+
+
+class Ui_Theme(object):
+ def setupUi(self, Theme):
+ Theme.setObjectName("Theme")
+ Theme.setWindowModality(QtCore.Qt.NonModal)
+ Theme.resize(450, 300)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(Theme.sizePolicy().hasHeightForWidth())
+ Theme.setSizePolicy(sizePolicy)
+ Theme.setMinimumSize(QtCore.QSize(100, 0))
+ Theme.setBaseSize(QtCore.QSize(0, 0))
+ Theme.setStyleSheet("")
+ self.gridLayout = QtWidgets.QGridLayout(Theme)
+ self.gridLayout.setContentsMargins(-1, -1, -1, 6)
+ self.gridLayout.setSpacing(6)
+ self.gridLayout.setObjectName("gridLayout")
+ self.r2 = QtWidgets.QVBoxLayout()
+ self.r2.setObjectName("r2")
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.horizontalLayout_2.addItem(spacerItem)
+ self.discardtheme = QtWidgets.QPushButton(Theme)
+ self.discardtheme.setObjectName("discardtheme")
+ self.horizontalLayout_2.addWidget(self.discardtheme)
+ self.savetheme = QtWidgets.QPushButton(Theme)
+ self.savetheme.setObjectName("savetheme")
+ self.horizontalLayout_2.addWidget(self.savetheme)
+ self.r2.addLayout(self.horizontalLayout_2)
+ self.gridLayout.addLayout(self.r2, 2, 0, 1, 1)
+ self.verticalLayout = QtWidgets.QVBoxLayout()
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.tabWidget = QtWidgets.QTabWidget(Theme)
+ self.tabWidget.setObjectName("tabWidget")
+ self.tab = QtWidgets.QWidget()
+ self.tab.setObjectName("tab")
+ self.layoutWidget = QtWidgets.QWidget(self.tab)
+ self.layoutWidget.setGeometry(QtCore.QRect(0, 0, 533, 164))
+ self.layoutWidget.setObjectName("layoutWidget")
+ self.r1 = QtWidgets.QHBoxLayout(self.layoutWidget)
+ self.r1.setContentsMargins(6, 6, 6, 0)
+ self.r1.setObjectName("r1")
+ self.c1 = QtWidgets.QVBoxLayout()
+ self.c1.setObjectName("c1")
+ self.h4_c1 = QtWidgets.QHBoxLayout()
+ self.h4_c1.setObjectName("h4_c1")
+ self.text2_lbl = QtWidgets.QLabel(self.layoutWidget)
+ self.text2_lbl.setObjectName("text2_lbl")
+ self.h4_c1.addWidget(self.text2_lbl)
+ spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h4_c1.addItem(spacerItem1)
+ self.text2_btn = QtWidgets.QToolButton(self.layoutWidget)
+ self.text2_btn.setText("")
+ self.text2_btn.setObjectName("text2_btn")
+ self.h4_c1.addWidget(self.text2_btn)
+ self.text2 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.text2.sizePolicy().hasHeightForWidth())
+ self.text2.setSizePolicy(sizePolicy)
+ self.text2.setMinimumSize(QtCore.QSize(75, 0))
+ self.text2.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.text2.setBaseSize(QtCore.QSize(75, 0))
+ self.text2.setReadOnly(True)
+ self.text2.setObjectName("text2")
+ self.h4_c1.addWidget(self.text2)
+ spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+ self.h4_c1.addItem(spacerItem2)
+ self.c1.addLayout(self.h4_c1)
+ self.h1_c2 = QtWidgets.QHBoxLayout()
+ self.h1_c2.setObjectName("h1_c2")
+ self.tooltip_lbl = QtWidgets.QLabel(self.layoutWidget)
+ self.tooltip_lbl.setObjectName("tooltip_lbl")
+ self.h1_c2.addWidget(self.tooltip_lbl)
+ self.tooltip_btn = QtWidgets.QToolButton(self.layoutWidget)
+ self.tooltip_btn.setText("")
+ self.tooltip_btn.setObjectName("tooltip_btn")
+ self.h1_c2.addWidget(self.tooltip_btn)
+ self.tooltip = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.tooltip.sizePolicy().hasHeightForWidth())
+ self.tooltip.setSizePolicy(sizePolicy)
+ self.tooltip.setMinimumSize(QtCore.QSize(75, 0))
+ self.tooltip.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.tooltip.setReadOnly(True)
+ self.tooltip.setObjectName("tooltip")
+ self.h1_c2.addWidget(self.tooltip)
+ spacerItem3 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+ self.h1_c2.addItem(spacerItem3)
+ self.c1.addLayout(self.h1_c2)
+ self.h3_c1 = QtWidgets.QHBoxLayout()
+ self.h3_c1.setObjectName("h3_c1")
+ self.text1_lbl = QtWidgets.QLabel(self.layoutWidget)
+ self.text1_lbl.setObjectName("text1_lbl")
+ self.h3_c1.addWidget(self.text1_lbl)
+ spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h3_c1.addItem(spacerItem4)
+ self.text1_btn = QtWidgets.QToolButton(self.layoutWidget)
+ self.text1_btn.setText("")
+ self.text1_btn.setObjectName("text1_btn")
+ self.h3_c1.addWidget(self.text1_btn)
+ self.text1 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.text1.sizePolicy().hasHeightForWidth())
+ self.text1.setSizePolicy(sizePolicy)
+ self.text1.setMinimumSize(QtCore.QSize(75, 0))
+ self.text1.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.text1.setBaseSize(QtCore.QSize(75, 0))
+ self.text1.setReadOnly(True)
+ self.text1.setObjectName("text1")
+ self.h3_c1.addWidget(self.text1)
+ spacerItem5 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+ self.h3_c1.addItem(spacerItem5)
+ self.c1.addLayout(self.h3_c1)
+ self.h2_c1 = QtWidgets.QHBoxLayout()
+ self.h2_c1.setObjectName("h2_c1")
+ self.stats1_lbl = QtWidgets.QLabel(self.layoutWidget)
+ self.stats1_lbl.setObjectName("stats1_lbl")
+ self.h2_c1.addWidget(self.stats1_lbl)
+ spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h2_c1.addItem(spacerItem6)
+ self.stats1_btn = QtWidgets.QToolButton(self.layoutWidget)
+ self.stats1_btn.setText("")
+ self.stats1_btn.setObjectName("stats1_btn")
+ self.h2_c1.addWidget(self.stats1_btn)
+ self.stats1 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.stats1.sizePolicy().hasHeightForWidth())
+ self.stats1.setSizePolicy(sizePolicy)
+ self.stats1.setMinimumSize(QtCore.QSize(75, 0))
+ self.stats1.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.stats1.setBaseSize(QtCore.QSize(75, 0))
+ self.stats1.setReadOnly(True)
+ self.stats1.setObjectName("stats1")
+ self.h2_c1.addWidget(self.stats1)
+ spacerItem7 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+ self.h2_c1.addItem(spacerItem7)
+ self.c1.addLayout(self.h2_c1)
+ spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.c1.addItem(spacerItem8)
+ self.r1.addLayout(self.c1)
+ self.c2 = QtWidgets.QVBoxLayout()
+ self.c2.setObjectName("c2")
+ self.h1_c1 = QtWidgets.QHBoxLayout()
+ self.h1_c1.setObjectName("h1_c1")
+ self.stats2_lbl = QtWidgets.QLabel(self.layoutWidget)
+ self.stats2_lbl.setObjectName("stats2_lbl")
+ self.h1_c1.addWidget(self.stats2_lbl)
+ spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h1_c1.addItem(spacerItem9)
+ spacerItem10 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+ self.h1_c1.addItem(spacerItem10)
+ self.stats2_btn = QtWidgets.QToolButton(self.layoutWidget)
+ self.stats2_btn.setText("")
+ self.stats2_btn.setObjectName("stats2_btn")
+ self.h1_c1.addWidget(self.stats2_btn)
+ self.stats2 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.stats2.sizePolicy().hasHeightForWidth())
+ self.stats2.setSizePolicy(sizePolicy)
+ self.stats2.setMinimumSize(QtCore.QSize(75, 0))
+ self.stats2.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.stats2.setBaseSize(QtCore.QSize(75, 0))
+ self.stats2.setReadOnly(True)
+ self.stats2.setObjectName("stats2")
+ self.h1_c1.addWidget(self.stats2)
+ self.c2.addLayout(self.h1_c1)
+ self.h2_c2 = QtWidgets.QHBoxLayout()
+ self.h2_c2.setObjectName("h2_c2")
+ self.label_7 = QtWidgets.QLabel(self.layoutWidget)
+ self.label_7.setEnabled(True)
+ self.label_7.setObjectName("label_7")
+ self.h2_c2.addWidget(self.label_7)
+ spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h2_c2.addItem(spacerItem11)
+ self.toolButton_6 = QtWidgets.QToolButton(self.layoutWidget)
+ self.toolButton_6.setText("")
+ self.toolButton_6.setObjectName("toolButton_6")
+ self.h2_c2.addWidget(self.toolButton_6)
+ self.lineEdit_3 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.lineEdit_3.sizePolicy().hasHeightForWidth())
+ self.lineEdit_3.setSizePolicy(sizePolicy)
+ self.lineEdit_3.setMinimumSize(QtCore.QSize(75, 0))
+ self.lineEdit_3.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.lineEdit_3.setReadOnly(True)
+ self.lineEdit_3.setObjectName("lineEdit_3")
+ self.h2_c2.addWidget(self.lineEdit_3)
+ self.c2.addLayout(self.h2_c2)
+ self.h3_c2 = QtWidgets.QHBoxLayout()
+ self.h3_c2.setObjectName("h3_c2")
+ self.label_6 = QtWidgets.QLabel(self.layoutWidget)
+ self.label_6.setObjectName("label_6")
+ self.h3_c2.addWidget(self.label_6)
+ spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h3_c2.addItem(spacerItem12)
+ self.toolButton_7 = QtWidgets.QToolButton(self.layoutWidget)
+ self.toolButton_7.setText("")
+ self.toolButton_7.setObjectName("toolButton_7")
+ self.h3_c2.addWidget(self.toolButton_7)
+ self.lineEdit_4 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.lineEdit_4.sizePolicy().hasHeightForWidth())
+ self.lineEdit_4.setSizePolicy(sizePolicy)
+ self.lineEdit_4.setMinimumSize(QtCore.QSize(75, 0))
+ self.lineEdit_4.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.lineEdit_4.setReadOnly(True)
+ self.lineEdit_4.setObjectName("lineEdit_4")
+ self.h3_c2.addWidget(self.lineEdit_4)
+ self.c2.addLayout(self.h3_c2)
+ self.h4_c2 = QtWidgets.QHBoxLayout()
+ self.h4_c2.setObjectName("h4_c2")
+ self.label_5 = QtWidgets.QLabel(self.layoutWidget)
+ self.label_5.setObjectName("label_5")
+ self.h4_c2.addWidget(self.label_5)
+ spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h4_c2.addItem(spacerItem13)
+ self.toolButton_8 = QtWidgets.QToolButton(self.layoutWidget)
+ self.toolButton_8.setText("")
+ self.toolButton_8.setObjectName("toolButton_8")
+ self.h4_c2.addWidget(self.toolButton_8)
+ self.lineEdit = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.lineEdit.sizePolicy().hasHeightForWidth())
+ self.lineEdit.setSizePolicy(sizePolicy)
+ self.lineEdit.setMinimumSize(QtCore.QSize(75, 0))
+ self.lineEdit.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.lineEdit.setReadOnly(True)
+ self.lineEdit.setObjectName("lineEdit")
+ self.h4_c2.addWidget(self.lineEdit)
+ self.c2.addLayout(self.h4_c2)
+ spacerItem14 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.c2.addItem(spacerItem14)
+ self.r1.addLayout(self.c2)
+ self.tabWidget.addTab(self.tab, "")
+ self.tab_2 = QtWidgets.QWidget()
+ self.tab_2.setObjectName("tab_2")
+ self.tabWidget.addTab(self.tab_2, "")
+ self.verticalLayout.addWidget(self.tabWidget)
+ self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
+
+ self.retranslateUi(Theme)
+ self.setVisibility()
+ QtCore.QMetaObject.connectSlotsByName(Theme)
+
+ def retranslateUi(self, Theme):
+ _translate = QtCore.QCoreApplication.translate
+ Theme.setWindowTitle(_translate("Theme", "Form"))
+ self.discardtheme.setText(_translate("Theme", "Discard"))
+ self.savetheme.setText(_translate("Theme", "Save"))
+ self.text2_lbl.setText(_translate("Theme", "Search Results Context"))
+ self.tooltip_lbl.setText(_translate("Theme", "Tool Tip Info"))
+ self.text1_lbl.setText(_translate("Theme", "Result Stats Text"))
+ self.stats1_lbl.setText(_translate("Theme", "Result Stat Values"))
+ self.stats2_lbl.setText(_translate("Theme", "Secondary Stat Values"))
+ self.label_7.setText(_translate("Theme", "TextLabel"))
+ self.label_6.setText(_translate("Theme", "TextLabel"))
+ self.label_5.setText(_translate("Theme", "TextLabel"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Theme", "Text"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Theme", "Window"))
+
+ def setVisibility(self):
+ self.label_7.setVisible(False)
+ self.label_6.setVisible(False)
+ self.label_5.setVisible(False)
+ self.stats2_lbl.setVisible(False)
+
+ self.lineEdit_4.setVisible(False)
+ self.lineEdit_3.setVisible(False)
+ self.lineEdit.setVisible(False)
+ self.stats2.setVisible(False)
+
+ self.toolButton_6.setVisible(False)
+ self.toolButton_7.setVisible(False)
+ self.toolButton_8.setVisible(False)
+ self.stats2_btn.setVisible(False)
\ No newline at end of file
diff --git a/python3.7libs/searcher/tools/imagetint.py b/python3.7libs/searcher/tools/imagetint.py
new file mode 100644
index 0000000..209ef7a
--- /dev/null
+++ b/python3.7libs/searcher/tools/imagetint.py
@@ -0,0 +1,70 @@
+from PIL import Image
+from PIL.ImageColor import getcolor, getrgb
+from PIL.ImageOps import grayscale
+import os
+import PIL.Image
+import PIL.ImageOps
+
+script_path = os.path.dirname(os.path.realpath(__file__))
+
+
+def image_tint(src, tint='#ffffff'):
+ if Image.isStringType(src): # file path?
+ src = Image.open(src)
+ if src.mode not in ['RGB', 'RGBA']:
+ raise TypeError('Unsupported source image mode: {}'.format(src.mode))
+ src.load()
+
+ tr, tg, tb = getrgb(tint)
+ tl = getcolor(tint, "L") # tint color's overall luminosity
+ if not tl: tl = 1 # avoid division by zero
+ tl = float(tl) # compute luminosity preserving tint factors
+ sr, sg, sb = map(lambda tv: tv/tl, (tr, tg, tb)) # per component adjustments
+
+ # create look-up tables to map luminosity to adjusted tint
+ # (using floating-point math only to compute table)
+ luts = (map(lambda lr: int(lr*sr + 0.5), range(256)) +
+ map(lambda lg: int(lg*sg + 0.5), range(256)) +
+ map(lambda lb: int(lb*sb + 0.5), range(256)))
+ l = grayscale(src) # 8-bit luminosity version of whole image
+ if Image.getmodebands(src.mode) < 4:
+ merge_args = (src.mode, (l, l, l)) # for RGB verion of grayscale
+ else: # include copy of src image's alpha layer
+ a = Image.new("L", src.size)
+ a.putdata(src.getdata(3))
+ merge_args = (src.mode, (l, l, l, a)) # for RGBA verion of grayscale
+ luts += range(256) # for 1:1 mapping of copied alpha values
+
+ return Image.merge(*merge_args).point(luts)
+
+def tint_image(src, color="#FFFFFF"):
+ if Image.isStringType(src): # file path?
+ src = Image.open(src)
+ if src.mode not in ['RGB', 'RGBA']:
+ raise TypeError('Unsupported source image mode: {}'.format(src.mode))
+ src.load()
+ r, g, b, alpha = src.split()
+ gray = ImageOps.grayscale(src)
+ result = ImageOps.colorize(gray, (0, 0, 0, 0), color)
+ result.putalpha(alpha)
+ return result
+
+if __name__ == '__main__':
+
+ PATH = os.path.abspath(os.path.join(script_path, "..", "images"))
+ p = PATH.replace("\\", "/")
+ input_image_path = ['branch-vline.png', 'branch-more.png', 'branch-end.png', 'opened.png', 'collapsed.svg']
+ for i in range(len(input_image_path)):
+ input_image = os.path.join(p, input_image_path[i])
+ print 'tinting "{}"'.format(input_image)
+
+ root, ext = os.path.splitext(input_image)
+ result_image_path = root+'_result'+ext
+
+ print 'creating "{}"'.format(result_image_path)
+ result = image_tint(input_image, '#686868')
+ if os.path.exists(result_image_path): # delete any previous result file
+ os.remove(result_image_path)
+ result.save(result_image_path) # file name's extension determines format
+
+ print 'done'
\ No newline at end of file
diff --git a/python3.7libs/searcher/ui_files/SearcherSettings.py b/python3.7libs/searcher/ui_files/SearcherSettings.py
new file mode 100644
index 0000000..66e102c
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/SearcherSettings.py
@@ -0,0 +1,181 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'SearcherSettings.ui'
+#
+# Created by: qtpy UI code generator 5.14.1
+#
+# WARNING! All changes made in this file will be lost!
+
+
+from qtpy import QtCore, QtGui, QtWidgets
+
+
+class Ui_SearcherSettings(object):
+ def setupUi(self, SearcherSettings):
+ SearcherSettings.setObjectName("SearcherSettings")
+ SearcherSettings.setWindowModality(QtCore.Qt.NonModal)
+ SearcherSettings.resize(450, 211)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(SearcherSettings.sizePolicy().hasHeightForWidth())
+ SearcherSettings.setSizePolicy(sizePolicy)
+ SearcherSettings.setMinimumSize(QtCore.QSize(450, 0))
+ SearcherSettings.setBaseSize(QtCore.QSize(0, 0))
+ SearcherSettings.setStyleSheet("")
+ self.gridLayout = QtWidgets.QGridLayout(SearcherSettings)
+ self.gridLayout.setContentsMargins(-1, -1, -1, 6)
+ self.gridLayout.setSpacing(6)
+ self.gridLayout.setObjectName("gridLayout")
+ self.verticalLayout_4 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_4.setObjectName("verticalLayout_4")
+ self.headerrow = QtWidgets.QHBoxLayout()
+ self.headerrow.setObjectName("headerrow")
+ self.projectTitle = QtWidgets.QLabel(SearcherSettings)
+ font = QtGui.QFont()
+ font.setPointSize(15)
+ self.projectTitle.setFont(font)
+ self.projectTitle.setAlignment(QtCore.Qt.AlignCenter)
+ self.projectTitle.setObjectName("projectTitle")
+ self.headerrow.addWidget(self.projectTitle)
+ self.line_2 = QtWidgets.QFrame(SearcherSettings)
+ self.line_2.setFrameShape(QtWidgets.QFrame.VLine)
+ self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.line_2.setObjectName("line_2")
+ self.headerrow.addWidget(self.line_2)
+ spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.headerrow.addItem(spacerItem)
+ self.checkBox = QtWidgets.QCheckBox(SearcherSettings)
+ self.checkBox.setLayoutDirection(QtCore.Qt.RightToLeft)
+ self.checkBox.setObjectName("checkBox")
+ self.headerrow.addWidget(self.checkBox)
+ self.windowsize_chk = QtWidgets.QCheckBox(SearcherSettings)
+ self.windowsize_chk.setLayoutDirection(QtCore.Qt.RightToLeft)
+ self.windowsize_chk.setObjectName("windowsize_chk")
+ self.headerrow.addWidget(self.windowsize_chk)
+ self.verticalLayout_4.addLayout(self.headerrow)
+ self.line = QtWidgets.QFrame(SearcherSettings)
+ self.line.setFrameShape(QtWidgets.QFrame.HLine)
+ self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.line.setObjectName("line")
+ self.verticalLayout_4.addWidget(self.line)
+ self.secondrow = QtWidgets.QHBoxLayout()
+ self.secondrow.setObjectName("secondrow")
+ self.lang_cbox = QtWidgets.QComboBox(SearcherSettings)
+ self.lang_cbox.setObjectName("lang_cbox")
+ self.lang_cbox.addItem("")
+ self.secondrow.addWidget(self.lang_cbox)
+ spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.secondrow.addItem(spacerItem1)
+ self.label_3 = QtWidgets.QLabel(SearcherSettings)
+ self.label_3.setObjectName("label_3")
+ self.secondrow.addWidget(self.label_3)
+ self.maxresults_txt = QtWidgets.QSpinBox(SearcherSettings)
+ self.maxresults_txt.setMinimum(1)
+ self.maxresults_txt.setMaximum(9999)
+ self.maxresults_txt.setObjectName("maxresults_txt")
+ self.secondrow.addWidget(self.maxresults_txt)
+ self.inmemory_chk = QtWidgets.QCheckBox(SearcherSettings)
+ self.inmemory_chk.setLayoutDirection(QtCore.Qt.RightToLeft)
+ self.inmemory_chk.setTristate(False)
+ self.inmemory_chk.setObjectName("inmemory_chk")
+ self.secondrow.addWidget(self.inmemory_chk)
+ self.verticalLayout_4.addLayout(self.secondrow)
+ self.thirdrow = QtWidgets.QHBoxLayout()
+ self.thirdrow.setObjectName("thirdrow")
+ self.label_2 = QtWidgets.QLabel(SearcherSettings)
+ self.label_2.setObjectName("label_2")
+ self.thirdrow.addWidget(self.label_2)
+ self.defaulthotkey_txt = QtWidgets.QLineEdit(SearcherSettings)
+ self.defaulthotkey_txt.setToolTip("")
+ self.defaulthotkey_txt.setReadOnly(True)
+ self.defaulthotkey_txt.setObjectName("defaulthotkey_txt")
+ self.thirdrow.addWidget(self.defaulthotkey_txt)
+ self.hotkey_icon = QtWidgets.QToolButton(SearcherSettings)
+ self.hotkey_icon.setPopupMode(QtWidgets.QToolButton.InstantPopup)
+ self.hotkey_icon.setObjectName("hotkey_icon")
+ self.thirdrow.addWidget(self.hotkey_icon)
+ self.verticalLayout_4.addLayout(self.thirdrow)
+ self.fourthrow = QtWidgets.QHBoxLayout()
+ self.fourthrow.setObjectName("fourthrow")
+ self.label = QtWidgets.QLabel(SearcherSettings)
+ self.label.setObjectName("label")
+ self.fourthrow.addWidget(self.label)
+ self.databasepath_txt = QtWidgets.QLineEdit(SearcherSettings)
+ self.databasepath_txt.setObjectName("databasepath_txt")
+ self.fourthrow.addWidget(self.databasepath_txt)
+ self.dbpath_icon = QtWidgets.QToolButton(SearcherSettings)
+ self.dbpath_icon.setObjectName("dbpath_icon")
+ self.fourthrow.addWidget(self.dbpath_icon)
+ self.verticalLayout_4.addLayout(self.fourthrow)
+ self.fifthrow = QtWidgets.QHBoxLayout()
+ self.fifthrow.setObjectName("fifthrow")
+ self.label_4 = QtWidgets.QLabel(SearcherSettings)
+ self.label_4.setObjectName("label_4")
+ self.fifthrow.addWidget(self.label_4)
+ self.test1_btn = QtWidgets.QPushButton(SearcherSettings)
+ self.test1_btn.setObjectName("test1_btn")
+ self.fifthrow.addWidget(self.test1_btn)
+ self.cleardata_btn = QtWidgets.QPushButton(SearcherSettings)
+ self.cleardata_btn.setObjectName("cleardata_btn")
+ self.fifthrow.addWidget(self.cleardata_btn)
+ self.verticalLayout_4.addLayout(self.fifthrow)
+ self.line_3 = QtWidgets.QFrame(SearcherSettings)
+ self.line_3.setFrameShape(QtWidgets.QFrame.HLine)
+ self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.line_3.setObjectName("line_3")
+ self.verticalLayout_4.addWidget(self.line_3)
+ self.sixthrow = QtWidgets.QHBoxLayout()
+ self.sixthrow.setObjectName("sixthrow")
+ self.about_btn = QtWidgets.QToolButton(SearcherSettings)
+ self.about_btn.setObjectName("about_btn")
+ self.sixthrow.addWidget(self.about_btn)
+ spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.sixthrow.addItem(spacerItem2)
+ self.debuglevel_cbx = QtWidgets.QComboBox(SearcherSettings)
+ self.debuglevel_cbx.setObjectName("debuglevel_cbx")
+ self.debuglevel_cbx.addItem("")
+ self.debuglevel_cbx.addItem("")
+ self.debuglevel_cbx.addItem("")
+ self.sixthrow.addWidget(self.debuglevel_cbx)
+ self.debugflag_chk = QtWidgets.QCheckBox(SearcherSettings)
+ self.debugflag_chk.setLayoutDirection(QtCore.Qt.LeftToRight)
+ self.debugflag_chk.setObjectName("debugflag_chk")
+ self.sixthrow.addWidget(self.debugflag_chk)
+ self.discard_btn = QtWidgets.QPushButton(SearcherSettings)
+ self.discard_btn.setObjectName("discard_btn")
+ self.sixthrow.addWidget(self.discard_btn)
+ self.save_btn = QtWidgets.QPushButton(SearcherSettings)
+ self.save_btn.setObjectName("save_btn")
+ self.sixthrow.addWidget(self.save_btn)
+ self.verticalLayout_4.addLayout(self.sixthrow)
+ self.gridLayout.addLayout(self.verticalLayout_4, 0, 0, 1, 1)
+
+ self.retranslateUi(SearcherSettings)
+ QtCore.QMetaObject.connectSlotsByName(SearcherSettings)
+
+ def retranslateUi(self, SearcherSettings):
+ _translate = QtCore.QCoreApplication.translate
+ SearcherSettings.setWindowTitle(_translate("SearcherSettings", "Form"))
+ self.projectTitle.setText(_translate("SearcherSettings", "Settings"))
+ self.checkBox.setText(_translate("SearcherSettings", "Use Animated Menus:"))
+ self.windowsize_chk.setText(_translate("SearcherSettings", "Remember Search Window Size"))
+ self.lang_cbox.setCurrentText(_translate("SearcherSettings", "English"))
+ self.lang_cbox.setItemText(0, _translate("SearcherSettings", "English"))
+ self.label_3.setText(_translate("SearcherSettings", "Maximum Search Results"))
+ self.inmemory_chk.setText(_translate("SearcherSettings", "Use In-Memory Database"))
+ self.label_2.setText(_translate("SearcherSettings", "Hotkey to use for opening unassigned items: "))
+ self.defaulthotkey_txt.setPlaceholderText(_translate("SearcherSettings", "Double Click"))
+ self.hotkey_icon.setText(_translate("SearcherSettings", "..."))
+ self.label.setText(_translate("SearcherSettings", "Database location: "))
+ self.dbpath_icon.setText(_translate("SearcherSettings", "..."))
+ self.label_4.setText(_translate("SearcherSettings", "Maintenance utilities:"))
+ self.test1_btn.setText(_translate("SearcherSettings", "Test Button 1"))
+ self.cleardata_btn.setText(_translate("SearcherSettings", "Clear Data"))
+ self.about_btn.setText(_translate("SearcherSettings", "..."))
+ self.debuglevel_cbx.setItemText(0, _translate("SearcherSettings", "NONE"))
+ self.debuglevel_cbx.setItemText(1, _translate("SearcherSettings", "TIMER"))
+ self.debuglevel_cbx.setItemText(2, _translate("SearcherSettings", "ALL"))
+ self.debugflag_chk.setText(_translate("SearcherSettings", "Debug Mode"))
+ self.discard_btn.setText(_translate("SearcherSettings", "Discard"))
+ self.save_btn.setText(_translate("SearcherSettings", "Save"))
diff --git a/python3.7libs/searcher/ui_files/SearcherSettings.ui b/python3.7libs/searcher/ui_files/SearcherSettings.ui
new file mode 100644
index 0000000..6840c36
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/SearcherSettings.ui
@@ -0,0 +1,334 @@
+
+
+ SearcherSettings
+
+
+ Qt::NonModal
+
+
+
+ 0
+ 0
+ 450
+ 211
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 450
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+
+
+
+
+ 6
+
+
+ 6
+
+
+
+
+
+
+
+
+
+ 15
+
+
+
+ Settings
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ Qt::RightToLeft
+
+
+ Use Animated Menus:
+
+
+
+
+
+
+ Qt::RightToLeft
+
+
+ Remember Search Window Size
+
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+
+ English
+
+
+
+ English
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ Maximum Search Results
+
+
+
+
+
+
+ 1
+
+
+ 9999
+
+
+
+
+
+
+ Qt::RightToLeft
+
+
+ Use In-Memory Database
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+ Hotkey to use for opening unassigned items:
+
+
+
+
+
+
+
+
+
+ true
+
+
+ Double Click
+
+
+
+
+
+
+ ...
+
+
+ QToolButton::InstantPopup
+
+
+
+
+
+
+
+
+
+
+ Database location:
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+
+
+
+
+
+
+ Maintenance utilities:
+
+
+
+
+
+
+ Test Button 1
+
+
+
+
+
+
+ Clear Data
+
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+ NONE
+
+
+
+
+ TIMER
+
+
+
+
+ ALL
+
+
+
+
+
+
+
+ Qt::LeftToRight
+
+
+ Debug Mode
+
+
+
+
+
+
+ Discard
+
+
+
+
+
+
+ Save
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/python3.7libs/searcher/ui_files/about.py b/python3.7libs/searcher/ui_files/about.py
new file mode 100644
index 0000000..d334bba
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/about.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'about.ui'
+#
+# Created by: qtpy UI code generator 5.14.1
+#
+# WARNING! All changes made in this file will be lost!
+
+
+from qtpy import QtCore, QtGui, QtWidgets
+
+
+class Ui_About(object):
+ def setupUi(self, About):
+ About.setObjectName("About")
+ About.setWindowModality(QtCore.Qt.NonModal)
+ About.resize(384, 135)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(About.sizePolicy().hasHeightForWidth())
+ About.setSizePolicy(sizePolicy)
+ About.setMinimumSize(QtCore.QSize(100, 0))
+ About.setBaseSize(QtCore.QSize(0, 0))
+ About.setStyleSheet("")
+ self.gridLayout = QtWidgets.QGridLayout(About)
+ self.gridLayout.setContentsMargins(-1, -1, -1, 6)
+ self.gridLayout.setSpacing(6)
+ self.gridLayout.setObjectName("gridLayout")
+ self.verticalLayout_4 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_4.setObjectName("verticalLayout_4")
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.verticalLayout = QtWidgets.QVBoxLayout()
+ self.verticalLayout.setObjectName("verticalLayout")
+ spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.verticalLayout.addItem(spacerItem)
+ self.secondrow = QtWidgets.QHBoxLayout()
+ self.secondrow.setObjectName("secondrow")
+ self.web = QtWidgets.QLabel(About)
+ self.web.setObjectName("web")
+ self.secondrow.addWidget(self.web)
+ self.verticalLayout.addLayout(self.secondrow)
+ self.headerrow = QtWidgets.QHBoxLayout()
+ self.headerrow.setObjectName("headerrow")
+ self.github = QtWidgets.QLabel(About)
+ self.github.setObjectName("github")
+ self.headerrow.addWidget(self.github)
+ self.verticalLayout.addLayout(self.headerrow)
+ self.horizontalLayout.addLayout(self.verticalLayout)
+ self.verticalLayout_4.addLayout(self.horizontalLayout)
+ self.gridLayout.addLayout(self.verticalLayout_4, 0, 0, 1, 1)
+ self.logo = QtWidgets.QLabel(About)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.logo.sizePolicy().hasHeightForWidth())
+ self.logo.setSizePolicy(sizePolicy)
+ self.logo.setMaximumSize(QtCore.QSize(120, 120))
+ self.logo.setText("")
+ self.logo.setPixmap(QtGui.QPixmap("C:/Users/mosthated/Downloads/483688212.png"))
+ self.logo.setScaledContents(True)
+ self.logo.setObjectName("logo")
+ self.gridLayout.addWidget(self.logo, 0, 1, 1, 1)
+
+ self.retranslateUi(About)
+ QtCore.QMetaObject.connectSlotsByName(About)
+
+ def retranslateUi(self, About):
+ _translate = QtCore.QCoreApplication.translate
+ About.setWindowTitle(_translate("About", "Form"))
+ self.web.setText(_translate("About", "instance.id"))
+ self.github.setText(_translate("About", "github.com/instance-id"))
diff --git a/python3.7libs/searcher/ui_files/about.ui b/python3.7libs/searcher/ui_files/about.ui
new file mode 100644
index 0000000..45c7273
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/about.ui
@@ -0,0 +1,123 @@
+
+
+ About
+
+
+ Qt::NonModal
+
+
+
+ 0
+ 0
+ 384
+ 135
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+
+
+
+
+ 6
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+ instance.id
+
+
+
+
+
+
+
+
+
+
+ github.com/instance-id
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 120
+ 120
+
+
+
+
+
+
+ C:/Users/mosthated/Downloads/483688212.png
+
+
+ true
+
+
+
+
+
+
+
+
diff --git a/python3.7libs/searcher/ui_files/bugreport.bak.ui b/python3.7libs/searcher/ui_files/bugreport.bak.ui
new file mode 100644
index 0000000..81b2dae
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/bugreport.bak.ui
@@ -0,0 +1,165 @@
+
+
+ BugReport
+
+
+ Qt::NonModal
+
+
+
+ 0
+ 0
+ 393
+ 172
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+
+
+
+
+ 6
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 175
+ 0
+
+
+
+ Name:
+
+
+
+
+
+
+
+
+
+
+
+ 175
+ 0
+
+
+
+ Contact:
+
+
+
+
+
+
+
+
+
+
+ What was the issue?
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 0
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 120
+ 120
+
+
+
+
+
+
+ C:/Users/mosthated/Downloads/483688212.png
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ Submit Bug
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/python3.7libs/searcher/ui_files/bugreport.py b/python3.7libs/searcher/ui_files/bugreport.py
new file mode 100644
index 0000000..5236825
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/bugreport.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'bugreport.ui'
+#
+# Created by: qtpy UI code generator 5.14.1
+#
+# WARNING! All changes made in this file will be lost!
+
+
+from qtpy import QtCore, QtGui, QtWidgets
+
+
+class Ui_BugReport(object):
+ def setupUi(self, BugReport):
+ BugReport.setObjectName("BugReport")
+ BugReport.setWindowModality(QtCore.Qt.NonModal)
+ BugReport.resize(393, 172)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(BugReport.sizePolicy().hasHeightForWidth())
+ BugReport.setSizePolicy(sizePolicy)
+ BugReport.setMinimumSize(QtCore.QSize(100, 0))
+ BugReport.setBaseSize(QtCore.QSize(0, 0))
+ BugReport.setStyleSheet("")
+ self.gridLayout = QtWidgets.QGridLayout(BugReport)
+ self.gridLayout.setContentsMargins(-1, -1, -1, 6)
+ self.gridLayout.setSpacing(6)
+ self.gridLayout.setObjectName("gridLayout")
+ self.verticalLayout_4 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_4.setObjectName("verticalLayout_4")
+ self.secondrow = QtWidgets.QHBoxLayout()
+ self.secondrow.setObjectName("secondrow")
+ self.title = QtWidgets.QLineEdit(BugReport)
+ self.title.setMinimumSize(QtCore.QSize(175, 0))
+ self.title.setObjectName("title")
+ self.secondrow.addWidget(self.title)
+ self.edittitle_btn = QtWidgets.QPushButton(BugReport)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.edittitle_btn.sizePolicy().hasHeightForWidth())
+ self.edittitle_btn.setSizePolicy(sizePolicy)
+ self.edittitle_btn.setMaximumSize(QtCore.QSize(55, 16777215))
+ self.edittitle_btn.setObjectName("edittitle")
+ self.secondrow.addWidget(self.edittitle_btn)
+ self.verticalLayout_4.addLayout(self.secondrow)
+ self.webview = QtWidgets.QLabel(BugReport)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.webview.sizePolicy().hasHeightForWidth())
+ self.webview.setSizePolicy(sizePolicy)
+ self.webview.setObjectName("webview")
+ self.verticalLayout_4.addWidget(self.webview)
+ self.gridLayout.addLayout(self.verticalLayout_4, 0, 0, 1, 1)
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ spacerItem = QtWidgets.QSpacerItem(40, 10, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.horizontalLayout.addItem(spacerItem)
+ self.continue_btn = QtWidgets.QPushButton(BugReport)
+ self.continue_btn.setObjectName("continue_btn")
+ self.horizontalLayout.addWidget(self.continue_btn)
+ self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1)
+
+ self.retranslateUi(BugReport)
+ QtCore.QMetaObject.connectSlotsByName(BugReport)
+
+ def retranslateUi(self, BugReport):
+ _translate = QtCore.QCoreApplication.translate
+ BugReport.setWindowTitle(_translate("BugReport", "Form"))
+ self.title.setPlaceholderText(_translate("BugReport", "Please enter descriptive bug report title"))
+ self.edittitle_btn.setText(_translate("BugReport", "Edit"))
+ self.webview.setText(_translate("BugReport", "TextLabel"))
+ self.continue_btn.setText(_translate("BugReport", "Continue"))
diff --git a/python3.7libs/searcher/ui_files/bugreport.ui b/python3.7libs/searcher/ui_files/bugreport.ui
new file mode 100644
index 0000000..b0a9cfa
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/bugreport.ui
@@ -0,0 +1,154 @@
+
+
+ BugReport
+
+
+ Qt::NonModal
+
+
+
+ 0
+ 0
+ 393
+ 172
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+
+
+
+
+ 6
+
+
+ 6
+
+
+
+
+
+
+
+
+ Qt::RightToLeft
+
+
+ QComboBox::AdjustToContents
+
+
+ false
+
+
+
+ 123
+
+
+
+
+ 123123
+
+
+
+
+
+
+
+
+ 175
+ 0
+
+
+
+ Please enter descriptive bug report title
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 55
+ 16777215
+
+
+
+ Edit Title
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ TextLabel
+
+
+
+
+
+
+
+
+ QLayout::SetDefaultConstraint
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 10
+
+
+
+
+
+
+
+ Continue
+
+
+
+
+
+
+
+
+
+
diff --git a/python3.7libs/searcher/ui_files/searcher_ui.py b/python3.7libs/searcher/ui_files/searcher_ui.py
new file mode 100644
index 0000000..52e4c64
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/searcher_ui.py
@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'searcher_ui.ui'
+#
+# Created by: qtpy UI code generator 5.14.1
+#
+# WARNING! All changes made in this file will be lost!
+
+
+from qtpy import QtCore, QtGui, QtWidgets
+
+
+class Ui_Searcher(object):
+ def setupUi(self, Searcher):
+ Searcher.setObjectName("Searcher")
+ Searcher.setWindowModality(QtCore.Qt.WindowModal)
+ Searcher.resize(1000, 329)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(Searcher.sizePolicy().hasHeightForWidth())
+ Searcher.setSizePolicy(sizePolicy)
+ Searcher.setMinimumSize(QtCore.QSize(0, 0))
+ Searcher.setBaseSize(QtCore.QSize(1000, 350))
+ Searcher.setStyleSheet("QTreeWidget QHeaderView::section {\n"
+" font-size: 9pt;\n"
+"}")
+ self.gridLayout = QtWidgets.QGridLayout(Searcher)
+ self.gridLayout.setContentsMargins(0, 0, 0, 0)
+ self.gridLayout.setSpacing(0)
+ self.gridLayout.setObjectName("gridLayout")
+ self.verticalLayout = QtWidgets.QVBoxLayout()
+ self.verticalLayout.setSpacing(0)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_3.setSpacing(0)
+ self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+ self.frame = QtWidgets.QFrame(Searcher)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(2)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth())
+ self.frame.setSizePolicy(sizePolicy)
+ self.frame.setMinimumSize(QtCore.QSize(0, 20))
+ self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
+ self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
+ self.frame.setObjectName("frame")
+ self.searchfilter_btn = QtWidgets.QToolButton(self.frame)
+ self.searchfilter_btn.setGeometry(QtCore.QRect(0, 0, 26, 20))
+ self.searchfilter_btn.setBaseSize(QtCore.QSize(16, 16))
+ self.searchfilter_btn.setStyleSheet("background-color: rgb(19, 19, 19);")
+ self.searchfilter_btn.setArrowType(QtCore.Qt.NoArrow)
+ self.searchfilter_btn.setObjectName("searchfilter_btn")
+ self.horizontalLayout_3.addWidget(self.frame)
+ self.searchbox_txt = QtWidgets.QLineEdit(Searcher)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ sizePolicy.setHorizontalStretch(99)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.searchbox_txt.sizePolicy().hasHeightForWidth())
+ self.searchbox_txt.setSizePolicy(sizePolicy)
+ self.searchbox_txt.setMinimumSize(QtCore.QSize(50, 0))
+ self.searchbox_txt.setMouseTracking(False)
+ self.searchbox_txt.setStyleSheet("background-color: rgb(19, 19, 19);")
+ self.searchbox_txt.setFrame(False)
+ self.searchbox_txt.setObjectName("searchbox_txt")
+ self.horizontalLayout_3.addWidget(self.searchbox_txt)
+ self.verticalLayout.addLayout(self.horizontalLayout_3)
+ self.searchresults_tree = QtWidgets.QTreeWidget(Searcher)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.searchresults_tree.sizePolicy().hasHeightForWidth())
+ self.searchresults_tree.setSizePolicy(sizePolicy)
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ self.searchresults_tree.setFont(font)
+ self.searchresults_tree.setMouseTracking(False)
+ self.searchresults_tree.setFocusPolicy(QtCore.Qt.NoFocus)
+ self.searchresults_tree.setFrameShadow(QtWidgets.QFrame.Sunken)
+ self.searchresults_tree.setLineWidth(0)
+ self.searchresults_tree.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
+ self.searchresults_tree.setAlternatingRowColors(True)
+ self.searchresults_tree.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
+ self.searchresults_tree.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
+ self.searchresults_tree.setObjectName("searchresults_tree")
+ self.searchresults_tree.headerItem().setText(0, "1")
+ self.verticalLayout.addWidget(self.searchresults_tree)
+ self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1)
+ self.infobar = QtWidgets.QHBoxLayout()
+ self.infobar.setObjectName("infobar")
+ self.infobargrid = QtWidgets.QGridLayout()
+ self.infobargrid.setObjectName("infobargrid")
+ self.info_lbl = QtWidgets.QLabel(Searcher)
+ font = QtGui.QFont()
+ font.setPointSize(8)
+ font.setBold(False)
+ font.setWeight(50)
+ self.info_lbl.setFont(font)
+ self.info_lbl.setStyleSheet("background-color: rgb(26, 26, 26);")
+ self.info_lbl.setIndent(5)
+ self.info_lbl.setObjectName("info_lbl")
+ self.infobargrid.addWidget(self.info_lbl, 1, 0, 1, 1)
+ self.label = QtWidgets.QLabel(Searcher)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
+ self.label.setSizePolicy(sizePolicy)
+ self.label.setMaximumSize(QtCore.QSize(50, 16777215))
+ self.label.setLayoutDirection(QtCore.Qt.RightToLeft)
+ self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
+ self.label.setObjectName("label")
+ self.infobargrid.addWidget(self.label, 1, 1, 1, 1)
+ self.infobar.addLayout(self.infobargrid)
+ self.gridLayout.addLayout(self.infobar, 3, 0, 1, 1)
+
+ self.retranslateUi(Searcher)
+ QtCore.QMetaObject.connectSlotsByName(Searcher)
+
+ def retranslateUi(self, Searcher):
+ _translate = QtCore.QCoreApplication.translate
+ Searcher.setWindowTitle(_translate("Searcher", "Searcher"))
+ self.searchfilter_btn.setText(_translate("Searcher", "..."))
+ self.info_lbl.setText(_translate("Searcher", "Begin typing to search or click magnifying glass icon to display options"))
+ self.label.setText(_translate("Searcher", "TextLabel"))
diff --git a/python3.7libs/searcher/ui_files/searcher_ui.ui b/python3.7libs/searcher/ui_files/searcher_ui.ui
new file mode 100644
index 0000000..2189a62
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/searcher_ui.ui
@@ -0,0 +1,248 @@
+
+
+ Searcher
+
+
+ Qt::WindowModal
+
+
+
+ 0
+ 0
+ 1000
+ 329
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 1000
+ 350
+
+
+
+ Searcher
+
+
+ QTreeWidget QHeaderView::section {
+ font-size: 9pt;
+}
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+
+
+ 2
+ 0
+
+
+
+
+ 0
+ 20
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+
+ 0
+ 0
+ 26
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ background-color: rgb(19, 19, 19);
+
+
+ ...
+
+
+ Qt::NoArrow
+
+
+
+
+
+
+
+
+ 99
+ 0
+
+
+
+
+ 50
+ 0
+
+
+
+ false
+
+
+ background-color: rgb(19, 19, 19);
+
+
+ false
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 9
+
+
+
+ false
+
+
+ Qt::NoFocus
+
+
+ QFrame::Sunken
+
+
+ 0
+
+
+ QAbstractScrollArea::AdjustToContents
+
+
+ true
+
+
+ QAbstractItemView::SingleSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+ 50
+ false
+
+
+
+ background-color: rgb(26, 26, 26);
+
+
+ Begin typing to search or click magnifying glass icon to display options
+
+
+ 2
+
+
+ 5
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 16777215
+
+
+
+ Qt::RightToLeft
+
+
+ TextLabel
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/python3.7libs/searcher/ui_files/theme_tabs.py b/python3.7libs/searcher/ui_files/theme_tabs.py
new file mode 100644
index 0000000..410a2ea
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/theme_tabs.py
@@ -0,0 +1,288 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'theme_tabs.ui'
+#
+# Created by: qtpy UI code generator 5.14.1
+#
+# WARNING! All changes made in this file will be lost!
+
+
+from qtpy import QtCore, QtGui, QtWidgets
+
+
+class Ui_Theme(object):
+ def setupUi(self, Theme):
+ Theme.setObjectName("Theme")
+ Theme.setWindowModality(QtCore.Qt.NonModal)
+ Theme.resize(556, 206)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(Theme.sizePolicy().hasHeightForWidth())
+ Theme.setSizePolicy(sizePolicy)
+ Theme.setMinimumSize(QtCore.QSize(100, 0))
+ Theme.setBaseSize(QtCore.QSize(0, 0))
+ Theme.setStyleSheet("")
+ self.gridLayout = QtWidgets.QGridLayout(Theme)
+ self.gridLayout.setContentsMargins(-1, -1, -1, 6)
+ self.gridLayout.setSpacing(6)
+ self.gridLayout.setObjectName("gridLayout")
+ self.r2 = QtWidgets.QVBoxLayout()
+ self.r2.setObjectName("r2")
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.horizontalLayout_2.addItem(spacerItem)
+ self.discardtheme = QtWidgets.QPushButton(Theme)
+ self.discardtheme.setObjectName("discardtheme")
+ self.horizontalLayout_2.addWidget(self.discardtheme)
+ self.savetheme = QtWidgets.QPushButton(Theme)
+ self.savetheme.setObjectName("savetheme")
+ self.horizontalLayout_2.addWidget(self.savetheme)
+ self.r2.addLayout(self.horizontalLayout_2)
+ self.gridLayout.addLayout(self.r2, 2, 0, 1, 1)
+ self.verticalLayout = QtWidgets.QVBoxLayout()
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.tabWidget = QtWidgets.QTabWidget(Theme)
+ self.tabWidget.setObjectName("tabWidget")
+ self.tab = QtWidgets.QWidget()
+ self.tab.setObjectName("tab")
+ self.layoutWidget = QtWidgets.QWidget(self.tab)
+ self.layoutWidget.setGeometry(QtCore.QRect(0, 0, 533, 164))
+ self.layoutWidget.setObjectName("layoutWidget")
+ self.r1 = QtWidgets.QHBoxLayout(self.layoutWidget)
+ self.r1.setContentsMargins(6, 6, 6, 0)
+ self.r1.setObjectName("r1")
+ self.c1 = QtWidgets.QVBoxLayout()
+ self.c1.setObjectName("c1")
+ self.h4_c1 = QtWidgets.QHBoxLayout()
+ self.h4_c1.setObjectName("h4_c1")
+ self.text2_lbl = QtWidgets.QLabel(self.layoutWidget)
+ self.text2_lbl.setObjectName("text2_lbl")
+ self.h4_c1.addWidget(self.text2_lbl)
+ spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h4_c1.addItem(spacerItem1)
+ self.text2_btn = QtWidgets.QToolButton(self.layoutWidget)
+ self.text2_btn.setText("")
+ self.text2_btn.setObjectName("text2_btn")
+ self.h4_c1.addWidget(self.text2_btn)
+ self.text2 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.text2.sizePolicy().hasHeightForWidth())
+ self.text2.setSizePolicy(sizePolicy)
+ self.text2.setMinimumSize(QtCore.QSize(75, 0))
+ self.text2.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.text2.setBaseSize(QtCore.QSize(75, 0))
+ self.text2.setReadOnly(True)
+ self.text2.setObjectName("text2")
+ self.h4_c1.addWidget(self.text2)
+ spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+ self.h4_c1.addItem(spacerItem2)
+ self.c1.addLayout(self.h4_c1)
+ self.h1_c2 = QtWidgets.QHBoxLayout()
+ self.h1_c2.setObjectName("h1_c2")
+ self.tooltip_lbl = QtWidgets.QLabel(self.layoutWidget)
+ self.tooltip_lbl.setObjectName("tooltip_lbl")
+ self.h1_c2.addWidget(self.tooltip_lbl)
+ self.tooltip_btn = QtWidgets.QToolButton(self.layoutWidget)
+ self.tooltip_btn.setText("")
+ self.tooltip_btn.setObjectName("tooltip_btn")
+ self.h1_c2.addWidget(self.tooltip_btn)
+ self.tooltip = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.tooltip.sizePolicy().hasHeightForWidth())
+ self.tooltip.setSizePolicy(sizePolicy)
+ self.tooltip.setMinimumSize(QtCore.QSize(75, 0))
+ self.tooltip.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.tooltip.setReadOnly(True)
+ self.tooltip.setObjectName("tooltip")
+ self.h1_c2.addWidget(self.tooltip)
+ spacerItem3 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+ self.h1_c2.addItem(spacerItem3)
+ self.c1.addLayout(self.h1_c2)
+ self.h3_c1 = QtWidgets.QHBoxLayout()
+ self.h3_c1.setObjectName("h3_c1")
+ self.text1_lbl = QtWidgets.QLabel(self.layoutWidget)
+ self.text1_lbl.setObjectName("text1_lbl")
+ self.h3_c1.addWidget(self.text1_lbl)
+ spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h3_c1.addItem(spacerItem4)
+ self.text1_btn = QtWidgets.QToolButton(self.layoutWidget)
+ self.text1_btn.setText("")
+ self.text1_btn.setObjectName("text1_btn")
+ self.h3_c1.addWidget(self.text1_btn)
+ self.text1 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.text1.sizePolicy().hasHeightForWidth())
+ self.text1.setSizePolicy(sizePolicy)
+ self.text1.setMinimumSize(QtCore.QSize(75, 0))
+ self.text1.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.text1.setBaseSize(QtCore.QSize(75, 0))
+ self.text1.setReadOnly(True)
+ self.text1.setObjectName("text1")
+ self.h3_c1.addWidget(self.text1)
+ spacerItem5 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+ self.h3_c1.addItem(spacerItem5)
+ self.c1.addLayout(self.h3_c1)
+ self.h2_c1 = QtWidgets.QHBoxLayout()
+ self.h2_c1.setObjectName("h2_c1")
+ self.stats1_lbl = QtWidgets.QLabel(self.layoutWidget)
+ self.stats1_lbl.setObjectName("stats1_lbl")
+ self.h2_c1.addWidget(self.stats1_lbl)
+ spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h2_c1.addItem(spacerItem6)
+ self.stats1_btn = QtWidgets.QToolButton(self.layoutWidget)
+ self.stats1_btn.setText("")
+ self.stats1_btn.setObjectName("stats1_btn")
+ self.h2_c1.addWidget(self.stats1_btn)
+ self.stats1 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.stats1.sizePolicy().hasHeightForWidth())
+ self.stats1.setSizePolicy(sizePolicy)
+ self.stats1.setMinimumSize(QtCore.QSize(75, 0))
+ self.stats1.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.stats1.setBaseSize(QtCore.QSize(75, 0))
+ self.stats1.setReadOnly(True)
+ self.stats1.setObjectName("stats1")
+ self.h2_c1.addWidget(self.stats1)
+ spacerItem7 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+ self.h2_c1.addItem(spacerItem7)
+ self.c1.addLayout(self.h2_c1)
+ spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.c1.addItem(spacerItem8)
+ self.r1.addLayout(self.c1)
+ self.c2 = QtWidgets.QVBoxLayout()
+ self.c2.setObjectName("c2")
+ self.h1_c1 = QtWidgets.QHBoxLayout()
+ self.h1_c1.setObjectName("h1_c1")
+ self.stats2_lbl = QtWidgets.QLabel(self.layoutWidget)
+ self.stats2_lbl.setObjectName("stats2_lbl")
+ self.h1_c1.addWidget(self.stats2_lbl)
+ spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h1_c1.addItem(spacerItem9)
+ spacerItem10 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+ self.h1_c1.addItem(spacerItem10)
+ self.stats2_btn = QtWidgets.QToolButton(self.layoutWidget)
+ self.stats2_btn.setText("")
+ self.stats2_btn.setObjectName("stats2_btn")
+ self.h1_c1.addWidget(self.stats2_btn)
+ self.stats2 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.stats2.sizePolicy().hasHeightForWidth())
+ self.stats2.setSizePolicy(sizePolicy)
+ self.stats2.setMinimumSize(QtCore.QSize(75, 0))
+ self.stats2.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.stats2.setBaseSize(QtCore.QSize(75, 0))
+ self.stats2.setReadOnly(True)
+ self.stats2.setObjectName("stats2")
+ self.h1_c1.addWidget(self.stats2)
+ self.c2.addLayout(self.h1_c1)
+ self.h2_c2 = QtWidgets.QHBoxLayout()
+ self.h2_c2.setObjectName("h2_c2")
+ self.label_7 = QtWidgets.QLabel(self.layoutWidget)
+ self.label_7.setEnabled(True)
+ self.label_7.setObjectName("label_7")
+ self.h2_c2.addWidget(self.label_7)
+ spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h2_c2.addItem(spacerItem11)
+ self.toolButton_6 = QtWidgets.QToolButton(self.layoutWidget)
+ self.toolButton_6.setText("")
+ self.toolButton_6.setObjectName("toolButton_6")
+ self.h2_c2.addWidget(self.toolButton_6)
+ self.lineEdit_3 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.lineEdit_3.sizePolicy().hasHeightForWidth())
+ self.lineEdit_3.setSizePolicy(sizePolicy)
+ self.lineEdit_3.setMinimumSize(QtCore.QSize(75, 0))
+ self.lineEdit_3.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.lineEdit_3.setReadOnly(True)
+ self.lineEdit_3.setObjectName("lineEdit_3")
+ self.h2_c2.addWidget(self.lineEdit_3)
+ self.c2.addLayout(self.h2_c2)
+ self.h3_c2 = QtWidgets.QHBoxLayout()
+ self.h3_c2.setObjectName("h3_c2")
+ self.label_6 = QtWidgets.QLabel(self.layoutWidget)
+ self.label_6.setObjectName("label_6")
+ self.h3_c2.addWidget(self.label_6)
+ spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h3_c2.addItem(spacerItem12)
+ self.toolButton_7 = QtWidgets.QToolButton(self.layoutWidget)
+ self.toolButton_7.setText("")
+ self.toolButton_7.setObjectName("toolButton_7")
+ self.h3_c2.addWidget(self.toolButton_7)
+ self.lineEdit_4 = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.lineEdit_4.sizePolicy().hasHeightForWidth())
+ self.lineEdit_4.setSizePolicy(sizePolicy)
+ self.lineEdit_4.setMinimumSize(QtCore.QSize(75, 0))
+ self.lineEdit_4.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.lineEdit_4.setReadOnly(True)
+ self.lineEdit_4.setObjectName("lineEdit_4")
+ self.h3_c2.addWidget(self.lineEdit_4)
+ self.c2.addLayout(self.h3_c2)
+ self.h4_c2 = QtWidgets.QHBoxLayout()
+ self.h4_c2.setObjectName("h4_c2")
+ self.label_5 = QtWidgets.QLabel(self.layoutWidget)
+ self.label_5.setObjectName("label_5")
+ self.h4_c2.addWidget(self.label_5)
+ spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.h4_c2.addItem(spacerItem13)
+ self.toolButton_8 = QtWidgets.QToolButton(self.layoutWidget)
+ self.toolButton_8.setText("")
+ self.toolButton_8.setObjectName("toolButton_8")
+ self.h4_c2.addWidget(self.toolButton_8)
+ self.lineEdit = QtWidgets.QLineEdit(self.layoutWidget)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.lineEdit.sizePolicy().hasHeightForWidth())
+ self.lineEdit.setSizePolicy(sizePolicy)
+ self.lineEdit.setMinimumSize(QtCore.QSize(75, 0))
+ self.lineEdit.setMaximumSize(QtCore.QSize(75, 16777215))
+ self.lineEdit.setReadOnly(True)
+ self.lineEdit.setObjectName("lineEdit")
+ self.h4_c2.addWidget(self.lineEdit)
+ self.c2.addLayout(self.h4_c2)
+ spacerItem14 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.c2.addItem(spacerItem14)
+ self.r1.addLayout(self.c2)
+ self.tabWidget.addTab(self.tab, "")
+ self.tab_2 = QtWidgets.QWidget()
+ self.tab_2.setObjectName("tab_2")
+ self.tabWidget.addTab(self.tab_2, "")
+ self.verticalLayout.addWidget(self.tabWidget)
+ self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
+
+ self.retranslateUi(Theme)
+ self.tabWidget.setCurrentIndex(0)
+ QtCore.QMetaObject.connectSlotsByName(Theme)
+
+ def retranslateUi(self, Theme):
+ _translate = QtCore.QCoreApplication.translate
+ Theme.setWindowTitle(_translate("Theme", "Form"))
+ self.discardtheme.setText(_translate("Theme", "Discard"))
+ self.savetheme.setText(_translate("Theme", "Save"))
+ self.text2_lbl.setText(_translate("Theme", "Search Results Context"))
+ self.tooltip_lbl.setText(_translate("Theme", "Tool Tip Info"))
+ self.text1_lbl.setText(_translate("Theme", "Result Stats Text"))
+ self.stats1_lbl.setText(_translate("Theme", "Result Stat Values"))
+ self.stats2_lbl.setText(_translate("Theme", "Secondary Stat Values"))
+ self.label_7.setText(_translate("Theme", "TextLabel"))
+ self.label_6.setText(_translate("Theme", "TextLabel"))
+ self.label_5.setText(_translate("Theme", "TextLabel"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Theme", "Text"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Theme", "Window"))
diff --git a/python3.7libs/searcher/ui_files/theme_tabs.ui b/python3.7libs/searcher/ui_files/theme_tabs.ui
new file mode 100644
index 0000000..ddde525
--- /dev/null
+++ b/python3.7libs/searcher/ui_files/theme_tabs.ui
@@ -0,0 +1,704 @@
+
+
+ Theme
+
+
+ Qt::NonModal
+
+
+
+ 0
+ 0
+ 556
+ 206
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+
+
+
+
+ 6
+
+
+ 6
+
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ Discard
+
+
+
+
+
+
+ Save
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+ Text
+
+
+
+
+ 0
+ 0
+ 533
+ 164
+
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+
+
+
+
+
+
+ Search Results Context
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ 0
+
+
+
+
+ 75
+ 16777215
+
+
+
+
+ 75
+ 0
+
+
+
+ true
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 20
+
+
+
+
+
+
+
+
+
+
+
+ Tool Tip Info
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ 0
+
+
+
+
+ 75
+ 16777215
+
+
+
+ true
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 20
+
+
+
+
+
+
+
+
+
+
+
+ Result Stats Text
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ 0
+
+
+
+
+ 75
+ 16777215
+
+
+
+
+ 75
+ 0
+
+
+
+ true
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 20
+
+
+
+
+
+
+
+
+
+
+
+ Result Stat Values
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ 0
+
+
+
+
+ 75
+ 16777215
+
+
+
+
+ 75
+ 0
+
+
+
+ true
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 20
+
+
+
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Secondary Stat Values
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ 0
+
+
+
+
+ 75
+ 16777215
+
+
+
+
+ 75
+ 0
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ TextLabel
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ 0
+
+
+
+
+ 75
+ 16777215
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ TextLabel
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ 0
+
+
+
+
+ 75
+ 16777215
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ TextLabel
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ 0
+
+
+
+
+ 75
+ 16777215
+
+
+
+ true
+
+
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+ Window
+
+
+
+
+
+
+
+
+
+
+
diff --git a/python3.7libs/searcher/util.py b/python3.7libs/searcher/util.py
new file mode 100644
index 0000000..2f9b5a7
--- /dev/null
+++ b/python3.7libs/searcher/util.py
@@ -0,0 +1,724 @@
+from __future__ import print_function
+from __future__ import absolute_import
+
+import sys
+
+from searcher import enum
+
+from typing import Tuple
+import os
+import hou
+
+hver = 0
+if os.environ["HFS"] != "" or os.environ["HFS"] is not None:
+ ver = os.environ["HFS"]
+ # hver = int(ver[ver.rindex('.') + 1:])
+ from hutil.Qt import QtCore
+else:
+ from qtpy import QtCore
+
+script_path = os.path.dirname(os.path.realpath(__file__))
+
+# @formatter:off ---------------------------------------- Helper Functions
+# SECTION Helper Functions -----------------------------------------------
+# @formatter:off ------------------------------ DEBUG_LEVEL
+# NOTE DEBUG_LEVEL ----------------------------------------
+DEBUG_LEVEL = enum.Enum('NONE', 'TIMER', 'ALL')
+class Dbug(object):
+ def __init__(self, enabled, level, perf, mainwindow=False):
+ self.enabled = enabled
+ self.level = level
+ self.performance = perf
+ self.mainwindow = mainwindow
+
+ def __nonzero__(self): return bool(self.enabled)
+
+class AppColors(object):
+ def __init__(self, colors={}):
+ self.text1 = colors[COLORFIELDS[0]]
+ self.text2 = colors[COLORFIELDS[1]]
+ self.stats1 = colors[COLORFIELDS[2]]
+ self.stats2 = colors[COLORFIELDS[3]]
+ self.tooltip = colors[COLORFIELDS[4]]
+
+# @formatter:off ----------------------------- get_platform
+# NOTE get_platform ---------------------------------------
+def get_platform():
+ return getattr(hou.session, "PLATFORM", None)
+
+# @formatter:off ----------------------------- get_settings
+# NOTE get_settings ---------------------------------------
+def get_settings():
+ return getattr(hou.session, "SETTINGS", None)
+
+
+# @formatter:off ----------------------------- get_settings
+# NOTE get_settings ---------------------------------------
+def get_path(folders=None):
+ s_path = os.path.dirname(os.path.realpath(__file__))
+ path = os.path.join(s_path, '/'.join(folders))
+ return path.replace("\\", "/")
+
+# @formatter:off --------------------------- Bool Converter
+# NOTE Bool Converter -------------------------------------
+def bc(v):
+ return str(v).lower() in ("yes", "true", "t", "1")
+
+# !SECTION Helper Functions
+
+
+# @formatter:off ------------------------------------------------ Settings
+# SECTION Settings -------------------------------------------------------
+# @formatter:off ---------------------------- SETTINGS_KEYS
+# NOTE SETTINGS_KEYS --------------------------------------
+SETTINGS_KEYS = [
+ 'in_memory_db', # 0
+ 'database_path', # 1
+ 'savewindowsize', # 2
+ 'windowsize', # 3
+ 'debugflag', # 4
+ 'pinwindow', # 5
+ 'defaulthotkey', # 6
+ 'showctx', # 7
+ 'animatedsettings', # 8
+ 'maxresults', # 9
+ 'debuglevel', # 10
+ 'lastkey', # 11
+ 'metrics', # 12
+ 'metricsmainwindow', # 13
+ 'appcolors', # 14
+ 'expanditems', # 15
+]
+
+# @formatter:off ------------------------------ COLORFIELDS
+# The names of the customizable colorfields
+# NOTE COLORFIELDS ----------------------------------------
+COLORFIELDS = [
+ 'text1', # 0
+ 'text2', # 1
+ 'stats1', # 2
+ 'stats2', # 3
+ 'tooltip', # 4
+]
+
+# @formatter:off --------------------------- SETTINGS_TYPES
+# Include type if it is to be processed, else mark NA
+# {bool, text, int, intval} get processed by settings menu
+# {flag} is a bool but handled separate from settings menu
+# {NA} is other, handled separaretly as well
+# NOTE SETTINGS_TYPES -------------------------------------
+SETTINGS_TYPES = {
+ SETTINGS_KEYS[0]: 'bool', # in_memory_db
+ SETTINGS_KEYS[1]: 'text', # database_path
+ SETTINGS_KEYS[2]: 'bool', # savewindowsize
+ SETTINGS_KEYS[3]: 'int', # windowsize
+ SETTINGS_KEYS[4]: 'bool', # debugflag
+ SETTINGS_KEYS[5]: 'flag', # pinwindow
+ SETTINGS_KEYS[6]: 'text', # defaulthotkey
+ SETTINGS_KEYS[7]: 'flag', # showctx
+ SETTINGS_KEYS[8]: 'bool', # animatedsettings
+ SETTINGS_KEYS[9]: 'intval', # maxresults
+ SETTINGS_KEYS[10]: 'cbx', # debuglevel
+ SETTINGS_KEYS[11]: 'NA', # lastkey
+ SETTINGS_KEYS[12]: 'bool', # metrics
+ SETTINGS_KEYS[13]: 'flag', # metricsmainwindow
+ SETTINGS_KEYS[14]: 'NA', # appcolors
+ SETTINGS_KEYS[15]: 'flag', # expanditems
+}
+
+# @formatter:off ------------------------- DEFAULT_SETTINGS
+# Default settings automatically applied upon creations
+# NOTE DEFAULT_SETTINGS -----------------------------------
+defaultHKeys = u"Cmd+Alt+Shift+F7" if sys.platform == 'darwin' else u"Ctrl+Alt+Shift+F7"
+DEFAULT_SETTINGS = {
+ SETTINGS_KEYS[0]: "False", # in_memory_db
+ SETTINGS_KEYS[1]: "", # database_path
+ SETTINGS_KEYS[2]: "True", # savewindowsize
+ SETTINGS_KEYS[3]: [750, 350], # windowsize
+ SETTINGS_KEYS[4]: "False", # debugflag
+ SETTINGS_KEYS[5]: "False", # pinwindow
+ SETTINGS_KEYS[6]: defaultHKeys, # defaulthotkey
+ SETTINGS_KEYS[7]: "True", # showctx
+ SETTINGS_KEYS[8]: "True", # animatedsettings
+ SETTINGS_KEYS[9]: 100, # maxresults
+ SETTINGS_KEYS[10]: "NONE", # debuglevel
+ SETTINGS_KEYS[11]: "", # lastkey
+ SETTINGS_KEYS[12]: "False", # metrics
+ SETTINGS_KEYS[13]: "False", # metricsmainwindow
+ SETTINGS_KEYS[14]: { # appcolors
+ COLORFIELDS[0]: "#607FAE", # text1
+ COLORFIELDS[1]: "#D2A00C", # text2
+ COLORFIELDS[2]: "#c2efe5", # stats1
+ COLORFIELDS[3]: "#c2efe5", # stats2
+ COLORFIELDS[4]: "#607FAE", # tooltip
+ },
+ SETTINGS_KEYS[15]: "True", # expanditems
+}
+# !SECTION Settings
+
+# @formatter:off ---------------------------------------- Key Translations
+# SECTION Key Translations -----------------------------------------------
+
+# @formatter:off ------------------------------ CTXSHOTCUTS
+# Context shortcodes for predefined results
+# NOTE CTXSHOTCUTS ----------------------------------------
+CTXSHOTCUTS = [":v", ":c", ":g"]
+
+# @formatter:off --------------------------- KEYCONVERSIONS
+# Convertions for arrow keys (Should be moved to main dict)
+# NOTE KEYCONVERSIONS -------------------------------------
+KEYCONVERSIONS = {
+ "DownArrow": "down",
+ "UpArrow": "up",
+ "LeftArrow": "left",
+ "RightArrow": "right",
+}
+
+# @formatter:off ------------------------------- HOTKEYLIST
+# List of possible hotkeys to use a temp keys when running commands
+# NOTE HOTKEYLIST -----------------------------------------
+HOTKEYLIST = [
+ u"Ctrl+Alt+Shift+F7",
+ u"Ctrl+Alt+Shift+F6",
+ u"Ctrl+Alt+Shift+F8",
+ u"Ctrl+Alt+Shift+F9",
+ u"Ctrl+Alt+Shift+F10"
+]
+
+HOTKEYLISTOSX = [
+ u"Cmd+Alt+Shift+F7",
+ u"Cmd+Alt+Shift+F6",
+ u"Cmd+Alt+Shift+F8",
+ u"Cmd+Alt+Shift+F9",
+ u"Cmd+Alt+Shift+F10"
+]
+
+def gethotkeys():
+ hkeys = []
+ settings = get_settings()
+ hkeys.append(settings[SETTINGS_KEYS[6]])
+ hklist = HOTKEYLISTOSX if sys.platform == 'darwin' else HOTKEYLIST
+ for key in hklist:
+ hkeys.append(key)
+ return hkeys
+
+
+# Used for bitmasking to determine modifiers
+MODIFIERS = {}
+# Used for constructing a bitmasked modifier
+REVERSE_MODIFIERS = {}
+
+# @formatter:off ---------------------------- MODIFIER_KEYS
+# Used to detect if a keypress was just a modifier
+# NOTE MODIFIER_KEYS --------------------------------------
+MODIFIER_KEYS = {
+ QtCore.Qt.Key_Alt: "Alt",
+ QtCore.Qt.Key_Meta: "Cmd",
+ QtCore.Qt.Key_Shift: "Shift",
+ QtCore.Qt.Key_Control: "Ctrl",
+}
+
+# @formatter:off -------------------------------- MODIFIERS
+# NOTE MODIFIERS ------------------------------------------
+MODIFIERS = {
+ "Control": QtCore.Qt.ControlModifier,
+ "Ctrl": QtCore.Qt.ControlModifier,
+ "Shift": QtCore.Qt.ShiftModifier,
+ "Meta": QtCore.Qt.MetaModifier,
+ "Cmd": QtCore.Qt.MetaModifier,
+ "Alt": QtCore.Qt.AltModifier,
+}
+
+# @formatter:off ----------------------------- SPECIAL_KEYS
+# Special keys
+# NOTE SPECIAL_KEYS ---------------------------------------
+SPECIAL_KEYS = {
+ QtCore.Qt.Key_Backspace: "BACKSPACE",
+ QtCore.Qt.Key_Delete: "DELETE",
+ QtCore.Qt.Key_Escape: "ESCAPE",
+ QtCore.Qt.Key_hyphen: "HYPHEN",
+ QtCore.Qt.Key_Return: "RETURN",
+ QtCore.Qt.Key_Enter: "RETURN",
+ QtCore.Qt.Key_Space: "SPACE",
+ QtCore.Qt.Key_Tab: "TAB",
+ QtCore.Qt.Key_Left: "Left",
+ QtCore.Qt.Key_Right: "Right",
+ QtCore.Qt.Key_Up: "Up",
+ QtCore.Qt.Key_Down: "Down",
+ QtCore.Qt.Key_PageUp: "PageUp",
+ QtCore.Qt.Key_PageDown: "PageDown",
+ QtCore.Qt.Key_End: "Page_End",
+ QtCore.Qt.Key_Home: "Page_Home",
+}
+
+# @formatter:off --------------------------------- Platform
+# # Platform conversions
+# NOTE Platform -------------------------------------------
+# if platform == "linux" or platform == "linux2":
+# tmp = {
+# QtCore.Qt.ShiftModifier: "Shift",
+# QtCore.Qt.ControlModifier: "Ctrl",
+# QtCore.Qt.AltModifier: "Alt",
+# QtCore.Qt.MetaModifier: "M"
+# }
+# MODIFIERS.update(tmp)
+# tmp = {
+# "Shift": QtCore.Qt.ShiftModifier,
+# "Ctrl": QtCore.Qt.ControlModifier,
+# "Alt": QtCore.Qt.AltModifier
+# }
+# REVERSE_MODIFIERS.update(tmp)
+# elif platform == "darwin":
+# tmp = {
+# QtCore.Qt.ShiftModifier: "s",
+# QtCore.Qt.ControlModifier: "S",
+# QtCore.Qt.AltModifier: "M",
+# QtCore.Qt.MetaModifier: "C"
+# }
+# MODIFIERS.update(tmp)
+# tmp = {
+# "s": QtCore.Qt.ShiftModifier,
+# "S": QtCore.Qt.ControlModifier,
+# "M": QtCore.Qt.AltModifier,
+# "C": QtCore.Qt.MetaModifier
+# }
+# REVERSE_MODIFIERS.update(tmp)
+# elif platform == "win32" or platform == "win64":
+# tmp = {
+# QtCore.Qt.ShiftModifier: "Shift",
+# QtCore.Qt.ControlModifier: "Ctrl",
+# QtCore.Qt.AltModifier: "Alt",
+# QtCore.Qt.MetaModifier: "M"
+# }
+# MODIFIERS.update(tmp)
+# tmp = {
+# "Shift": QtCore.Qt.ShiftModifier,
+# "Ctrl": QtCore.Qt.ControlModifier,
+# "Alt": QtCore.Qt.AltModifier
+# }
+# REVERSE_MODIFIERS.update(tmp)
+# endregion
+
+# @formatter:off --------------------------------- KEY_DICT
+# NOTE KEY_DICT -------------------------------------------
+KEY_DICT = {
+ # @formatter:off ---------------------- Grey keys
+ "Escape": QtCore.Qt.Key_Escape,
+ "Tab": QtCore.Qt.Key_Tab,
+ "Backtab": QtCore.Qt.Key_Backtab,
+ "Backspace": QtCore.Qt.Key_Backspace,
+ "Return": QtCore.Qt.Key_Return,
+ "Enter": QtCore.Qt.Key_Enter,
+ "Insert": QtCore.Qt.Key_Insert,
+ "Del": QtCore.Qt.Key_Delete,
+ "Pause": QtCore.Qt.Key_Pause,
+ "Print": QtCore.Qt.Key_Print,
+ "SysReq": QtCore.Qt.Key_SysReq,
+ "Home": QtCore.Qt.Key_Home,
+ "End": QtCore.Qt.Key_End,
+ "Left": QtCore.Qt.Key_Left,
+ "Up": QtCore.Qt.Key_Up,
+ "Right": QtCore.Qt.Key_Right,
+ "Down": QtCore.Qt.Key_Down,
+ "Prior": None,
+ "Next": None,
+ "Shift": QtCore.Qt.Key_Shift,
+ "Control": QtCore.Qt.Key_Control,
+ "Ctrl": QtCore.Qt.Key_Control,
+ "Cmd": QtCore.Qt.Key_Meta,
+ "Meta": QtCore.Qt.Key_Meta,
+ "Alt": QtCore.Qt.Key_Alt,
+ "CapsLock": QtCore.Qt.Key_CapsLock,
+ "NumLock": QtCore.Qt.Key_NumLock,
+ "ScrollLock": QtCore.Qt.Key_ScrollLock,
+ "F1": QtCore.Qt.Key_F1,
+ "F2": QtCore.Qt.Key_F2,
+ "F3": QtCore.Qt.Key_F3,
+ "F4": QtCore.Qt.Key_F4,
+ "F5": QtCore.Qt.Key_F5,
+ "F6": QtCore.Qt.Key_F6,
+ "F7": QtCore.Qt.Key_F7,
+ "F8": QtCore.Qt.Key_F8,
+ "F9": QtCore.Qt.Key_F9,
+ "F10": QtCore.Qt.Key_F10,
+ "F11": QtCore.Qt.Key_F11,
+ "F12": QtCore.Qt.Key_F12,
+ "F13": QtCore.Qt.Key_F13,
+ "F14": QtCore.Qt.Key_F14,
+ "F15": QtCore.Qt.Key_F15,
+ "F16": QtCore.Qt.Key_F16,
+ "F17": QtCore.Qt.Key_F17,
+ "F18": QtCore.Qt.Key_F18,
+ "F19": QtCore.Qt.Key_F19,
+ "F20": QtCore.Qt.Key_F20,
+ "F21": QtCore.Qt.Key_F21,
+ "F22": QtCore.Qt.Key_F22,
+ "F23": QtCore.Qt.Key_F23,
+ "F24": QtCore.Qt.Key_F24,
+ "F25": QtCore.Qt.Key_F25,
+ "F26": QtCore.Qt.Key_F26,
+ "F27": QtCore.Qt.Key_F27,
+ "F28": QtCore.Qt.Key_F28,
+ "F29": QtCore.Qt.Key_F29,
+ "F30": QtCore.Qt.Key_F30,
+ "F31": QtCore.Qt.Key_F31,
+ "F32": QtCore.Qt.Key_F32,
+ "F33": QtCore.Qt.Key_F33,
+ "F34": QtCore.Qt.Key_F34,
+ "F35": QtCore.Qt.Key_F35,
+ "Super_L": QtCore.Qt.Key_Super_L,
+ "Super_R": QtCore.Qt.Key_Super_R,
+ "Menu": QtCore.Qt.Key_Menu,
+ "Hyper_L": QtCore.Qt.Key_Hyper_L,
+ "Hyper_R": QtCore.Qt.Key_Hyper_R,
+ # @formatter:off ---------------------- Regular keys
+ "Space": QtCore.Qt.Key_Space,
+ "Exclam": QtCore.Qt.Key_Exclam,
+ "!": QtCore.Qt.Key_Exclam,
+ "QuoteDbl": QtCore.Qt.Key_QuoteDbl,
+ "\"": QtCore.Qt.Key_QuoteDbl,
+ "NumberSign": QtCore.Qt.Key_NumberSign,
+ "#": QtCore.Qt.Key_NumberSign,
+ "Dollar": QtCore.Qt.Key_Dollar,
+ "$": QtCore.Qt.Key_Dollar,
+ "Percent": QtCore.Qt.Key_Percent,
+ "%": QtCore.Qt.Key_Percent,
+ "Ampersand": QtCore.Qt.Key_Ampersand,
+ "&": QtCore.Qt.Key_Ampersand,
+ "Apostrophe": QtCore.Qt.Key_Apostrophe,
+ "\'": QtCore.Qt.Key_Apostrophe,
+ "ParenLeft": QtCore.Qt.Key_ParenLeft,
+ "(": QtCore.Qt.Key_ParenLeft,
+ "ParenRight": QtCore.Qt.Key_ParenRight,
+ ")": QtCore.Qt.Key_ParenRight,
+ "Asterisk": QtCore.Qt.Key_Asterisk,
+ "*": QtCore.Qt.Key_Asterisk,
+ "+": QtCore.Qt.Key_Plus,
+ "Plus": QtCore.Qt.Key_Plus,
+ "Comma": QtCore.Qt.Key_Comma,
+ ",": QtCore.Qt.Key_Comma,
+ "Minus": QtCore.Qt.Key_Minus,
+ "-": QtCore.Qt.Key_Minus,
+ "Period": QtCore.Qt.Key_Period,
+ ".": QtCore.Qt.Key_Period,
+ "Slash": QtCore.Qt.Key_Slash,
+ "/": QtCore.Qt.Key_Slash,
+ "0": QtCore.Qt.Key_0,
+ "1": QtCore.Qt.Key_1,
+ "2": QtCore.Qt.Key_2,
+ "3": QtCore.Qt.Key_3,
+ "4": QtCore.Qt.Key_4,
+ "5": QtCore.Qt.Key_5,
+ "6": QtCore.Qt.Key_6,
+ "7": QtCore.Qt.Key_7,
+ "8": QtCore.Qt.Key_8,
+ "9": QtCore.Qt.Key_9,
+ "Colon": QtCore.Qt.Key_Colon,
+ ":": QtCore.Qt.Key_Colon,
+ "Semicolon": QtCore.Qt.Key_Semicolon,
+ ";": QtCore.Qt.Key_Semicolon,
+ "Less": QtCore.Qt.Key_Less,
+ "<": QtCore.Qt.Key_Less,
+ "Equal": QtCore.Qt.Key_Equal,
+ "=": QtCore.Qt.Key_Equal,
+ "Greater": QtCore.Qt.Key_Greater,
+ ">": QtCore.Qt.Key_Greater,
+ "Question": QtCore.Qt.Key_Question,
+ "?": QtCore.Qt.Key_Question,
+ "At": QtCore.Qt.Key_At,
+ "A": QtCore.Qt.Key_A,
+ "B": QtCore.Qt.Key_B,
+ "C": QtCore.Qt.Key_C,
+ "D": QtCore.Qt.Key_D,
+ "E": QtCore.Qt.Key_E,
+ "F": QtCore.Qt.Key_F,
+ "G": QtCore.Qt.Key_G,
+ "H": QtCore.Qt.Key_H,
+ "I": QtCore.Qt.Key_I,
+ "J": QtCore.Qt.Key_J,
+ "K": QtCore.Qt.Key_K,
+ "L": QtCore.Qt.Key_L,
+ "M": QtCore.Qt.Key_M,
+ "N": QtCore.Qt.Key_N,
+ "O": QtCore.Qt.Key_O,
+ "P": QtCore.Qt.Key_P,
+ "Q": QtCore.Qt.Key_Q,
+ "R": QtCore.Qt.Key_R,
+ "S": QtCore.Qt.Key_S,
+ "T": QtCore.Qt.Key_T,
+ "U": QtCore.Qt.Key_U,
+ "V": QtCore.Qt.Key_V,
+ "W": QtCore.Qt.Key_W,
+ "X": QtCore.Qt.Key_X,
+ "Y": QtCore.Qt.Key_Y,
+ "Z": QtCore.Qt.Key_Z,
+ "PageUp": QtCore.Qt.Key_PageUp,
+ "PageDown": QtCore.Qt.Key_PageDown,
+ "BracketLeft": QtCore.Qt.Key_BracketLeft,
+ "[": QtCore.Qt.Key_BracketLeft,
+ "BracketRight": QtCore.Qt.Key_BracketRight,
+ "]": QtCore.Qt.Key_BracketRight,
+ "Backslash": QtCore.Qt.Key_Backslash,
+ "\\": QtCore.Qt.Key_Backslash,
+ "Underscore": QtCore.Qt.Key_Underscore,
+ "_": QtCore.Qt.Key_Underscore,
+ "QuoteLeft": QtCore.Qt.Key_QuoteLeft,
+ "BraceLeft": QtCore.Qt.Key_BraceLeft,
+ "{": QtCore.Qt.Key_BraceLeft,
+ "BraceRight": QtCore.Qt.Key_BraceRight,
+ "}": QtCore.Qt.Key_BraceRight,
+ "Bar": QtCore.Qt.Key_Bar,
+ "|": QtCore.Qt.Key_Bar,
+ "AsciiCircum": QtCore.Qt.Key_AsciiCircum,
+ "^": QtCore.Qt.Key_AsciiCircum,
+ "AsciiTilde": QtCore.Qt.Key_AsciiTilde,
+ "~": QtCore.Qt.Key_AsciiTilde,
+}
+# !SECTION Key Translations
+
+# @formatter:off ------------------------------------ Houdini Translations
+# SECTION Houdini Translations -------------------------------------------
+# @formatter:off ------------------------------- getcontext
+# NOTE getcontext -----------------------------------------
+def getcontext(editor):
+ """Return houdini context string."""
+ hou_context = editor.pwd().childTypeCategory().name()
+ if hou_context == 'Sop':
+ return 'SOP'
+ elif hou_context == 'Dop':
+ return 'DOP'
+ elif hou_context == 'Object':
+ return 'OBJ'
+ elif hou_context == 'Driver':
+ return 'ROP'
+ elif hou_context == 'Chop':
+ return 'CHOP'
+ elif hou_context == 'Vop':
+ return 'VOP'
+ elif hou_context == 'Shop':
+ return 'SHOP'
+ elif hou_context == 'Cop2':
+ return 'COP'
+
+
+# @formatter:off ------------------------------ CONTEXTTYPE
+# NOTE CONTEXTTYPE ----------------------------------------
+CONTEXTTYPE = {
+ "Cop2": "COP",
+ "CopNet": "COPNET",
+ "Chop": "CHOP",
+ "ChopNet": "CHOPNET",
+ "Dop": "DOP",
+ "Driver": "ROP",
+ "Object": "OBJ",
+ "Particle": "PART",
+ "Pop": "POP",
+ "Sop": "SOP",
+ "Shop": "SHOP",
+ "Tsop": "TSOP",
+ "Vop": "VOP",
+ "VopNet": "VEX",
+}
+
+# @formatter:off -------------------------------- PANETYPES
+# NOTE PANETYPES ------------------------------------------
+PANETYPES = {
+ hou.paneTabType.AssetBrowser: [["h.pane.projectm"], "Asset Browser"],
+ hou.paneTabType.BundleList: [["h.pane.bundle"], "Bundle List"],
+ hou.paneTabType.ChannelEditor: [["h.pane.chedit", "h.pane.chedit.dope", "h.pane.chedit.dope.py", "h.pane.chedit.graph", "h.pane.chedit.graph.py", "h.pane.chedit.table", "h.pane.chedit.table.py"], "Channel Editor"],
+ hou.paneTabType.ChannelList: [["h.pane.chlist", "h.pane.chlist.ch", "h.pane.chlist.layers", "h.pane.chlist.parmbox"], "Channel List"],
+ hou.paneTabType.ChannelViewer: [["h.pane.gview.selmodechview"], "Channel Viewer"],
+ hou.paneTabType.CompositorViewer: [["h.pane.imgui.state", "h.pane.imgui.state.cop"], "Compositor Viewer"],
+ hou.paneTabType.DataTree: [["h.pane.datatree"], "Data Tree"],
+ hou.paneTabType.DetailsView: [["h.pane.details"], "Details View"],
+ hou.paneTabType.HandleList: [["h.pane.manip"], "Handle List"],
+ hou.paneTabType.HelpBrowser: [[""], "Help Browser"],
+ hou.paneTabType.IPRViewer: [["h.pane.ipr"], "IPR Viewer"],
+ hou.paneTabType.LightLinker: [["h.pane.linkeditor", "h.pane.linkeditor.sheet", ], "Light Linker"],
+ hou.paneTabType.MaterialPalette: [["h.pane.material"], "Material Palette"],
+ hou.paneTabType.NetworkEditor: [["h.pane.wsheet"], "Network Editor"],
+ hou.paneTabType.OutputViewer: [["h.pane.outputsview"], "Output Viewer"],
+ hou.paneTabType.Parm: [["h.pane.editparms", "h.pane.parms"], "Parameters"],
+ hou.paneTabType.ParmSpreadsheet: [["h.pane.parmsheet"], "Parameter Spreadsheet"],
+ hou.paneTabType.PerformanceMonitor: [["h.pane.perfmon"], "Performance Monitor"],
+ hou.paneTabType.PythonPanel: [["h.py"], "PythonPanel"],
+ hou.paneTabType.PythonShell: [["h.pane.pythonshell", "h.py"], "Python Shell"],
+ hou.paneTabType.SceneViewer: [["h.pane.gview.selmode", "h.pane.gview.state.select"], "Scene Viewer"],
+ hou.paneTabType.TakeList: [["h.pane.take", "h.pane.take.content", "h.pane.take.list"], "Take List"],
+ hou.paneTabType.Textport: [["h.pane.textport"], "Textport"],
+ hou.paneTabType.TreeView: [["tree"], "Tree View"],
+ "playbar": [["h.playbar"], "Playbar"],
+ "shelf": [["h.shelf"], "Shelf"],
+}
+# !SECTION Houdini Translations
+
+# @formatter:off ------------------------------------------------ UI Info
+# SECTION UI Info -------------------------------------------------------
+
+# @formatter:off --------------------------------- SEVERITY
+# NOTE SEVERITY -------------------------------------------
+SEVERITY = {
+ "Message": [hou.severityType.Message, "#FF0000"],
+ "ImportantMessage": [hou.severityType.ImportantMessage, "#FF0000"],
+ "Warning": [hou.severityType.Warning, "#FF0000"],
+ "Error": [hou.severityType.Error, "FF0000"],
+ "Fatal": [hou.severityType.Fatal, "#FF0000"],
+}
+
+# DOP_pyrosolver
+# MISC_database
+# MISC_python
+# MISC_rename
+# NETVIEW_64bit_badge # bug
+# NETVIEW_comment_badge
+# NETVIEW_debug
+# NETVIEW_info_button
+# NETVIEW_message_badge
+# NETVIEW_image_link
+# NETVIEW_image_link_located
+# BUTTONS_resizegrip_se -------- Resize
+# BUTTONS_tree
+# COMMON_opencolorio COP2_colorwheel - Nice color things
+
+# vop_terminals_connected
+# vop_terminals_collapsed
+
+# @formatter:off ------------------------------------ Icons
+# NOTE Icons ----------------------------------------------
+ICON_SIZE = hou.ui.scaledSize(32)
+EDIT_ICON_SIZE = hou.ui.scaledSize(28)
+
+PATH = os.path.join(script_path, "images")
+root = PATH.replace("\\", "/")
+
+ABOUT_ICON1 = hou.ui.createQtIcon(
+ 'NETVIEW_info_button',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+BUG_ICON = hou.ui.createQtIcon(
+ 'NETVIEW_64bit_badge',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+COLLAPSE_ALL_ICON = hou.ui.createQtIcon(
+ (root + "/collapse_all.png"),
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+COLLAPSE_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_collapse_left',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+COLOR_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_chooser_color',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+DOWN_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_down',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+EXPAND_ALL_ICON = hou.ui.createQtIcon(
+ (root + "/expand_all.png"),
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+EXPAND_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_expand_right',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+FILE_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_folder',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+HELP_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_help',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+INFO_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_info',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+# BUTTONS_pinned
+PIN_IN_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_pinned',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+PIN_OUT_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_pin_out_mono',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+RESIZEL_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_resizegrip_se',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+SEARCH_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_search',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+SETTINGS_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_gear',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+UP_ICON = hou.ui.createQtIcon(
+ 'BUTTONS_up',
+ EDIT_ICON_SIZE,
+ EDIT_ICON_SIZE
+)
+
+# !SECTION UI Info
+
+
+# SECTION Widget Tools ---------------------------------------------------
+def widgets_at(mainwindow, pos):
+ """Return ALL widgets at `pos`
+ Arguments:
+ pos (QPoint): Position at which to get widgets
+ :param mainwindow:
+ """
+
+ widgets = []
+ widget_at = mainwindow.widgetAt(pos)
+
+ while widget_at:
+ widgets.append(widget_at)
+
+ # Make widget invisible to further enquiries
+ widget_at.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
+ widget_at = mainwindow.widgetAt(pos)
+
+ # Restore attribute
+ for widget in widgets:
+ widget.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents, False)
+
+ return widgets
+
+ # !SECTION Widget Tools
diff --git a/python3.7libs/searcher/widgets/__init__py b/python3.7libs/searcher/widgets/__init__py
new file mode 100644
index 0000000..e69de29
diff --git a/python3.7libs/searcher/widgets/collapsedock.py b/python3.7libs/searcher/widgets/collapsedock.py
new file mode 100644
index 0000000..dde58df
--- /dev/null
+++ b/python3.7libs/searcher/widgets/collapsedock.py
@@ -0,0 +1,112 @@
+from qtpy import QtCore, QtGui, QtWidgets
+
+
+class CollapsibleBox(QtWidgets.QWidget):
+ def __init__(self, title="", parent=None):
+ super(CollapsibleBox, self).__init__(parent)
+
+ self.toggle_button = QtWidgets.QToolButton(
+ text=title, checkable=True, checked=False
+ )
+ self.toggle_button.setStyleSheet("QToolButton { border: none; }")
+ self.toggle_button.setToolButtonStyle(
+ QtCore.Qt.ToolButtonTextBesideIcon
+ )
+ self.toggle_button.setArrowType(QtCore.Qt.RightArrow)
+ self.toggle_button.pressed.connect(self.on_pressed)
+
+ self.toggle_animation = QtCore.QParallelAnimationGroup(self)
+
+ self.content_area = QtWidgets.QScrollArea(
+ maximumHeight=0, minimumHeight=0
+ )
+ self.content_area.setSizePolicy(
+ QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
+ )
+ self.content_area.setFrameShape(QtWidgets.QFrame.NoFrame)
+
+ lay = QtWidgets.QVBoxLayout(self)
+ lay.setSpacing(0)
+ lay.setContentsMargins(0, 0, 0, 0)
+ lay.addWidget(self.toggle_button)
+ lay.addWidget(self.content_area)
+
+ self.toggle_animation.addAnimation(
+ QtCore.QPropertyAnimation(self, b"minimumHeight")
+ )
+ self.toggle_animation.addAnimation(
+ QtCore.QPropertyAnimation(self, b"maximumHeight")
+ )
+ self.toggle_animation.addAnimation(
+ QtCore.QPropertyAnimation(self.content_area, b"maximumHeight")
+ )
+
+ @QtCore.pyqtSlot()
+ def on_pressed(self):
+ checked = self.toggle_button.isChecked()
+ self.toggle_button.setArrowType(
+ QtCore.Qt.DownArrow if not checked else QtCore.Qt.RightArrow
+ )
+ self.toggle_animation.setDirection(
+ QtCore.QAbstractAnimation.Forward
+ if not checked
+ else QtCore.QAbstractAnimation.Backward
+ )
+ self.toggle_animation.start()
+
+ def setContentLayout(self, layout):
+ lay = self.content_area.layout()
+ del lay
+ self.content_area.setLayout(layout)
+ collapsed_height = (
+ self.sizeHint().height() - self.content_area.maximumHeight()
+ )
+ content_height = layout.sizeHint().height()
+ for i in range(self.toggle_animation.animationCount()):
+ animation = self.toggle_animation.animationAt(i)
+ animation.setDuration(200)
+ animation.setStartValue(collapsed_height)
+ animation.setEndValue(collapsed_height + content_height)
+
+ content_animation = self.toggle_animation.animationAt(
+ self.toggle_animation.animationCount() - 1
+ )
+ content_animation.setDuration(200)
+ content_animation.setStartValue(0)
+ content_animation.setEndValue(content_height)
+
+
+if __name__ == "__main__":
+ import sys
+ import random
+
+ app = QtWidgets.QApplication(sys.argv)
+
+ w = QtWidgets.QMainWindow()
+ w.setCentralWidget(QtWidgets.QWidget())
+ dock = QtWidgets.QDockWidget("Collapsible Demo")
+ w.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock)
+ scroll = QtWidgets.QScrollArea()
+ dock.setWidget(scroll)
+ content = QtWidgets.QWidget()
+ scroll.setWidget(content)
+ scroll.setWidgetResizable(True)
+ vlay = QtWidgets.QVBoxLayout(content)
+ for i in range(10):
+ box = CollapsibleBox("Collapsible Box Header-{}".format(i))
+ vlay.addWidget(box)
+ lay = QtWidgets.QVBoxLayout()
+ for j in range(8):
+ label = QtWidgets.QLineEdit("{}".format(j))
+ color = QtGui.QColor(*[random.randint(0, 255) for _ in range(3)])
+ label.setStyleSheet(
+ "background-color: {}; color : white;".format(color.name())
+ )
+ label.setAlignment(QtCore.Qt.AlignCenter)
+ lay.addWidget(label)
+
+ box.setContentLayout(lay)
+ vlay.addStretch()
+ w.resize(640, 480)
+ w.show()
+ sys.exit(app.exec_())
\ No newline at end of file
diff --git a/python_panels/searcher.pypanel b/python_panels/searcher.pypanel
index e02af81..d2cb5bc 100644
--- a/python_panels/searcher.pypanel
+++ b/python_panels/searcher.pypanel
@@ -8,6 +8,7 @@