~facundo/enjuewemela/trunk

« back to all changes in this revision

Viewing changes to cocos/layer/python_interpreter.py

  • Committer: facundo at com
  • Date: 2011-05-14 18:13:25 UTC
  • mfrom: (67.1.4 v3rel)
  • Revision ID: facundo@taniquetil.com.ar-20110514181325-614h8kjz32w5cmoy
Refactor back

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#
2
 
# Python Interpreter
3
 
# 95% of the code from 'Bruce: the presentation tool' by Richard Jones
4
 
# http://code.google.com/p/bruce-tpt/
5
 
#
6
 
#
7
 
 
8
 
__docformat__ = 'restructuredtext'
9
 
 
10
 
import sys
11
 
import os
12
 
import code
13
 
 
14
 
import pyglet
15
 
from pyglet import graphics
16
 
from pyglet import text
17
 
from pyglet.text import caret, document, layout
18
 
 
19
 
import cocos
20
 
from cocos.director import director
21
 
from base_layers import Layer
22
 
from util_layers import ColorLayer
23
 
 
24
 
__all__ = ['PythonInterpreterLayer']
25
 
 
26
 
class Output:
27
 
    def __init__(self, display, realstdout):
28
 
        self.out = display
29
 
        self.realstdout = realstdout
30
 
        self.data = ''
31
 
 
32
 
    def write(self, data):
33
 
        self.out(data)
34
 
 
35
 
class MyInterpreter(code.InteractiveInterpreter):
36
 
    def __init__(self, locals, display):
37
 
        self.write = display
38
 
        code.InteractiveInterpreter.__init__(self, locals=locals)
39
 
 
40
 
    def execute(self, input):
41
 
        old_stdout = sys.stdout
42
 
        sys.stdout = Output(self.write, old_stdout)
43
 
        more = self.runsource(input)
44
 
        sys.stdout = old_stdout
45
 
        return more
46
 
 
47
 
class PythonInterpreterLayer(ColorLayer):
48
 
    '''Runs an interactive Python interpreter as a child `Layer` of the current `Scene`.
49
 
    '''
50
 
 
51
 
    cfg = {'code.font_name':'Arial',
52
 
            'code.font_size':12,
53
 
            'code.color':(255,255,255,255),
54
 
            'caret.color':(255,255,255),
55
 
            }
56
 
 
57
 
    name = 'py'
58
 
 
59
 
    prompt = ">>> "             #: python prompt
60
 
    prompt_more = "... "        #: python 'more' prompt
61
 
    doing_more = False
62
 
 
63
 
    is_event_handler = True     #: enable pyglet's events
64
 
 
65
 
    def __init__(self):
66
 
        super(PythonInterpreterLayer, self).__init__( 32,32,32,192 )
67
 
 
68
 
        self.content = self.prompt
69
 
        local_vars = director.interpreter_locals
70
 
        local_vars["self"] = self
71
 
        self.interpreter = MyInterpreter(
72
 
                local_vars, self._write)
73
 
 
74
 
        self.current_input = []
75
 
 
76
 
        self.history = ['']
77
 
        self.history_pos = 0
78
 
 
79
 
 
80
 
    def on_enter(self):
81
 
        super(PythonInterpreterLayer, self).on_enter()
82
 
 
83
 
        vw,vh = cocos.director.director.get_window_size()
84
 
 
85
 
        # format the code
86
 
        self.document = document.FormattedDocument(self.content)
87
 
        self.document.set_style(0, len(self.document.text), {
88
 
            'font_name': self.cfg['code.font_name'],
89
 
            'font_size': self.cfg['code.font_size'],
90
 
            'color': self.cfg['code.color'],
91
 
        })
92
 
 
93
 
        self.batch = graphics.Batch()
94
 
 
95
 
        # generate the document
96
 
        self.layout = layout.IncrementalTextLayout(self.document,
97
 
            vw, vh, multiline=True, batch=self.batch)
98
 
        self.layout.anchor_y= 'top'
99
 
 
100
 
        self.caret = caret.Caret(self.layout, color=self.cfg['caret.color'] )
101
 
        self.caret.on_activate()
102
 
 
103
 
        self.on_resize(vw, vh)
104
 
 
105
 
        self.start_of_line = len(self.document.text)
106
 
 
107
 
    def on_resize(self, x, y):
108
 
        vw, vh = director.get_window_size()
109
 
        self.layout.begin_update()
110
 
        self.layout.height = vh
111
 
        self.layout.x = 2
112
 
        self.layout.width = vw - 4
113
 
        self.layout.y = vh
114
 
        self.layout.end_update()
115
 
 
116
 
        # XXX: hack
117
 
        x,y = director.window.width, director.window.height
118
 
        self.layout.top_group._scissor_width=x-4
119
 
 
120
 
        self.caret.position = len(self.document.text)
121
 
 
122
 
    def on_exit(self):
123
 
        super(PythonInterpreterLayer, self).on_exit()
124
 
        self.content = self.document.text
125
 
        self.document = None
126
 
        self.layout = None
127
 
        self.batch = None
128
 
        self.caret = None
129
 
 
130
 
    def on_key_press(self, symbol, modifiers):
131
 
        if symbol == pyglet.window.key.TAB:
132
 
            return self.caret.on_text('\t')
133
 
        elif symbol in (pyglet.window.key.ENTER, pyglet.window.key.NUM_ENTER):
134
 
            # write the newline
135
 
            self._write('\n')
136
 
 
137
 
            line = self.document.text[self.start_of_line:]
138
 
            if line.strip() == 'help()':
139
 
                line = 'print "help() not supported, sorry!"'
140
 
            self.current_input.append(line)
141
 
            self.history_pos = len(self.history)
142
 
            if line.strip():
143
 
                self.history[self.history_pos-1] = line.strip()
144
 
                self.history.append('')
145
 
 
146
 
            more = False
147
 
            if not self.doing_more:
148
 
                more = self.interpreter.execute('\n'.join(self.current_input))
149
 
 
150
 
            if self.doing_more and not line.strip():
151
 
                self.doing_more = False
152
 
                self.interpreter.execute('\n'.join(self.current_input))
153
 
 
154
 
            more = more or self.doing_more
155
 
            if not more:
156
 
                self.current_input = []
157
 
                self._write(self.prompt)
158
 
            else:
159
 
                self.doing_more = True
160
 
                self._write(self.prompt_more)
161
 
            self.start_of_line = len(self.document.text)
162
 
            self.caret.position = len(self.document.text)
163
 
        elif symbol == pyglet.window.key.SPACE:
164
 
            pass
165
 
        else:
166
 
            return pyglet.event.EVENT_UNHANDLED
167
 
        return pyglet.event.EVENT_HANDLED
168
 
 
169
 
    def on_text(self, symbol):
170
 
        # squash carriage return - we already handle them above
171
 
        if symbol == '\r':
172
 
            return pyglet.event.EVENT_HANDLED
173
 
 
174
 
        self._scroll_to_bottom()
175
 
        return self.caret.on_text(symbol)
176
 
 
177
 
    def on_text_motion(self, motion):
178
 
        at_sol = self.caret.position == self.start_of_line
179
 
 
180
 
        if motion == pyglet.window.key.MOTION_UP:
181
 
            # move backward in history, storing the current line of input
182
 
            # if we're at the very end of time
183
 
            line = self.document.text[self.start_of_line:]
184
 
            if self.history_pos == len(self.history)-1:
185
 
                self.history[self.history_pos] = line
186
 
            self.history_pos = max(0, self.history_pos-1)
187
 
            self.document.delete_text(self.start_of_line,
188
 
                len(self.document.text))
189
 
            self._write(self.history[self.history_pos])
190
 
            self.caret.position = len(self.document.text)
191
 
        elif motion == pyglet.window.key.MOTION_DOWN:
192
 
            # move forward in the history
193
 
            self.history_pos = min(len(self.history)-1, self.history_pos+1)
194
 
            self.document.delete_text(self.start_of_line,
195
 
                len(self.document.text))
196
 
            self._write(self.history[self.history_pos])
197
 
            self.caret.position = len(self.document.text)
198
 
        elif motion == pyglet.window.key.MOTION_BACKSPACE:
199
 
            # can't delete the prompt
200
 
            if not at_sol:
201
 
                return self.caret.on_text_motion(motion)
202
 
        elif motion == pyglet.window.key.MOTION_LEFT:
203
 
            # can't move back beyond start of line
204
 
            if not at_sol:
205
 
                return self.caret.on_text_motion(motion)
206
 
        elif motion == pyglet.window.key.MOTION_PREVIOUS_WORD:
207
 
            # can't move back word beyond start of line
208
 
            if not at_sol:
209
 
                return self.caret.on_text_motion(motion)
210
 
        else:
211
 
            return self.caret.on_text_motion(motion)
212
 
        return pyglet.event.EVENT_HANDLED
213
 
 
214
 
    def _write(self, s):
215
 
        self.document.insert_text(len(self.document.text), s, {
216
 
            'font_name': self.cfg['code.font_name'],
217
 
            'font_size': self.cfg['code.font_size'],
218
 
            'color': self.cfg['code.color'],
219
 
        })
220
 
        self._scroll_to_bottom()
221
 
 
222
 
    def _scroll_to_bottom(self):
223
 
        # on key press always move the view to the bottom of the screen
224
 
        if self.layout.height < self.layout.content_height:
225
 
            self.layout.anchor_y= 'bottom'
226
 
            self.layout.y = 0
227
 
            self.layout.view_y = 0
228
 
        if self.caret.position < self.start_of_line:
229
 
            self.caret.position = len(self.document.text)
230
 
 
231
 
    def draw(self):
232
 
        super( PythonInterpreterLayer, self).draw()
233
 
        self.batch.draw()