console.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. """
  2. Simple console widget for rocket
  3. """
  4. import sys, os.path
  5. # workaround: https://www.panda3d.org/forums/viewtopic.php?t=10062&p=99697#p99054
  6. #from panda3d import rocket
  7. import _rocketcore as rocket
  8. from panda3d.rocket import RocketRegion, RocketInputHandler
  9. class Console(object):
  10. def __init__(self, base, context, cols, rows, commandHandler):
  11. self.base = base
  12. self.context = context
  13. self.loadFonts()
  14. self.cols = cols
  15. self.rows = rows
  16. self.commandHandler = commandHandler
  17. self.setupConsole()
  18. self.allowEditing(True)
  19. def getTextContainer(self):
  20. return self.textEl
  21. def setPrompt(self, prompt):
  22. self.consolePrompt = prompt
  23. def allowEditing(self, editMode):
  24. self.editMode = editMode
  25. if editMode:
  26. self.input = ""
  27. if not self.lastLine:
  28. self.addLine("")
  29. self.newEditLine()
  30. def loadFonts(self):
  31. rocket.LoadFontFace("Perfect DOS VGA 437.ttf")
  32. def setupConsole(self):
  33. self.document = self.context.LoadDocument("console.rml")
  34. if not self.document:
  35. raise AssertionError("did not find console.rml")
  36. el = self.document.GetElementById('content')
  37. self.textEl = el
  38. # roundabout way of accessing the current object through rocket event...
  39. # add attribute to let Rocket know about the receiver
  40. self.context.console = self
  41. # then reference through the string format (dunno how else to get the event...)
  42. self.document.AddEventListener(
  43. 'keydown', 'document.context.console.handleKeyDown(event)', True)
  44. self.document.AddEventListener(
  45. 'textinput', 'document.context.console.handleTextInput(event)', True)
  46. self.consolePrompt = "C:\\>"
  47. self.input = ""
  48. self.lastLine = None
  49. self.blinkState = False
  50. self.queueBlinkCursor()
  51. self.document.Show()
  52. def queueBlinkCursor(self):
  53. self.base.taskMgr.doMethodLater(0.2, self.blinkCursor, 'blinkCursor')
  54. def blinkCursor(self, task):
  55. self.blinkState = not self.blinkState
  56. if self.editMode:
  57. self.updateEditLine(self.input)
  58. self.queueBlinkCursor()
  59. def escape(self, text):
  60. return text. \
  61. replace('<', '&lt;'). \
  62. replace('>', '&gt;'). \
  63. replace('"', '&quot;')
  64. def addLine(self, text):
  65. curKids = list(self.textEl.child_nodes)
  66. while len(curKids) >= self.rows:
  67. self.textEl.RemoveChild(curKids[0])
  68. curKids = curKids[1:]
  69. line = self.document.CreateTextNode(self.escape(text) + '\n')
  70. self.textEl.AppendChild(line)
  71. self.lastLine = line
  72. def addLines(self, lines):
  73. for line in lines:
  74. self.addLine(line)
  75. def updateEditLine(self, newInput=''):
  76. newText = self.consolePrompt + newInput
  77. self.lastLine.text = self.escape(newText) + (self.blinkState and '_' or '')
  78. self.input = newInput
  79. def scroll(self):
  80. self.blinkState = False
  81. self.updateEditLine(self.input + '\n')
  82. def handleKeyDown(self, event):
  83. """
  84. Handle control keys
  85. """
  86. keyId = event.parameters['key_identifier']
  87. if not self.editMode:
  88. if keyId == rocket.key_identifier.PAUSE:
  89. if event.parameters['ctrl_key']:
  90. self.commandHandler(None)
  91. return
  92. if keyId == rocket.key_identifier.RETURN:
  93. # emit line without cursor
  94. self.scroll()
  95. # handle command
  96. self.commandHandler(self.input)
  97. if self.editMode:
  98. # start with new "command"
  99. self.addLine(self.consolePrompt)
  100. self.updateEditLine("")
  101. elif keyId == rocket.key_identifier.BACK:
  102. self.updateEditLine(self.input[0:-1])
  103. def handleTextInput(self, event):
  104. if not self.editMode:
  105. return
  106. # handle normal text character
  107. data = event.parameters['data']
  108. if 32 <= data < 128:
  109. self.updateEditLine(self.input + chr(data))
  110. def newEditLine(self):
  111. self.addLine("")
  112. self.updateEditLine()
  113. def cls(self):
  114. curKids = list(self.textEl.child_nodes)
  115. for kid in curKids:
  116. self.textEl.RemoveChild(kid)