-
Notifications
You must be signed in to change notification settings - Fork 17
/
window.py
executable file
·142 lines (111 loc) · 4.94 KB
/
window.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#
# This file is part of The Principles of Modern Game AI.
# Copyright (c) 2015, AiGameDev.com KG.
#
import nuclai.bootstrap # Demonstration specific setup.
import vispy.scene # Canvas & visuals for rendering.
import vispy.util.event # Events and observer support.
CONSOLE_PREFIX = '> '
CONSOLE_LINEHEIGHT = 40.0
CONSOLE_LINEOFFSET = 16.0
CONSOLE_MARGIN = 16.0
class TextEvent(vispy.util.event.Event):
"""Simple data-structure to store a text string, as processed by the terminal window.
"""
def __init__(self, text):
super(TextEvent, self).__init__('text_event')
self.text = text
class TerminalWindow(object):
"""Creates and manages a window used for terminal input. You can setup notifications via
`self.events` that emits notifications for user inputs and user commands.
"""
def __init__(self):
"""Constructor sets up events, creates a canvas and data for processing input.
"""
self.events = vispy.util.event.EmitterGroup(
user_input=TextEvent,
user_command=TextEvent)
self._create_canvas()
self._create_terminal()
def _create_canvas(self):
"""Initialize the Vispy scene and a canvas, connect up the events to this object.
"""
self.canvas = vispy.scene.SceneCanvas(
title='HAL9000 Terminal - nucl.ai Courses',
size=(1280, 720),
bgcolor='#F0F0F0',
show=False,
keys='interactive')
self.widget = self.canvas.central_widget
self.widget.set_transform('matrix')
self.widget.transform.translate((0.0, -CONSOLE_LINEOFFSET))
vispy.scene.visuals.GridLines(parent=self.widget, scale=(0.0, 15.984/CONSOLE_LINEHEIGHT))
self.canvas.show(visible=True)
self.canvas.events.mouse_press() # HACK: Layout workaround for bug in Vispy 0.5.0.
self.old_size = self.canvas.size
self.canvas.events.resize.connect(self.on_resize)
self.canvas.events.key_press.connect(self.on_key_press)
def _create_terminal(self):
"""Setup everything that's necessary for processing key events and the text.
"""
self.text_buffer = ''
self.entry_offset = CONSOLE_LINEOFFSET - CONSOLE_LINEHEIGHT / 2 + self.canvas.size[1]
self.entry_blink = 0
self.entries = []
self.log(CONSOLE_PREFIX, color='#1463A3')
timer = vispy.app.Timer(interval=1.0 / 3.0)
timer.connect(self.on_blink)
timer.start()
def scroll(self, height):
self.widget.transform.translate((0.0, -height))
def on_resize(self, evt):
self.scroll(self.old_size[1] - evt.size[1])
self.old_size = evt.size
def log(self, text, align='left', color='#1463A3'):
assert align in ('left', 'right', 'center')
if align == 'center':
position = self.canvas.size[0] / 2
elif align == 'left':
position = CONSOLE_MARGIN
else:
position = self.canvas.size[0] - CONSOLE_MARGIN
if text != '':
entry = vispy.scene.visuals.Text(parent=self.widget,
text=text,
face='Questrial',
color=color,
bold=False,
font_size=20,
anchor_x=align,
anchor_y='bottom',
pos=[position, self.entry_offset, 0.0])
self.entries.append(entry)
self.scroll(CONSOLE_LINEHEIGHT)
self.entry_offset += CONSOLE_LINEHEIGHT
self.entries[0].pos[0][1] = self.entry_offset
def show_input(self, text):
self.entries[0].text = CONSOLE_PREFIX + text
self.entries[0].update()
def on_key_press(self, evt):
if evt.text:
self.on_key_char(evt.text)
c = evt.key
if c.name == 'Enter' and self.text_buffer != '':
if self.text_buffer.startswith('/'):
self.events.user_command(TextEvent(self.text_buffer[1:]))
else:
self.log(self.text_buffer, align='left')
self.events.user_input(TextEvent(self.text_buffer))
self.text_buffer = ''
if c.name == 'Backspace':
self.text_buffer = self.text_buffer[:-1]
self.show_input(self.text_buffer)
def on_key_char(self, text):
self.text_buffer += text
self.show_input(self.text_buffer)
def on_blink(self, _):
if (self.entry_blink%2) == 0:
self.show_input(self.text_buffer+'_')
if (self.entry_blink%2) == 1:
self.show_input(self.text_buffer)
self.entry_blink += 1