##// END OF EJS Templates
Fix the default size under MacOSX.
Gael Varoquaux -
Show More
@@ -1,436 +1,436 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A Wx widget to act as a console and input commands.
3 A Wx widget to act as a console and input commands.
4
4
5 This widget deals with prompts and provides an edit buffer
5 This widget deals with prompts and provides an edit buffer
6 restricted to after the last prompt.
6 restricted to after the last prompt.
7 """
7 """
8
8
9 __docformat__ = "restructuredtext en"
9 __docformat__ = "restructuredtext en"
10
10
11 #-------------------------------------------------------------------------------
11 #-------------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
12 # Copyright (C) 2008 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is
14 # Distributed under the terms of the BSD License. The full license is
15 # in the file COPYING, distributed as part of this software.
15 # in the file COPYING, distributed as part of this software.
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17
17
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21
21
22 import wx
22 import wx
23 import wx.stc as stc
23 import wx.stc as stc
24
24
25 from wx.py import editwindow
25 from wx.py import editwindow
26 import time
26 import time
27 import sys
27 import sys
28 LINESEP = '\n'
28 LINESEP = '\n'
29 if sys.platform == 'win32':
29 if sys.platform == 'win32':
30 LINESEP = '\n\r'
30 LINESEP = '\n\r'
31
31
32 import re
32 import re
33
33
34 # FIXME: Need to provide an API for non user-generated display on the
34 # FIXME: Need to provide an API for non user-generated display on the
35 # screen: this should not be editable by the user.
35 # screen: this should not be editable by the user.
36
36
37 _DEFAULT_SIZE = 10
37 _DEFAULT_SIZE = 10
38 if sys.platform == 'darwin':
38 if sys.platform == 'darwin':
39 _DEFAULT_STYLE = 14
39 _DEFAULT_SIZE = 12
40
40
41 _DEFAULT_STYLE = {
41 _DEFAULT_STYLE = {
42 'stdout' : 'fore:#0000FF',
42 'stdout' : 'fore:#0000FF',
43 'stderr' : 'fore:#007f00',
43 'stderr' : 'fore:#007f00',
44 'trace' : 'fore:#FF0000',
44 'trace' : 'fore:#FF0000',
45
45
46 'default' : 'size:%d' % _DEFAULT_SIZE,
46 'default' : 'size:%d' % _DEFAULT_SIZE,
47 'bracegood' : 'fore:#00AA00,back:#000000,bold',
47 'bracegood' : 'fore:#00AA00,back:#000000,bold',
48 'bracebad' : 'fore:#FF0000,back:#000000,bold',
48 'bracebad' : 'fore:#FF0000,back:#000000,bold',
49
49
50 # properties for the various Python lexer styles
50 # properties for the various Python lexer styles
51 'comment' : 'fore:#007F00',
51 'comment' : 'fore:#007F00',
52 'number' : 'fore:#007F7F',
52 'number' : 'fore:#007F7F',
53 'string' : 'fore:#7F007F,italic',
53 'string' : 'fore:#7F007F,italic',
54 'char' : 'fore:#7F007F,italic',
54 'char' : 'fore:#7F007F,italic',
55 'keyword' : 'fore:#00007F,bold',
55 'keyword' : 'fore:#00007F,bold',
56 'triple' : 'fore:#7F0000',
56 'triple' : 'fore:#7F0000',
57 'tripledouble' : 'fore:#7F0000',
57 'tripledouble' : 'fore:#7F0000',
58 'class' : 'fore:#0000FF,bold,underline',
58 'class' : 'fore:#0000FF,bold,underline',
59 'def' : 'fore:#007F7F,bold',
59 'def' : 'fore:#007F7F,bold',
60 'operator' : 'bold'
60 'operator' : 'bold'
61 }
61 }
62
62
63 # new style numbers
63 # new style numbers
64 _STDOUT_STYLE = 15
64 _STDOUT_STYLE = 15
65 _STDERR_STYLE = 16
65 _STDERR_STYLE = 16
66 _TRACE_STYLE = 17
66 _TRACE_STYLE = 17
67
67
68
68
69 # system colors
69 # system colors
70 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
70 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
71
71
72 #-------------------------------------------------------------------------------
72 #-------------------------------------------------------------------------------
73 # The console widget class
73 # The console widget class
74 #-------------------------------------------------------------------------------
74 #-------------------------------------------------------------------------------
75 class ConsoleWidget(editwindow.EditWindow):
75 class ConsoleWidget(editwindow.EditWindow):
76 """ Specialized styled text control view for console-like workflow.
76 """ Specialized styled text control view for console-like workflow.
77
77
78 This widget is mainly interested in dealing with the prompt and
78 This widget is mainly interested in dealing with the prompt and
79 keeping the cursor inside the editing line.
79 keeping the cursor inside the editing line.
80 """
80 """
81
81
82 # This is where the title captured from the ANSI escape sequences are
82 # This is where the title captured from the ANSI escape sequences are
83 # stored.
83 # stored.
84 title = 'Console'
84 title = 'Console'
85
85
86 # The buffer being edited.
86 # The buffer being edited.
87 def _set_input_buffer(self, string):
87 def _set_input_buffer(self, string):
88 self.SetSelection(self.current_prompt_pos, self.GetLength())
88 self.SetSelection(self.current_prompt_pos, self.GetLength())
89 self.ReplaceSelection(string)
89 self.ReplaceSelection(string)
90 self.GotoPos(self.GetLength())
90 self.GotoPos(self.GetLength())
91
91
92 def _get_input_buffer(self):
92 def _get_input_buffer(self):
93 """ Returns the text in current edit buffer.
93 """ Returns the text in current edit buffer.
94 """
94 """
95 input_buffer = self.GetTextRange(self.current_prompt_pos,
95 input_buffer = self.GetTextRange(self.current_prompt_pos,
96 self.GetLength())
96 self.GetLength())
97 input_buffer = input_buffer.replace(LINESEP, '\n')
97 input_buffer = input_buffer.replace(LINESEP, '\n')
98 return input_buffer
98 return input_buffer
99
99
100 input_buffer = property(_get_input_buffer, _set_input_buffer)
100 input_buffer = property(_get_input_buffer, _set_input_buffer)
101
101
102 style = _DEFAULT_STYLE.copy()
102 style = _DEFAULT_STYLE.copy()
103
103
104 # Translation table from ANSI escape sequences to color. Override
104 # Translation table from ANSI escape sequences to color. Override
105 # this to specify your colors.
105 # this to specify your colors.
106 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
106 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
107 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
107 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
108 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
108 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
109 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
109 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
110 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
110 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
111 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
111 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
112 '1;34': [12, 'LIGHT BLUE'], '1;35':
112 '1;34': [12, 'LIGHT BLUE'], '1;35':
113 [13, 'MEDIUM VIOLET RED'],
113 [13, 'MEDIUM VIOLET RED'],
114 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
114 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
115
115
116 # The color of the carret (call _apply_style() after setting)
116 # The color of the carret (call _apply_style() after setting)
117 carret_color = 'BLACK'
117 carret_color = 'BLACK'
118
118
119 # Store the last time a refresh was done
119 # Store the last time a refresh was done
120 _last_refresh_time = 0
120 _last_refresh_time = 0
121
121
122 #--------------------------------------------------------------------------
122 #--------------------------------------------------------------------------
123 # Public API
123 # Public API
124 #--------------------------------------------------------------------------
124 #--------------------------------------------------------------------------
125
125
126 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
126 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
127 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
127 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
128 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
128 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
129 self._configure_scintilla()
129 self._configure_scintilla()
130
130
131 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
131 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
132 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
132 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
133
133
134
134
135 def write(self, text, refresh=True):
135 def write(self, text, refresh=True):
136 """ Write given text to buffer, while translating the ansi escape
136 """ Write given text to buffer, while translating the ansi escape
137 sequences.
137 sequences.
138 """
138 """
139 # XXX: do not put print statements to sys.stdout/sys.stderr in
139 # XXX: do not put print statements to sys.stdout/sys.stderr in
140 # this method, the print statements will call this method, as
140 # this method, the print statements will call this method, as
141 # you will end up with an infinit loop
141 # you will end up with an infinit loop
142 title = self.title_pat.split(text)
142 title = self.title_pat.split(text)
143 if len(title)>1:
143 if len(title)>1:
144 self.title = title[-2]
144 self.title = title[-2]
145
145
146 text = self.title_pat.sub('', text)
146 text = self.title_pat.sub('', text)
147 segments = self.color_pat.split(text)
147 segments = self.color_pat.split(text)
148 segment = segments.pop(0)
148 segment = segments.pop(0)
149 self.GotoPos(self.GetLength())
149 self.GotoPos(self.GetLength())
150 self.StartStyling(self.GetLength(), 0xFF)
150 self.StartStyling(self.GetLength(), 0xFF)
151 try:
151 try:
152 self.AppendText(segment)
152 self.AppendText(segment)
153 except UnicodeDecodeError:
153 except UnicodeDecodeError:
154 # XXX: Do I really want to skip the exception?
154 # XXX: Do I really want to skip the exception?
155 pass
155 pass
156
156
157 if segments:
157 if segments:
158 for ansi_tag, text in zip(segments[::2], segments[1::2]):
158 for ansi_tag, text in zip(segments[::2], segments[1::2]):
159 self.StartStyling(self.GetLength(), 0xFF)
159 self.StartStyling(self.GetLength(), 0xFF)
160 try:
160 try:
161 self.AppendText(text)
161 self.AppendText(text)
162 except UnicodeDecodeError:
162 except UnicodeDecodeError:
163 # XXX: Do I really want to skip the exception?
163 # XXX: Do I really want to skip the exception?
164 pass
164 pass
165
165
166 if ansi_tag not in self.ANSI_STYLES:
166 if ansi_tag not in self.ANSI_STYLES:
167 style = 0
167 style = 0
168 else:
168 else:
169 style = self.ANSI_STYLES[ansi_tag][0]
169 style = self.ANSI_STYLES[ansi_tag][0]
170
170
171 self.SetStyling(len(text), style)
171 self.SetStyling(len(text), style)
172
172
173 self.GotoPos(self.GetLength())
173 self.GotoPos(self.GetLength())
174 if refresh:
174 if refresh:
175 current_time = time.time()
175 current_time = time.time()
176 if current_time - self._last_refresh_time > 0.03:
176 if current_time - self._last_refresh_time > 0.03:
177 if sys.platform == 'win32':
177 if sys.platform == 'win32':
178 wx.SafeYield()
178 wx.SafeYield()
179 else:
179 else:
180 wx.Yield()
180 wx.Yield()
181 # self.ProcessEvent(wx.PaintEvent())
181 # self.ProcessEvent(wx.PaintEvent())
182 self._last_refresh_time = current_time
182 self._last_refresh_time = current_time
183
183
184
184
185 def new_prompt(self, prompt):
185 def new_prompt(self, prompt):
186 """ Prints a prompt at start of line, and move the start of the
186 """ Prints a prompt at start of line, and move the start of the
187 current block there.
187 current block there.
188
188
189 The prompt can be given with ascii escape sequences.
189 The prompt can be given with ascii escape sequences.
190 """
190 """
191 self.write(prompt, refresh=False)
191 self.write(prompt, refresh=False)
192 # now we update our cursor giving end of prompt
192 # now we update our cursor giving end of prompt
193 self.current_prompt_pos = self.GetLength()
193 self.current_prompt_pos = self.GetLength()
194 self.current_prompt_line = self.GetCurrentLine()
194 self.current_prompt_line = self.GetCurrentLine()
195 self.EnsureCaretVisible()
195 self.EnsureCaretVisible()
196
196
197
197
198 def scroll_to_bottom(self):
198 def scroll_to_bottom(self):
199 maxrange = self.GetScrollRange(wx.VERTICAL)
199 maxrange = self.GetScrollRange(wx.VERTICAL)
200 self.ScrollLines(maxrange)
200 self.ScrollLines(maxrange)
201
201
202
202
203 def pop_completion(self, possibilities, offset=0):
203 def pop_completion(self, possibilities, offset=0):
204 """ Pops up an autocompletion menu. Offset is the offset
204 """ Pops up an autocompletion menu. Offset is the offset
205 in characters of the position at which the menu should
205 in characters of the position at which the menu should
206 appear, relativ to the cursor.
206 appear, relativ to the cursor.
207 """
207 """
208 self.AutoCompSetIgnoreCase(False)
208 self.AutoCompSetIgnoreCase(False)
209 self.AutoCompSetAutoHide(False)
209 self.AutoCompSetAutoHide(False)
210 self.AutoCompSetMaxHeight(len(possibilities))
210 self.AutoCompSetMaxHeight(len(possibilities))
211 self.AutoCompShow(offset, " ".join(possibilities))
211 self.AutoCompShow(offset, " ".join(possibilities))
212
212
213
213
214 def get_line_width(self):
214 def get_line_width(self):
215 """ Return the width of the line in characters.
215 """ Return the width of the line in characters.
216 """
216 """
217 return self.GetSize()[0]/self.GetCharWidth()
217 return self.GetSize()[0]/self.GetCharWidth()
218
218
219 #--------------------------------------------------------------------------
219 #--------------------------------------------------------------------------
220 # EditWindow API
220 # EditWindow API
221 #--------------------------------------------------------------------------
221 #--------------------------------------------------------------------------
222
222
223 def OnUpdateUI(self, event):
223 def OnUpdateUI(self, event):
224 """ Override the OnUpdateUI of the EditWindow class, to prevent
224 """ Override the OnUpdateUI of the EditWindow class, to prevent
225 syntax highlighting both for faster redraw, and for more
225 syntax highlighting both for faster redraw, and for more
226 consistent look and feel.
226 consistent look and feel.
227 """
227 """
228
228
229 #--------------------------------------------------------------------------
229 #--------------------------------------------------------------------------
230 # Private API
230 # Private API
231 #--------------------------------------------------------------------------
231 #--------------------------------------------------------------------------
232
232
233 def _apply_style(self):
233 def _apply_style(self):
234 """ Applies the colors for the different text elements and the
234 """ Applies the colors for the different text elements and the
235 carret.
235 carret.
236 """
236 """
237 self.SetCaretForeground(self.carret_color)
237 self.SetCaretForeground(self.carret_color)
238
238
239 #self.StyleClearAll()
239 #self.StyleClearAll()
240 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
240 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
241 "fore:#FF0000,back:#0000FF,bold")
241 "fore:#FF0000,back:#0000FF,bold")
242 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
242 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
243 "fore:#000000,back:#FF0000,bold")
243 "fore:#000000,back:#FF0000,bold")
244
244
245 for style in self.ANSI_STYLES.values():
245 for style in self.ANSI_STYLES.values():
246 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
246 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
247
247
248
248
249 def _configure_scintilla(self):
249 def _configure_scintilla(self):
250 self.SetEOLMode(stc.STC_EOL_LF)
250 self.SetEOLMode(stc.STC_EOL_LF)
251
251
252 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
252 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
253 # the widget
253 # the widget
254 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
254 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
255 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
255 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
256 # Also allow Ctrl Shift "=" for poor non US keyboard users.
256 # Also allow Ctrl Shift "=" for poor non US keyboard users.
257 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
257 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
258 stc.STC_CMD_ZOOMIN)
258 stc.STC_CMD_ZOOMIN)
259
259
260 # Keys: we need to clear some of the keys the that don't play
260 # Keys: we need to clear some of the keys the that don't play
261 # well with a console.
261 # well with a console.
262 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
262 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
263 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
263 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
264 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
264 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
265 self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
265 self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
266
266
267 self.SetEOLMode(stc.STC_EOL_CRLF)
267 self.SetEOLMode(stc.STC_EOL_CRLF)
268 self.SetWrapMode(stc.STC_WRAP_CHAR)
268 self.SetWrapMode(stc.STC_WRAP_CHAR)
269 self.SetWrapMode(stc.STC_WRAP_WORD)
269 self.SetWrapMode(stc.STC_WRAP_WORD)
270 self.SetBufferedDraw(True)
270 self.SetBufferedDraw(True)
271 self.SetUseAntiAliasing(True)
271 self.SetUseAntiAliasing(True)
272 self.SetLayoutCache(stc.STC_CACHE_PAGE)
272 self.SetLayoutCache(stc.STC_CACHE_PAGE)
273 self.SetUndoCollection(False)
273 self.SetUndoCollection(False)
274 self.SetUseTabs(True)
274 self.SetUseTabs(True)
275 self.SetIndent(4)
275 self.SetIndent(4)
276 self.SetTabWidth(4)
276 self.SetTabWidth(4)
277
277
278 # we don't want scintilla's autocompletion to choose
278 # we don't want scintilla's autocompletion to choose
279 # automaticaly out of a single choice list, as we pop it up
279 # automaticaly out of a single choice list, as we pop it up
280 # automaticaly
280 # automaticaly
281 self.AutoCompSetChooseSingle(False)
281 self.AutoCompSetChooseSingle(False)
282 self.AutoCompSetMaxHeight(10)
282 self.AutoCompSetMaxHeight(10)
283 # XXX: this doesn't seem to have an effect.
283 # XXX: this doesn't seem to have an effect.
284 self.AutoCompSetFillUps('\n')
284 self.AutoCompSetFillUps('\n')
285
285
286 self.SetMargins(3, 3) #text is moved away from border with 3px
286 self.SetMargins(3, 3) #text is moved away from border with 3px
287 # Suppressing Scintilla margins
287 # Suppressing Scintilla margins
288 self.SetMarginWidth(0, 0)
288 self.SetMarginWidth(0, 0)
289 self.SetMarginWidth(1, 0)
289 self.SetMarginWidth(1, 0)
290 self.SetMarginWidth(2, 0)
290 self.SetMarginWidth(2, 0)
291
291
292 self._apply_style()
292 self._apply_style()
293
293
294 # Xterm escape sequences
294 # Xterm escape sequences
295 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
295 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
296 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
296 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
297
297
298 #self.SetEdgeMode(stc.STC_EDGE_LINE)
298 #self.SetEdgeMode(stc.STC_EDGE_LINE)
299 #self.SetEdgeColumn(80)
299 #self.SetEdgeColumn(80)
300
300
301 # styles
301 # styles
302 p = self.style
302 p = self.style
303 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
303 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
304 self.StyleClearAll()
304 self.StyleClearAll()
305 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
305 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
306 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
306 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
307 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
307 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
308
308
309 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
309 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
310 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
310 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
311 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
311 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
312 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
312 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
313 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
313 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
314 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
314 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
315 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
315 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
316 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
316 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
317 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
317 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
318 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
318 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
319 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
319 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
320 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
320 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
321 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
321 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
322 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
322 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
323
323
324 def _on_key_down(self, event, skip=True):
324 def _on_key_down(self, event, skip=True):
325 """ Key press callback used for correcting behavior for
325 """ Key press callback used for correcting behavior for
326 console-like interfaces: the cursor is constraint to be after
326 console-like interfaces: the cursor is constraint to be after
327 the last prompt.
327 the last prompt.
328
328
329 Return True if event as been catched.
329 Return True if event as been catched.
330 """
330 """
331 catched = True
331 catched = True
332 # Intercept some specific keys.
332 # Intercept some specific keys.
333 if event.KeyCode == ord('L') and event.ControlDown() :
333 if event.KeyCode == ord('L') and event.ControlDown() :
334 self.scroll_to_bottom()
334 self.scroll_to_bottom()
335 elif event.KeyCode == ord('K') and event.ControlDown() :
335 elif event.KeyCode == ord('K') and event.ControlDown() :
336 self.input_buffer = ''
336 self.input_buffer = ''
337 elif event.KeyCode == ord('A') and event.ControlDown() :
337 elif event.KeyCode == ord('A') and event.ControlDown() :
338 self.GotoPos(self.GetLength())
338 self.GotoPos(self.GetLength())
339 self.SetSelectionStart(self.current_prompt_pos)
339 self.SetSelectionStart(self.current_prompt_pos)
340 self.SetSelectionEnd(self.GetCurrentPos())
340 self.SetSelectionEnd(self.GetCurrentPos())
341 catched = True
341 catched = True
342 elif event.KeyCode == ord('E') and event.ControlDown() :
342 elif event.KeyCode == ord('E') and event.ControlDown() :
343 self.GotoPos(self.GetLength())
343 self.GotoPos(self.GetLength())
344 catched = True
344 catched = True
345 elif event.KeyCode == wx.WXK_PAGEUP:
345 elif event.KeyCode == wx.WXK_PAGEUP:
346 self.ScrollPages(-1)
346 self.ScrollPages(-1)
347 elif event.KeyCode == wx.WXK_PAGEDOWN:
347 elif event.KeyCode == wx.WXK_PAGEDOWN:
348 self.ScrollPages(1)
348 self.ScrollPages(1)
349 elif event.KeyCode == wx.WXK_UP and event.ShiftDown():
349 elif event.KeyCode == wx.WXK_UP and event.ShiftDown():
350 self.ScrollLines(-1)
350 self.ScrollLines(-1)
351 elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown():
351 elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown():
352 self.ScrollLines(1)
352 self.ScrollLines(1)
353 else:
353 else:
354 catched = False
354 catched = False
355
355
356 if self.AutoCompActive():
356 if self.AutoCompActive():
357 event.Skip()
357 event.Skip()
358 else:
358 else:
359 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
359 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
360 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
360 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
361 catched = True
361 catched = True
362 self.CallTipCancel()
362 self.CallTipCancel()
363 self.write('\n', refresh=False)
363 self.write('\n', refresh=False)
364 # Under windows scintilla seems to be doing funny stuff to the
364 # Under windows scintilla seems to be doing funny stuff to the
365 # line returns here, but the getter for input_buffer filters
365 # line returns here, but the getter for input_buffer filters
366 # this out.
366 # this out.
367 if sys.platform == 'win32':
367 if sys.platform == 'win32':
368 self.input_buffer = self.input_buffer
368 self.input_buffer = self.input_buffer
369 self._on_enter()
369 self._on_enter()
370
370
371 elif event.KeyCode == wx.WXK_HOME:
371 elif event.KeyCode == wx.WXK_HOME:
372 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
372 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
373 self.GotoPos(self.current_prompt_pos)
373 self.GotoPos(self.current_prompt_pos)
374 catched = True
374 catched = True
375
375
376 elif event.Modifiers == wx.MOD_SHIFT:
376 elif event.Modifiers == wx.MOD_SHIFT:
377 # FIXME: This behavior is not ideal: if the selection
377 # FIXME: This behavior is not ideal: if the selection
378 # is already started, it will jump.
378 # is already started, it will jump.
379 self.SetSelectionStart(self.current_prompt_pos)
379 self.SetSelectionStart(self.current_prompt_pos)
380 self.SetSelectionEnd(self.GetCurrentPos())
380 self.SetSelectionEnd(self.GetCurrentPos())
381 catched = True
381 catched = True
382
382
383 elif event.KeyCode == wx.WXK_UP:
383 elif event.KeyCode == wx.WXK_UP:
384 if self.GetCurrentLine() > self.current_prompt_line:
384 if self.GetCurrentLine() > self.current_prompt_line:
385 if self.GetCurrentLine() == self.current_prompt_line + 1 \
385 if self.GetCurrentLine() == self.current_prompt_line + 1 \
386 and self.GetColumn(self.GetCurrentPos()) < \
386 and self.GetColumn(self.GetCurrentPos()) < \
387 self.GetColumn(self.current_prompt_pos):
387 self.GetColumn(self.current_prompt_pos):
388 self.GotoPos(self.current_prompt_pos)
388 self.GotoPos(self.current_prompt_pos)
389 else:
389 else:
390 event.Skip()
390 event.Skip()
391 catched = True
391 catched = True
392
392
393 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
393 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
394 if self.GetCurrentPos() > self.current_prompt_pos:
394 if self.GetCurrentPos() > self.current_prompt_pos:
395 event.Skip()
395 event.Skip()
396 catched = True
396 catched = True
397
397
398 if skip and not catched:
398 if skip and not catched:
399 # Put the cursor back in the edit region
399 # Put the cursor back in the edit region
400 if self.GetCurrentPos() < self.current_prompt_pos:
400 if self.GetCurrentPos() < self.current_prompt_pos:
401 self.GotoPos(self.current_prompt_pos)
401 self.GotoPos(self.current_prompt_pos)
402 else:
402 else:
403 event.Skip()
403 event.Skip()
404
404
405 return catched
405 return catched
406
406
407
407
408 def _on_key_up(self, event, skip=True):
408 def _on_key_up(self, event, skip=True):
409 """ If cursor is outside the editing region, put it back.
409 """ If cursor is outside the editing region, put it back.
410 """
410 """
411 event.Skip()
411 event.Skip()
412 if self.GetCurrentPos() < self.current_prompt_pos:
412 if self.GetCurrentPos() < self.current_prompt_pos:
413 self.GotoPos(self.current_prompt_pos)
413 self.GotoPos(self.current_prompt_pos)
414
414
415
415
416
416
417 if __name__ == '__main__':
417 if __name__ == '__main__':
418 # Some simple code to test the console widget.
418 # Some simple code to test the console widget.
419 class MainWindow(wx.Frame):
419 class MainWindow(wx.Frame):
420 def __init__(self, parent, id, title):
420 def __init__(self, parent, id, title):
421 wx.Frame.__init__(self, parent, id, title, size=(300,250))
421 wx.Frame.__init__(self, parent, id, title, size=(300,250))
422 self._sizer = wx.BoxSizer(wx.VERTICAL)
422 self._sizer = wx.BoxSizer(wx.VERTICAL)
423 self.console_widget = ConsoleWidget(self)
423 self.console_widget = ConsoleWidget(self)
424 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
424 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
425 self.SetSizer(self._sizer)
425 self.SetSizer(self._sizer)
426 self.SetAutoLayout(1)
426 self.SetAutoLayout(1)
427 self.Show(True)
427 self.Show(True)
428
428
429 app = wx.PySimpleApp()
429 app = wx.PySimpleApp()
430 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
430 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
431 w.SetSize((780, 460))
431 w.SetSize((780, 460))
432 w.Show()
432 w.Show()
433
433
434 app.MainLoop()
434 app.MainLoop()
435
435
436
436
General Comments 0
You need to be logged in to leave comments. Login now