##// END OF EJS Templates
Update wx frontend.
Gael Varoquaux -
Show More
@@ -0,0 +1,207 b''
1 # encoding: utf-8 -*- test-case-name:
2 # FIXME: Need to add tests.
3 # ipython1.frontend.cocoa.tests.test_cocoa_frontend -*-
4
5 """Classes to provide a Wx frontend to the
6 ipython1.kernel.engineservice.EngineService.
7
8 """
9
10 __docformat__ = "restructuredtext en"
11
12 #-------------------------------------------------------------------------------
13 # Copyright (C) 2008 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-------------------------------------------------------------------------------
18
19 #-------------------------------------------------------------------------------
20 # Imports
21 #-------------------------------------------------------------------------------
22
23
24 import wx
25 from console_widget import ConsoleWidget
26 import re
27
28 import IPython
29 from IPython.kernel.engineservice import EngineService
30 from IPython.frontend.frontendbase import FrontEndBase
31
32 #-------------------------------------------------------------------------------
33 # Classes to implement the Wx frontend
34 #-------------------------------------------------------------------------------
35
36
37
38
39 class IPythonWxController(FrontEndBase, ConsoleWidget):
40
41 output_prompt = \
42 '\n\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
43
44 # Are we entering multi line input?
45 multi_line_input = False
46
47 # The added tab stop to the string. It may, for instance, come from
48 # copy and pasting something with tabs.
49 tab_stop = 0
50 # FIXME: We still have to deal with this.
51
52 #--------------------------------------------------------------------------
53 # Public API
54 #--------------------------------------------------------------------------
55
56 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
57 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
58 *args, **kwds):
59 """ Create Shell instance.
60 """
61 ConsoleWidget.__init__(self, parent, id, pos, size, style)
62 FrontEndBase.__init__(self, engine=EngineService(),
63 )
64
65 # FIXME: Something is wrong with the history, I instanciate it
66 # with an empty cache, but this is not the way to do.
67 self.lines = {}
68
69 # Start the IPython engine
70 self.engine.startService()
71
72 # Capture Character keys
73 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
74
75 #FIXME: print banner.
76 banner = """IPython1 %s -- An enhanced Interactive Python.""" \
77 % IPython.__version__
78
79
80 def appWillTerminate_(self, notification):
81 """appWillTerminate"""
82
83 self.engine.stopService()
84
85
86 def complete(self, token):
87 """Complete token in engine's user_ns
88
89 Parameters
90 ----------
91 token : string
92
93 Result
94 ------
95 Deferred result of
96 IPython.kernel.engineservice.IEngineBase.complete
97 """
98
99 return self.engine.complete(token)
100
101
102 def render_result(self, result):
103 if 'stdout' in result and result['stdout']:
104 self.write('\n' + result['stdout'])
105 if 'display' in result and result['display']:
106 self.write("%s%s\n" % (
107 self.output_prompt % result['number'],
108 result['display']['pprint']
109 ) )
110
111
112 def render_error(self, failure):
113 self.insert_text('\n\n'+str(failure)+'\n\n')
114 return failure
115
116
117 #--------------------------------------------------------------------------
118 # Private API
119 #--------------------------------------------------------------------------
120
121
122 def _on_key_down(self, event, skip=True):
123 """ Capture the character events, let the parent
124 widget handle them, and put our logic afterward.
125 """
126 current_line_number = self.GetCurrentLine()
127 # Capture enter
128 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
129 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
130 self._on_enter()
131 # Up history
132 elif event.KeyCode == wx.WXK_UP and (
133 ( current_line_number == self.current_prompt_line and
134 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
135 or event.ControlDown() ):
136 new_buffer = self.get_history_previous(
137 self.get_current_edit_buffer())
138 if new_buffer is not None:
139 self.replace_current_edit_buffer(new_buffer)
140 # Down history
141 elif event.KeyCode == wx.WXK_DOWN and (
142 ( current_line_number == self.LineCount -1 and
143 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
144 or event.ControlDown() ):
145 new_buffer = self.get_history_next()
146 if new_buffer is not None:
147 self.replace_current_edit_buffer(new_buffer)
148 else:
149 ConsoleWidget._on_key_down(self, event, skip=True)
150
151
152 def _on_enter(self):
153 """ Called when the return key is pressed in a line editing
154 buffer.
155 """
156 current_buffer = self.get_current_edit_buffer()
157 current_buffer = current_buffer.replace('\r\n', '\n')
158 current_buffer = current_buffer.replace('\t', 4*' ')
159 cleaned_buffer = '\n'.join(l.rstrip()
160 for l in current_buffer.split('\n'))
161 if ( not self.multi_line_input
162 or re.findall(r"\n[\t ]*$", cleaned_buffer)):
163 if self.is_complete(cleaned_buffer):
164 self._add_history(None, cleaned_buffer.rstrip())
165 result = self.engine.shell.execute(cleaned_buffer)
166 self.render_result(result)
167 self.new_prompt(self.prompt % (result['number'] + 1))
168 self.multi_line_input = False
169 else:
170 if self.multi_line_input:
171 self.write('\n' + self._get_indent_string(current_buffer))
172 else:
173 self.multi_line_input = True
174 self.write('\n\t')
175 else:
176 self.write('\n'+self._get_indent_string(current_buffer))
177
178
179 def _get_indent_string(self, string):
180 string = string.split('\n')[-1]
181 indent_chars = len(string) - len(string.lstrip())
182 indent_string = '\t'*(indent_chars // 4) + \
183 ' '*(indent_chars % 4)
184
185 return indent_string
186
187
188
189 if __name__ == '__main__':
190 class MainWindow(wx.Frame):
191 def __init__(self, parent, id, title):
192 wx.Frame.__init__(self, parent, id, title, size=(300,250))
193 self._sizer = wx.BoxSizer(wx.VERTICAL)
194 self.shell = IPythonWxController(self)
195 self._sizer.Add(self.shell, 1, wx.EXPAND)
196 self.SetSizer(self._sizer)
197 self.SetAutoLayout(1)
198 self.Show(True)
199
200 app = wx.PySimpleApp()
201 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
202 frame.shell.SetFocus()
203 frame.SetSize((660, 460))
204 self = frame.shell
205
206 app.MainLoop()
207
@@ -1,370 +1,388 b''
1 1 # encoding: utf-8
2 2 """
3 3 A Wx widget to act as a console and input commands.
4 4
5 5 This widget deals with prompts and provides an edit buffer
6 6 restricted to after the last prompt.
7 7 """
8 8
9 9 __docformat__ = "restructuredtext en"
10 10
11 11 #-------------------------------------------------------------------------------
12 12 # Copyright (C) 2008 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is
15 15 # in the file COPYING, distributed as part of this software.
16 16 #-------------------------------------------------------------------------------
17 17
18 18 #-------------------------------------------------------------------------------
19 19 # Imports
20 20 #-------------------------------------------------------------------------------
21 21
22 22 import wx
23 23 import wx.stc as stc
24 24
25 from wx.py import editwindow
26
25 27 import re
26 28
27 29 # FIXME: Need to provide an API for non user-generated display on the
28 30 # screen: this should not be editable by the user.
29 31
32 if wx.Platform == '__WXMSW__':
33 _DEFAULT_SIZE = 80
34 else:
35 _DEFAULT_SIZE = 10
36
37 _DEFAULT_STYLE = {
38 'stdout' : 'fore:#0000FF',
39 'stderr' : 'fore:#007f00',
40 'trace' : 'fore:#FF0000',
41
42 'default' : 'size:%d' % _DEFAULT_SIZE,
43 'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
44 'bracebad' : 'fore:#000000,back:#FF0000,bold',
45
46 # properties for the various Python lexer styles
47 'comment' : 'fore:#007F00',
48 'number' : 'fore:#007F7F',
49 'string' : 'fore:#7F007F,italic',
50 'char' : 'fore:#7F007F,italic',
51 'keyword' : 'fore:#00007F,bold',
52 'triple' : 'fore:#7F0000',
53 'tripledouble': 'fore:#7F0000',
54 'class' : 'fore:#0000FF,bold,underline',
55 'def' : 'fore:#007F7F,bold',
56 'operator' : 'bold',
57
58 }
59
60 # new style numbers
61 _STDOUT_STYLE = 15
62 _STDERR_STYLE = 16
63 _TRACE_STYLE = 17
64
65
30 66 #-------------------------------------------------------------------------------
31 67 # The console widget class
32 68 #-------------------------------------------------------------------------------
33 class ConsoleWidget(stc.StyledTextCtrl):
69 class ConsoleWidget(editwindow.EditWindow):
34 70 """ Specialized styled text control view for console-like workflow.
35 71
36 72 This widget is mainly interested in dealing with the prompt and
37 73 keeping the cursor inside the editing line.
38 74 """
39 75
76 style = _DEFAULT_STYLE.copy()
77
40 78 # Translation table from ANSI escape sequences to color. Override
41 79 # this to specify your colors.
42 80 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
43 81 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
44 82 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
45 83 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
46 84 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
47 85 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
48 86 '1;34': [12, 'LIGHT BLUE'], '1;35':
49 87 [13, 'MEDIUM VIOLET RED'],
50 88 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
51 89
52 90 # The color of the carret (call _apply_style() after setting)
53 91 carret_color = 'BLACK'
54 92
55 93
56 94 #--------------------------------------------------------------------------
57 95 # Public API
58 96 #--------------------------------------------------------------------------
59 97
98 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
99 size=wx.DefaultSize, style=0,
100 autocomplete_mode='IPYTHON'):
101 """ Autocomplete_mode: Can be 'IPYTHON' or 'STC'
102 'IPYTHON' show autocompletion the ipython way
103 'STC" show it scintilla text control way
104 """
105 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
106 self.configure_scintilla()
107
108 # FIXME: we need to retrieve this from the interpreter.
109 self.prompt = \
110 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02%i\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
111 self.new_prompt(self.prompt % 1)
112
113 self.autocomplete_mode = autocomplete_mode
114
115 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
116
117
118 def configure_scintilla(self):
119 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
120 # the widget
121 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
122 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
123 # Also allow Ctrl Shift "=" for poor non US keyboard users.
124 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
125 stc.STC_CMD_ZOOMIN)
126
127 self.CmdKeyAssign(stc.STC_KEY_PRIOR, stc.STC_SCMOD_SHIFT,
128 stc.STC_CMD_PAGEUP)
129
130 self.CmdKeyAssign(stc.STC_KEY_NEXT, stc.STC_SCMOD_SHIFT,
131 stc.STC_CMD_PAGEDOWN)
132
133 # Keys: we need to clear some of the keys the that don't play
134 # well with a console.
135 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
136 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
137 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
138
139
140 self.SetEOLMode(stc.STC_EOL_CRLF)
141 self.SetWrapMode(stc.STC_WRAP_CHAR)
142 self.SetWrapMode(stc.STC_WRAP_WORD)
143 self.SetBufferedDraw(True)
144 self.SetUseAntiAliasing(True)
145 self.SetLayoutCache(stc.STC_CACHE_PAGE)
146 self.SetUndoCollection(False)
147 self.SetUseTabs(True)
148 self.SetIndent(4)
149 self.SetTabWidth(4)
150
151 self.EnsureCaretVisible()
152
153 self.SetMargins(3, 3) #text is moved away from border with 3px
154 # Suppressing Scintilla margins
155 self.SetMarginWidth(0, 0)
156 self.SetMarginWidth(1, 0)
157 self.SetMarginWidth(2, 0)
158
159 self._apply_style()
160
161 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
162
163 #self.SetEdgeMode(stc.STC_EDGE_LINE)
164 #self.SetEdgeColumn(80)
165
166 # styles
167 p = self.style
168 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
169 self.StyleClearAll()
170 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
171 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
172 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
173
174 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
175 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
176 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
177 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
178 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
179 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
180 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
181 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
182 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
183 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
184 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
185 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
186 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
187
188
60 189 def write(self, text):
61 190 """ Write given text to buffer, while translating the ansi escape
62 191 sequences.
63 192 """
64 193 segments = self.color_pat.split(text)
65 194 segment = segments.pop(0)
66 195 self.StartStyling(self.GetLength(), 0xFF)
67 196 self.AppendText(segment)
68 197
69 198 if segments:
70 199 ansi_tags = self.color_pat.findall(text)
71 200
72 201 for tag in ansi_tags:
73 202 i = segments.index(tag)
74 203 self.StartStyling(self.GetLength(), 0xFF)
75 204 self.AppendText(segments[i+1])
76 205
77 206 if tag != '0':
78 207 self.SetStyling(len(segments[i+1]),
79 208 self.ANSI_STYLES[tag][0])
80 209
81 210 segments.pop(i)
82 211
83 212 self.GotoPos(self.GetLength())
84 213
85 214
86 215 def new_prompt(self, prompt):
87 216 """ Prints a prompt at start of line, and move the start of the
88 217 current block there.
89 218
90 219 The prompt can be give with ascii escape sequences.
91 220 """
92 221 self.write(prompt)
93 222 # now we update our cursor giving end of prompt
94 223 self.current_prompt_pos = self.GetLength()
95 224 self.current_prompt_line = self.GetCurrentLine()
96 225
97 autoindent = self.indent * ' '
98 autoindent = autoindent.replace(' ','\t')
99 self.write(autoindent)
100
101 226
102 227 def replace_current_edit_buffer(self, text):
103 228 """ Replace currently entered command line with given text.
104 229 """
105 230 self.SetSelection(self.current_prompt_pos, self.GetLength())
106 231 self.ReplaceSelection(text)
107 232 self.GotoPos(self.GetLength())
108 233
109 234
110 235 def get_current_edit_buffer(self):
111 236 """ Returns the text in current edit buffer.
112 237 """
113 238 return self.GetTextRange(self.current_prompt_pos,
114 239 self.GetLength())
115 240
116 241
117 242 #--------------------------------------------------------------------------
118 243 # Private API
119 244 #--------------------------------------------------------------------------
120 245
121 def __init__(self, parent, pos=wx.DefaultPosition, ID=-1,
122 size=wx.DefaultSize, style=0,
123 autocomplete_mode='IPYTHON'):
124 """ Autocomplete_mode: Can be 'IPYTHON' or 'STC'
125 'IPYTHON' show autocompletion the ipython way
126 'STC" show it scintilla text control way
127 """
128 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
129
130 #------ Scintilla configuration -----------------------------------
131
132 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
133 # the widget
134 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
135 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
136 # Also allow Ctrl Shift "=" for poor non US keyboard users.
137 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
138 stc.STC_CMD_ZOOMIN)
139
140 self.SetEOLMode(stc.STC_EOL_CRLF)
141 self.SetWrapMode(stc.STC_WRAP_CHAR)
142 self.SetWrapMode(stc.STC_WRAP_WORD)
143 self.SetBufferedDraw(True)
144 self.SetUseAntiAliasing(True)
145 self.SetLayoutCache(stc.STC_CACHE_PAGE)
146 self.SetUndoCollection(False)
147 self.SetUseTabs(True)
148 self.SetIndent(4)
149 self.SetTabWidth(4)
150
151 self.EnsureCaretVisible()
152
153 self.SetMargins(3, 3) #text is moved away from border with 3px
154 # Suppressing Scintilla margins
155 self.SetMarginWidth(0, 0)
156 self.SetMarginWidth(1, 0)
157 self.SetMarginWidth(2, 0)
158
159 self._apply_style()
160
161 self.indent = 0
162 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
163
164 # FIXME: we need to retrieve this from the interpreter.
165 self.prompt = \
166 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x026\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
167 self.new_prompt(self.prompt)
168
169 self.autocomplete_mode = autocomplete_mode
170
171 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress)
172
173
174 246 def _apply_style(self):
175 247 """ Applies the colors for the different text elements and the
176 248 carret.
177 249 """
178 # FIXME: We need to do something for the fonts, but this is
179 # clearly not the right option.
180 #we define platform specific fonts
181 # if wx.Platform == '__WXMSW__':
182 # faces = { 'times': 'Times New Roman',
183 # 'mono' : 'Courier New',
184 # 'helv' : 'Arial',
185 # 'other': 'Comic Sans MS',
186 # 'size' : 10,
187 # 'size2': 8,
188 # }
189 # elif wx.Platform == '__WXMAC__':
190 # faces = { 'times': 'Times New Roman',
191 # 'mono' : 'Monaco',
192 # 'helv' : 'Arial',
193 # 'other': 'Comic Sans MS',
194 # 'size' : 10,
195 # 'size2': 8,
196 # }
197 # else:
198 # faces = { 'times': 'Times',
199 # 'mono' : 'Courier',
200 # 'helv' : 'Helvetica',
201 # 'other': 'new century schoolbook',
202 # 'size' : 10,
203 # 'size2': 8,
204 # }
205 # self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
206 # "fore:%s,back:%s,size:%d,face:%s"
207 # % (self.ANSI_STYLES['0;30'][1],
208 # self.background_color,
209 # faces['size'], faces['mono']))
210
211 250 self.SetCaretForeground(self.carret_color)
212 251
213 252 self.StyleClearAll()
214 253 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
215 254 "fore:#FF0000,back:#0000FF,bold")
216 255 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
217 256 "fore:#000000,back:#FF0000,bold")
218 257
219 258 for style in self.ANSI_STYLES.values():
220 259 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
221 260
222 261
223 def removeFromTo(self, from_pos, to_pos):
262 def removeFromTo(self, from_pos, to_pos):
224 263 if from_pos < to_pos:
225 264 self.SetSelection(from_pos, to_pos)
226 265 self.DeleteBack()
227 266
228 267
229 268 def selectFromTo(self, from_pos, to_pos):
230 269 self.SetSelectionStart(from_pos)
231 270 self.SetSelectionEnd(to_pos)
232 271
233 272
234 273 def writeCompletion(self, possibilities):
235 274 if self.autocomplete_mode == 'IPYTHON':
236 275 max_len = len(max(possibilities, key=len))
237 276 max_symbol = ' '*max_len
238 277
239 278 #now we check how much symbol we can put on a line...
240 279 test_buffer = max_symbol + ' '*4
241 280
242 281 allowed_symbols = 80/len(test_buffer)
243 282 if allowed_symbols == 0:
244 283 allowed_symbols = 1
245 284
246 285 pos = 1
247 286 buf = ''
248 287 for symbol in possibilities:
249 288 #buf += symbol+'\n'#*spaces)
250 289 if pos < allowed_symbols:
251 290 spaces = max_len - len(symbol) + 4
252 291 buf += symbol+' '*spaces
253 292 pos += 1
254 293 else:
255 294 buf += symbol+'\n'
256 295 pos = 1
257 296 self.write(buf)
258 297 else:
259 298 possibilities.sort() # Python sorts are case sensitive
260 299 self.AutoCompSetIgnoreCase(False)
261 300 self.AutoCompSetAutoHide(False)
262 301 #let compute the length ot last word
263 302 splitter = [' ', '(', '[', '{']
264 303 last_word = self.get_current_edit_buffer()
265 304 for breaker in splitter:
266 305 last_word = last_word.split(breaker)[-1]
267 306 self.AutoCompShow(len(last_word), " ".join(possibilities))
268 307
308
309 def scroll_to_bottom(self):
310 maxrange = self.GetScrollRange(wx.VERTICAL)
311 self.ScrollLines(maxrange)
312
269 313
270 def _onKeypress(self, event, skip=True):
314 def _on_key_down(self, event, skip=True):
271 315 """ Key press callback used for correcting behavior for
272 316 console-like interfaces: the cursor is constraint to be after
273 317 the last prompt.
274 318
275 319 Return True if event as been catched.
276 320 """
277 321 catched = False
322 if event.KeyCode == ord('L') and event.ControlDown() :
323 skip = False
324 catched = True
325 self.scroll_to_bottom()
326
278 327 if self.AutoCompActive():
279 328 event.Skip()
280 329 else:
281 if event.GetKeyCode() == wx.WXK_HOME:
330 if event.KeyCode == wx.WXK_HOME:
282 331 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
283 332 self.GotoPos(self.current_prompt_pos)
284 333 catched = True
285 334
286 elif event.Modifiers == wx.MOD_SHIFT:
335 elif event.Modifiers in (wx.MOD_SHIFT, wx.MOD_WIN) :
287 336 self.selectFromTo(self.current_prompt_pos,
288 337 self.GetCurrentPos())
289 338 catched = True
290 339
291 elif event.GetKeyCode() == wx.WXK_UP:
340 elif event.KeyCode == wx.WXK_UP:
292 341 if self.GetCurrentLine() > self.current_prompt_line:
293 342 if self.GetCurrentLine() == self.current_prompt_line + 1 \
294 343 and self.GetColumn(self.GetCurrentPos()) < \
295 344 self.GetColumn(self.current_prompt_pos):
296 345 self.GotoPos(self.current_prompt_pos)
297 346 else:
298 347 event.Skip()
299 348 catched = True
300 349
301 elif event.GetKeyCode() in (wx.WXK_LEFT, wx.WXK_BACK):
350 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
302 351 if self.GetCurrentPos() > self.current_prompt_pos:
303 352 event.Skip()
304 353 catched = True
305 354
306 355 if skip and not catched:
307 356 event.Skip()
308 357
309 if event.GetKeyCode() not in (wx.WXK_PAGEUP, wx.WXK_PAGEDOWN)\
358 if event.KeyCode not in (wx.WXK_PAGEUP, wx.WXK_PAGEDOWN)\
310 359 and event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN,
311 360 wx.MOD_SHIFT):
312 361 # If cursor is outside the editing region, put it back.
313 362 if self.GetCurrentPos() < self.current_prompt_pos:
314 363 self.GotoPos(self.current_prompt_pos)
315 364
316 365 return catched
317 366
318 367
319 def OnUpdateUI(self, evt):
320 # check for matching braces
321 braceAtCaret = -1
322 braceOpposite = -1
323 charBefore = None
324 caretPos = self.GetCurrentPos()
325
326 if caretPos > 0:
327 charBefore = self.GetCharAt(caretPos - 1)
328 styleBefore = self.GetStyleAt(caretPos - 1)
329
330 # check before
331 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
332 braceAtCaret = caretPos - 1
333
334 # check after
335 if braceAtCaret < 0:
336 charAfter = self.GetCharAt(caretPos)
337 styleAfter = self.GetStyleAt(caretPos)
338
339 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
340 braceAtCaret = caretPos
341
342 if braceAtCaret >= 0:
343 braceOpposite = self.BraceMatch(braceAtCaret)
344
345 if braceAtCaret != -1 and braceOpposite == -1:
346 self.BraceBadLight(braceAtCaret)
347 else:
348 self.BraceHighlight(braceAtCaret, braceOpposite)
349
350 368
351 369 if __name__ == '__main__':
352 370 # Some simple code to test the console widget.
353 371 class MainWindow(wx.Frame):
354 372 def __init__(self, parent, id, title):
355 373 wx.Frame.__init__(self, parent, id, title, size=(300,250))
356 374 self._sizer = wx.BoxSizer(wx.VERTICAL)
357 375 self.console_widget = ConsoleWidget(self)
358 376 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
359 377 self.SetSizer(self._sizer)
360 378 self.SetAutoLayout(1)
361 379 self.Show(True)
362 380
363 381 app = wx.PySimpleApp()
364 382 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
365 383 w.SetSize((780, 460))
366 384 w.Show()
367 385
368 386 app.MainLoop()
369 387
370 388
General Comments 0
You need to be logged in to leave comments. Login now