Skip to content

Commit ef0882c

Browse files
committedJul 9, 2021
Fifth Release
1 parent 287147b commit ef0882c

4 files changed

+588
-55
lines changed
 

‎InstallationGuide.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import W_hotbox, W_hotboxManager
1212

1313
3.a Copy the folder named 'icons' to your .nuke folder. (If you would rather place the icons elsewhere, make sure to follow step 3.b. If you decide to put them in the default location, you can skip step 3.b)
1414

15-
3.b Launch Nuke. Open the Preferences Panel and navigate to the W_hotbox tab. change the path pointing to the icons folder to the folder you placed the icons in step 3.a.
15+
3.b Launch Nuke. Open the Preferences Panel and navigate to the W_hotbox tab. Change the path pointing to the icons folder to the folder you placed the icons in step 3.a. Restart Nuke.
1616

1717
Step 4 is optional. The download ships with a set of buttons ready to use with the hotbox. The hotbox will function fine without those, but the user has to add buttons himself before the hotbox becomes useful. The buttons that ship with this download are easily removed if the user would rather start from scratch himself.
1818

‎W_hotbox.py

+107-41
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#----------------------------------------------------------------------------------------------------------
22
# Wouter Gilsing
33
# woutergilsing@hotmail.com
4-
version = '1.3'
5-
releaseDate = 'Sept 4 2016'
4+
version = '1.4'
5+
releaseDate = 'November 16 2016'
66

77
#----------------------------------------------------------------------------------------------------------
88
#
@@ -44,6 +44,7 @@
4444
import os
4545
import subprocess
4646
import platform
47+
import traceback
4748

4849
import colorsys
4950

@@ -65,16 +66,25 @@ def __init__(self, subMenuMode = False, path = '', name = '', position = ''):
6566
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
6667

6768
masterLayout = QtGui.QVBoxLayout()
69+
6870
self.setLayout(masterLayout)
6971

72+
self.selection = nuke.selectedNodes()
73+
74+
#check whether selection in group
75+
self.groupRoot = 'root'
76+
77+
if len(self.selection) != 0:
78+
nodeRoot = self.selection[0].fullName()
79+
if nodeRoot.count('.') > 0:
80+
self.groupRoot = '.'.join(nodeRoot.split('.')[:-1])
81+
7082
#--------------------------------------------------------------------------------------------------
7183
#main hotbox
7284
#--------------------------------------------------------------------------------------------------
7385

7486
if not subMenuMode:
7587

76-
self.selection = nuke.selectedNodes()
77-
7888
if len(self.selection) > 1:
7989

8090
if len(list(set([i.Class() for i in nuke.selectedNodes()]))) == 1:
@@ -347,7 +357,7 @@ def __init__(self, mode, allItems = ''):
347357
class hotboxCenter(QtGui.QLabel):
348358
'''
349359
Center button of the hotbox.
350-
If the 'color nodes' is set to True in the preferencespanel, the button will take over the color and
360+
If the 'color nodes' is set to True in the preferences panel, the button will take over the color and
351361
name of the current selection. If not, the button will be the same color as the other buttons will
352362
be in their selected state. The text will be read from the _name.json file in the folder.
353363
'''
@@ -508,20 +518,73 @@ def __init__(self, name, function = None):
508518
self.setMouseTracking(True)
509519
self.setFixedWidth(105)
510520
self.setFixedHeight(35)
521+
511522
fontSize = preferencesNode.knob('hotboxFontSize').value()
512523
font = QtGui.QFont(preferencesNode.knob('UIFont').value(), fontSize, QtGui.QFont.Bold)
524+
513525
self.setFont(font)
514526
self.setWordWrap(True)
515527
self.setTextFormat(QtCore.Qt.RichText)
516528

517529
self.setText(name)
518530

519-
520531
self.setAlignment(QtCore.Qt.AlignCenter)
521532

522533
self.selected = False
523534
self.setSelectionStatus()
524535

536+
def invokeButton(self):
537+
'''
538+
Execute script attached to button
539+
'''
540+
with nuke.toNode(hotboxInstance.groupRoot):
541+
try:
542+
exec self.function
543+
except:
544+
self.printError(traceback.format_exc())
545+
546+
def printError(self, error):
547+
548+
fullError = error.splitlines()
549+
550+
lineNumber = 'error determining line'
551+
552+
for index, line in enumerate(reversed(fullError)):
553+
if line.startswith(' File "<'):
554+
555+
for i in line.split(','):
556+
if i.startswith(' line '):
557+
lineNumber = i
558+
559+
index = len(fullError)-index
560+
break
561+
562+
fullError = fullError[index:]
563+
564+
errorDescription = '\n'.join(fullError)
565+
566+
scriptFolder = os.path.dirname(self.filePath)
567+
scriptFolderName = os.path.basename(scriptFolder)
568+
569+
buttonName = [self.text()]
570+
571+
while len(scriptFolderName) == 3 and scriptFolderName.isdigit():
572+
573+
name = open(scriptFolder+'/_name.json').read()
574+
buttonName.insert(0, name)
575+
scriptFolder = os.path.dirname(scriptFolder)
576+
scriptFolderName = os.path.basename(scriptFolder)
577+
578+
for i in range(2):
579+
buttonName.insert(0, os.path.basename(scriptFolder))
580+
scriptFolder = os.path.dirname(scriptFolder)
581+
582+
hotboxError = '\nW_HOTBOX ERROR: %s -%s:\n\n%s'%('/'.join(buttonName),lineNumber,errorDescription)
583+
584+
#print error
585+
print hotboxError
586+
nuke.tprint(hotboxError)
587+
525588
def setSelectionStatus(self, selected = False):
526589
'''
527590
Define the style of the button for different states
@@ -563,11 +626,14 @@ def mouseReleaseEvent(self,event):
563626
if self.selected:
564627
nuke.Undo().name(self.text())
565628
nuke.Undo().begin()
566-
try:
567-
exec self.function
568-
except:
569-
pass
629+
630+
631+
632+
self.invokeButton()
633+
634+
570635
nuke.Undo().end()
636+
571637
return True
572638

573639
#----------------------------------------------------------------------------------------------------------
@@ -838,37 +904,6 @@ def getSelectionColor():
838904

839905
#----------------------------------------------------------------------------------------------------------
840906

841-
def showHotbox(force = False, resetPosition = True):
842-
843-
global hotboxInstance
844-
if force:
845-
hotboxInstance.active = False
846-
hotboxInstance.close()
847-
848-
if resetPosition:
849-
global lastPosition
850-
lastPosition = ''
851-
852-
if hotboxInstance == None or not hotboxInstance.active:
853-
hotboxInstance = hotbox(position = lastPosition)
854-
hotboxInstance.show()
855-
856-
def showHotboxSubMenu(path, name):
857-
global hotboxInstance
858-
hotboxInstance.active = False
859-
if hotboxInstance == None or not hotboxInstance.active:
860-
hotboxInstance = hotbox(True, path, name)
861-
hotboxInstance.show()
862-
863-
def showHotboxManager():
864-
'''
865-
Open the hotbox manager from the hotbox
866-
'''
867-
hotboxInstance.closeHotbox()
868-
W_hotboxManager.showHotboxManager()
869-
870-
#----------------------------------------------------------------------------------------------------------
871-
872907
def revealInBrowser(startFolder = False):
873908
'''
874909
Reveal the hotbox folder in a filebrowser
@@ -909,6 +944,37 @@ def getFileBrowser():
909944

910945
return fileBrowser
911946

947+
#----------------------------------------------------------------------------------------------------------
948+
949+
def showHotbox(force = False, resetPosition = True):
950+
951+
global hotboxInstance
952+
953+
if force:
954+
hotboxInstance.active = False
955+
hotboxInstance.close()
956+
957+
if resetPosition:
958+
global lastPosition
959+
lastPosition = ''
960+
961+
if hotboxInstance == None or not hotboxInstance.active:
962+
hotboxInstance = hotbox(position = lastPosition)
963+
hotboxInstance.show()
964+
965+
def showHotboxSubMenu(path, name):
966+
global hotboxInstance
967+
hotboxInstance.active = False
968+
if hotboxInstance == None or not hotboxInstance.active:
969+
hotboxInstance = hotbox(True, path, name)
970+
hotboxInstance.show()
971+
972+
def showHotboxManager():
973+
'''
974+
Open the hotbox manager from the hotbox
975+
'''
976+
hotboxInstance.closeHotbox()
977+
W_hotboxManager.showHotboxManager()
912978

913979
#----------------------------------------------------------------------------------------------------------
914980

‎W_hotboxManager.py

+480-13
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#----------------------------------------------------------------------------------------------------------
22
# Wouter Gilsing
33
# woutergilsing@hotmail.com
4-
version = '1.3'
5-
releaseDate = 'Sept 4 2016'
4+
version = '1.4'
5+
releaseDate = 'November 16 2016'
66

77
#----------------------------------------------------------------------------------------------------------
88
#
@@ -201,12 +201,14 @@ def __init__(self, path = ''):
201201
self.scriptEditorNameLayout.addWidget(self.scriptEditorNameLabel)
202202
self.scriptEditorNameLayout.addWidget(self.scriptEditorName)
203203

204-
self.scriptEditorScript = QtGui.QPlainTextEdit()
204+
self.scriptEditorScript = scriptEditorWidget()
205205
self.scriptEditorScript.setMinimumHeight(200)
206206
self.scriptEditorScript.setMinimumWidth(500)
207207
self.scriptEditorScript.setReadOnly(True)
208208
self.scriptEditorScript.setStyleSheet('background:#262626')
209209

210+
scriptEditorHighlighter(self.scriptEditorScript.document())
211+
210212
scriptEditorFont = QtGui.QFont()
211213
scriptEditorFont.setFamily("Courier")
212214
scriptEditorFont.setStyleHint(QtGui.QFont.Monospace)
@@ -448,16 +450,19 @@ def loadScriptEditor(self):
448450
openFile = open(self.loadedScript).readlines()
449451
for index, line in enumerate(openFile):
450452
if not line.startswith('#'):
451-
self.scriptEditorScript.setPlainText(''.join(openFile[index+1:]))
453+
text = ''.join(openFile[index+1:]).replace('\t',' '*4)
454+
self.scriptEditorScript.setPlainText(text)
452455
break
453456
self.scriptEditorScript.setReadOnly(False)
454457

458+
455459
else:
456460

457461
#set name
458462
self.scriptEditorName.setText(open(self.loadedScript+'/_name.json').read())
459463
self.scriptEditorScript.setReadOnly(True)
460464
self.scriptEditorScript.setStyleSheet('background:%s'%lockedColor)
465+
self.scriptEditorScript.highlightCurrentLine()
461466
self.scriptEditorScript.clear()
462467

463468
self.scriptEditorName.setReadOnly(False)
@@ -476,8 +481,6 @@ def loadScriptEditor(self):
476481
self.scriptEditorName.setStyleSheet('background:%s'%lockedColor)
477482
self.scriptEditorScript.setStyleSheet('background:%s'%lockedColor)
478483

479-
480-
481484
def importScriptEditor(self):
482485
'''
483486
Set the current content of the script editor by importing an existing file.
@@ -486,7 +489,8 @@ def importScriptEditor(self):
486489
if self.loadedScript != None:
487490

488491
importFile = nuke.getFilename('select file to import','*.py *.json')
489-
self.scriptEditorScript.setPlainText(open(importFile).read())
492+
text = open(importFile).read().replace('\t',' '*4)
493+
self.scriptEditorScript.setPlainText(text)
490494

491495
def saveScriptEditor(self):
492496
'''
@@ -747,9 +751,474 @@ def openAboutDialog(self):
747751
aboutDialogInstance.close()
748752
aboutDialogInstance = aboutDialog()
749753
aboutDialogInstance.show()
754+
#------------------------------------------------------------------------------------------------------
755+
#Script Editor
756+
#------------------------------------------------------------------------------------------------------
757+
758+
class scriptEditorWidget(QtGui.QPlainTextEdit):
759+
'''
760+
Script editor widget.
761+
762+
763+
'''
764+
765+
#Signal that will be emitted when the user has changed the text
766+
userChangedEvent = QtCore.Signal()
767+
768+
def __init__(self):
769+
super(scriptEditorWidget, self).__init__()
770+
771+
#Setup line numbers
772+
self.lineNumberArea = LineNumberArea(self)
773+
self.blockCountChanged.connect(self.updateLineNumberAreaWidth)
774+
self.updateRequest.connect(self.updateLineNumberArea)
775+
self.updateLineNumberAreaWidth()
776+
777+
#highlight line
778+
self.cursorPositionChanged.connect(self.highlightCurrentLine)
779+
780+
#--------------------------------------------------------------------------------------------------
781+
#Line Numbers
782+
783+
#While researching the implementation of line number, I had a look at Nuke's Blinkscript node.
784+
#This node has an excellent C++ editor, built with Qt.
785+
#The source code for that editor can be found here (or in Nuke's installation folder):
786+
#thefoundry.co.uk/products/nuke/developers/100/pythonreference/nukescripts.blinkscripteditor-pysrc.html
787+
#I stripped and modified the useful bits of the line number related parts of the code
788+
#and implemented it in the Hotbox Manager. Credits to theFoundry for writing the blinkscripteditor,
789+
#best example code I could wish for.
790+
#--------------------------------------------------------------------------------------------------
791+
792+
def lineNumberAreaWidth(self):
793+
digits = 1
794+
maxNum = max(1, self.blockCount())
795+
while (maxNum >= 10):
796+
maxNum /= 10
797+
digits += 1
798+
799+
space = 7 + self.fontMetrics().width('9') * digits
800+
return space
801+
802+
def updateLineNumberAreaWidth(self):
803+
self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)
804+
805+
def updateLineNumberArea(self, rect, dy):
806+
807+
if (dy):
808+
self.lineNumberArea.scroll(0, dy)
809+
else:
810+
self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height())
811+
812+
if (rect.contains(self.viewport().rect())):
813+
self.updateLineNumberAreaWidth()
814+
815+
def resizeEvent(self, event):
816+
QtGui.QPlainTextEdit.resizeEvent(self, event)
817+
818+
cr = self.contentsRect()
819+
self.lineNumberArea.setGeometry(QtCore.QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height()))
820+
821+
def lineNumberAreaPaintEvent(self, event):
822+
823+
if self.isReadOnly():
824+
return
825+
826+
painter = QtGui.QPainter(self.lineNumberArea)
827+
painter.fillRect(event.rect(), QtGui.QColor(38, 38, 38))
828+
829+
block = self.firstVisibleBlock()
830+
blockNumber = block.blockNumber()
831+
top = int( self.blockBoundingGeometry(block).translated(self.contentOffset()).top() )
832+
bottom = top + int( self.blockBoundingRect(block).height() )
833+
currentLine = self.document().findBlock(self.textCursor().position()).blockNumber()
834+
835+
painter.setPen( self.palette().color(QtGui.QPalette.Text) )
836+
837+
while (block.isValid() and top <= event.rect().bottom()):
838+
839+
textColor = QtGui.QColor(155, 155, 155)
840+
841+
if blockNumber == currentLine and self.hasFocus():
842+
textColor = QtGui.QColor(255, 170, 0)
843+
844+
painter.setPen(textColor)
845+
846+
847+
number = "%s " % str(blockNumber + 1)
848+
painter.drawText(0, top, self.lineNumberArea.width(), self.fontMetrics().height(), QtCore.Qt.AlignRight, number)
849+
850+
#Move to the next block
851+
block = block.next()
852+
top = bottom
853+
bottom = top + int(self.blockBoundingRect(block).height())
854+
blockNumber += 1
855+
856+
#--------------------------------------------------------------------------------------------------
857+
#Auto indent
858+
#--------------------------------------------------------------------------------------------------
859+
860+
def keyPressEvent(self, event):
861+
'''
862+
Custom actions for specific keystrokes
863+
'''
864+
865+
866+
#if Tab convert to Space
867+
if event.key() == 16777217:
868+
self.indentation('indent')
869+
870+
#if Shift+Tab remove indent
871+
elif event.key() == 16777218:
872+
873+
self.indentation('unindent')
874+
875+
#if BackSpace try to snap to previous indent level
876+
elif event.key() == 16777219:
877+
if not self.unindentBackspace():
878+
QtGui.QPlainTextEdit.keyPressEvent(self, event)
879+
880+
#if enter or return, match indent level
881+
elif event.key() in [16777220 ,16777221]:
882+
#QtGui.QPlainTextEdit.keyPressEvent(self, event)
883+
self.indentNewLine()
884+
else:
885+
QtGui.QPlainTextEdit.keyPressEvent(self, event)
886+
#--------------------------------------------------------------------------------------------------
887+
888+
def getCursorInfo(self):
889+
890+
891+
self.cursor = self.textCursor()
892+
893+
self.firstChar = self.cursor.selectionStart()
894+
self.lastChar = self.cursor.selectionEnd()
895+
896+
self.noSelection = False
897+
if self.firstChar == self.lastChar:
898+
self.noSelection = True
899+
900+
self.originalPosition = self.cursor.position()
901+
self.cursorBlockPos = self.cursor.positionInBlock()
902+
#--------------------------------------------------------------------------------------------------
903+
904+
def unindentBackspace(self):
905+
'''
906+
#snap to previous indent level
907+
'''
908+
self.getCursorInfo()
909+
910+
if not self.noSelection or self.cursorBlockPos == 0:
911+
return False
912+
913+
#check text in front of cursor
914+
textInFront = self.document().findBlock(self.firstChar).text()[:self.cursorBlockPos]
915+
916+
#check whether solely spaces
917+
if textInFront != ' '*self.cursorBlockPos:
918+
return False
919+
920+
#snap to previous indent level
921+
spaces = len(textInFront)
922+
for space in range(spaces - ((spaces -1) /4) * 4 -1):
923+
self.cursor.deletePreviousChar()
924+
925+
def indentNewLine(self):
926+
927+
#in case selection covers multiple line, make it one line first
928+
self.insertPlainText('')
929+
930+
self.getCursorInfo()
931+
932+
#check how many spaces after cursor
933+
text = self.document().findBlock(self.firstChar).text()
750934

935+
textInFront = text[:self.cursorBlockPos]
936+
937+
if len(textInFront) == 0:
938+
self.insertPlainText('\n')
939+
return
940+
941+
indentLevel = 0
942+
for i in textInFront:
943+
if i == ' ':
944+
indentLevel += 1
945+
else:
946+
break
947+
948+
indentLevel /= 4
949+
950+
#find out whether textInFront's last character was a ':'
951+
#if that's the case add another indent.
952+
#ignore any spaces at the end, however also
953+
#make sure textInFront is not just an indent
954+
if textInFront.count(' ') != len(textInFront):
955+
while textInFront[-1] == ' ':
956+
textInFront = textInFront[:-1]
957+
958+
if textInFront[-1] == ':':
959+
indentLevel += 1
960+
961+
#new line
962+
self.insertPlainText('\n')
963+
#match indent
964+
self.insertPlainText(' '*(4*indentLevel))
965+
966+
def indentation(self, mode):
967+
968+
self.getCursorInfo()
969+
970+
#if nothing is selected and mode is set to indent, simply insert as many
971+
#space as needed to reach the next indentation level.
972+
if self.noSelection and mode == 'indent':
973+
974+
remainingSpaces = 4 - (self.cursorBlockPos%4)
975+
self.insertPlainText(' '*remainingSpaces)
976+
return
977+
978+
selectedBlocks = self.findBlocks(self.firstChar, self.lastChar)
979+
beforeBlocks = self.findBlocks(last = self.firstChar -1, exclude = selectedBlocks)
980+
afterBlocks = self.findBlocks(first = self.lastChar + 1, exclude = selectedBlocks)
981+
982+
beforeBlocksText = self.blocks2list(beforeBlocks)
983+
selectedBlocksText = self.blocks2list(selectedBlocks, mode)
984+
afterBlocksText = self.blocks2list(afterBlocks)
985+
986+
combinedText = '\n'.join(beforeBlocksText + selectedBlocksText + afterBlocksText)
987+
988+
#make sure the line count stays the same
989+
originalBlockCount = len(self.toPlainText().split('\n'))
990+
combinedText = '\n'.join(combinedText.split('\n')[:originalBlockCount])
991+
992+
self.clear()
993+
self.setPlainText(combinedText)
994+
995+
if self.noSelection:
996+
self.cursor.setPosition(self.lastChar)
997+
998+
#check whether the the orignal selection was from top to bottom or vice versa
999+
else:
1000+
if self.originalPosition == self.firstChar:
1001+
first = self.lastChar
1002+
last = self.firstChar
1003+
firstBlockSnap = QtGui.QTextCursor.EndOfBlock
1004+
lastBlockSnap = QtGui.QTextCursor.StartOfBlock
1005+
else:
1006+
first = self.firstChar
1007+
last = self.lastChar
1008+
firstBlockSnap = QtGui.QTextCursor.StartOfBlock
1009+
lastBlockSnap = QtGui.QTextCursor.EndOfBlock
1010+
1011+
self.cursor.setPosition(first)
1012+
self.cursor.movePosition(firstBlockSnap,QtGui.QTextCursor.MoveAnchor)
1013+
self.cursor.setPosition(last,QtGui.QTextCursor.KeepAnchor)
1014+
self.cursor.movePosition(lastBlockSnap,QtGui.QTextCursor.KeepAnchor)
1015+
1016+
self.setTextCursor(self.cursor)
1017+
1018+
def findBlocks(self, first = 0, last = None, exclude = []):
1019+
blocks = []
1020+
if last == None:
1021+
last = self.document().characterCount()
1022+
for pos in range(first,last+1):
1023+
block = self.document().findBlock(pos)
1024+
if block not in blocks and block not in exclude:
1025+
blocks.append(block)
1026+
return blocks
1027+
1028+
def blocks2list(self, blocks, mode = None):
1029+
text = []
1030+
for block in blocks:
1031+
blockText = block.text()
1032+
if mode == 'unindent':
1033+
if blockText.startswith(' '*4):
1034+
blockText = blockText[4:]
1035+
self.lastChar -= 4
1036+
elif blockText.startswith('\t'):
1037+
blockText = blockText[1:]
1038+
self.lastChar -= 1
1039+
1040+
elif mode == 'indent':
1041+
blockText = ' '*4 + blockText
1042+
self.lastChar += 4
1043+
1044+
text.append(blockText)
1045+
1046+
return text
1047+
1048+
#--------------------------------------------------------------------------------------------------
1049+
#syntax hightlighting
1050+
#--------------------------------------------------------------------------------------------------
1051+
1052+
def highlightCurrentLine(self):
1053+
'''
1054+
Highlight currently selected line
1055+
'''
1056+
extraSelections = []
1057+
1058+
selection = QtGui.QTextEdit.ExtraSelection()
1059+
1060+
lineColor = QtGui.QColor(88, 88, 88, 255)
1061+
1062+
if not self.hasFocus():
1063+
lineColor = QtGui.QColor(88, 88, 88, 0)
1064+
1065+
selection.format.setBackground(lineColor)
1066+
selection.format.setProperty(QtGui.QTextFormat.FullWidthSelection, True)
1067+
selection.cursor = self.textCursor()
1068+
selection.cursor.clearSelection()
1069+
1070+
extraSelections.append(selection)
1071+
1072+
self.setExtraSelections(extraSelections)
1073+
1074+
class LineNumberArea(QtGui.QWidget):
1075+
def __init__(self, scriptEditor):
1076+
super(LineNumberArea, self).__init__(scriptEditor)
1077+
1078+
self.scriptEditor = scriptEditor
1079+
self.setStyleSheet("text-align: center;")
1080+
1081+
def paintEvent(self, event):
1082+
self.scriptEditor.lineNumberAreaPaintEvent(event)
1083+
return
1084+
1085+
class scriptEditorHighlighter(QtGui.QSyntaxHighlighter):
1086+
'''
1087+
Modified, simplified version of some code found I found when researching:
1088+
wiki.python.org/moin/PyQt/Python%20syntax%20highlighting
1089+
They did an awesome job, so credits to them. I only needed to make some
1090+
modifications to make it fit my needs.
1091+
'''
1092+
1093+
def __init__(self, document):
1094+
1095+
super(scriptEditorHighlighter, self).__init__(document)
1096+
1097+
self.styles = {
1098+
'keyword': self.format([238,117,181],'bold'),
1099+
'string': self.format([242, 136, 135]),
1100+
'comment': self.format([143, 221, 144 ]),
1101+
'numbers': self.format([174, 129, 255])
1102+
}
1103+
1104+
self.keywords = [
1105+
'and', 'assert', 'break', 'class', 'continue', 'def',
1106+
'del', 'elif', 'else', 'except', 'exec', 'finally',
1107+
'for', 'from', 'global', 'if', 'import', 'in',
1108+
'is', 'lambda', 'not', 'or', 'pass', 'print',
1109+
'raise', 'return', 'try', 'while', 'yield'
1110+
]
1111+
1112+
self.operatorKeywords = [
1113+
'=','==', '!=', '<', '<=', '>', '>=',
1114+
'\+', '-', '\*', '/', '//', '\%', '\*\*',
1115+
'\+=', '-=', '\*=', '/=', '\%=',
1116+
'\^', '\|', '\&', '\~', '>>', '<<'
1117+
]
1118+
1119+
self.numbers = ['True', 'False','None']
1120+
1121+
self.tri_single = (QtCore.QRegExp("'''"), 1, self.styles['comment'])
1122+
self.tri_double = (QtCore.QRegExp('"""'), 2, self.styles['comment'])
1123+
1124+
#rules
1125+
rules = []
1126+
1127+
rules += [(r'\b%s\b' % i, 0, self.styles['keyword']) for i in self.keywords]
1128+
rules += [(i, 0, self.styles['keyword']) for i in self.operatorKeywords]
1129+
rules += [(r'\b%s\b' % i, 0, self.styles['numbers']) for i in self.numbers]
1130+
1131+
rules += [
1132+
1133+
# integers
1134+
(r'\b[0-9]+\b', 0, self.styles['numbers']),
1135+
# Double-quoted string, possibly containing escape sequences
1136+
(r'"[^"\\]*(\\.[^"\\]*)*"', 0, self.styles['string']),
1137+
# Single-quoted string, possibly containing escape sequences
1138+
(r"'[^'\\]*(\\.[^'\\]*)*'", 0, self.styles['string']),
1139+
# From '#' until a newline
1140+
(r'#[^\n]*', 0, self.styles['comment']),
1141+
]
1142+
1143+
# Build a QRegExp for each pattern
1144+
self.rules = [(QtCore.QRegExp(pat), index, fmt) for (pat, index, fmt) in rules]
1145+
1146+
def format(self,rgb, style=''):
1147+
'''
1148+
Return a QtGui.QTextCharFormat with the given attributes.
1149+
'''
1150+
1151+
color = QtGui.QColor(*rgb)
1152+
textFormat = QtGui.QTextCharFormat()
1153+
textFormat.setForeground(color)
1154+
1155+
if 'bold' in style:
1156+
textFormat.setFontWeight(QtGui.QFont.Bold)
1157+
if 'italic' in style:
1158+
textFormat.setFontItalic(True)
1159+
1160+
return textFormat
1161+
1162+
def highlightBlock(self, text):
1163+
'''
1164+
Apply syntax highlighting to the given block of text.
1165+
'''
1166+
# Do other syntax formatting
1167+
for expression, nth, format in self.rules:
1168+
index = expression.indexIn(text, 0)
1169+
1170+
while index >= 0:
1171+
# We actually want the index of the nth match
1172+
index = expression.pos(nth)
1173+
length = len(expression.cap(nth))
1174+
self.setFormat(index, length, format)
1175+
index = expression.indexIn(text, index + length)
1176+
1177+
self.setCurrentBlockState(0)
1178+
1179+
# Do multi-line strings
1180+
in_multiline = self.match_multiline(text, *self.tri_single)
1181+
if not in_multiline:
1182+
in_multiline = self.match_multiline(text, *self.tri_double)
1183+
1184+
def match_multiline(self, text, delimiter, in_state, style):
1185+
'''
1186+
Check whether highlighting reuires multiple lines.
1187+
'''
1188+
# If inside triple-single quotes, start at 0
1189+
if self.previousBlockState() == in_state:
1190+
start = 0
1191+
add = 0
1192+
# Otherwise, look for the delimiter on this line
1193+
else:
1194+
start = delimiter.indexIn(text)
1195+
# Move past this match
1196+
add = delimiter.matchedLength()
1197+
1198+
# As long as there's a delimiter match on this line...
1199+
while start >= 0:
1200+
# Look for the ending delimiter
1201+
end = delimiter.indexIn(text, start + add)
1202+
# Ending delimiter on this line?
1203+
if end >= add:
1204+
length = end - start + add + delimiter.matchedLength()
1205+
self.setCurrentBlockState(0)
1206+
# No; multi-line string
1207+
else:
1208+
self.setCurrentBlockState(in_state)
1209+
length = len(text) - start + add
1210+
# Apply formatting
1211+
self.setFormat(start, length, style)
1212+
# Look for the next match
1213+
start = delimiter.indexIn(text, start + length)
1214+
1215+
# Return True if still inside a multi-line string, False otherwise
1216+
if self.currentBlockState() == in_state:
1217+
return True
1218+
else:
1219+
return False
7511220
#------------------------------------------------------------------------------------------------------
752-
#Modified Qt classes
1221+
#Tree View
7531222
#------------------------------------------------------------------------------------------------------
7541223

7551224
class QTreeViewCustom(QtGui.QTreeView):
@@ -1389,7 +1858,6 @@ def enterEvent(self, event):
13891858
def leaveEvent(self,event):
13901859
self.deactivate()
13911860

1392-
13931861
def mouseReleaseEvent(self,event):
13941862

13951863
webbrowser.open(self.link)
@@ -1400,17 +1868,17 @@ def mouseReleaseEvent(self,event):
14001868

14011869
class fileHeader():
14021870
def __init__(self,name):
1403-
self.text = '\n'.join(['#----------------------------------------------------------------------------------------------------------',
1871+
dividerLine = '-'*106
1872+
self.text = '\n'.join(['#%s'%dividerLine,
14041873
'#',
14051874
'# AUTOMATICALLY GENERATED FILE TO BE USED BY W_HOTBOX',
14061875
'#',
14071876
'# NAME: %s'%name,
14081877
'#',
1409-
'#----------------------------------------------------------------------------------------------------------\n\n'])
1878+
'#%s\n\n'%dividerLine])
14101879
def getHeader(self):
14111880
return self.text
14121881

1413-
#------------------------------------------------------------------------------------------------------
14141882

14151883
#------------------------------------------------------------------------------------------------------
14161884
#Repair
@@ -1562,7 +2030,6 @@ def clearHotboxManager(sections = ['Single','Multiple','All']):
15622030
except:
15632031
pass
15642032

1565-
15662033
#--------------------------------------------------------------------------------------------------
15672034

15682035
hotboxManagerInstance = None
Binary file not shown.

0 commit comments

Comments
 (0)
Please sign in to comment.