]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/py/crust.py
make wxGetKeyState() work for non-modifier keys; corrected some key mappings (patch...
[wxWidgets.git] / wxPython / wx / py / crust.py
1 """Crust combines the shell and filling into one control."""
2
3 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
4 __cvsid__ = "$Id$"
5 __revision__ = "$Revision$"[11:-2]
6
7 import wx
8
9 import os
10 import pprint
11 import re
12 import sys
13
14 import dispatcher
15 import editwindow
16 from filling import Filling
17 import frame
18 from shell import Shell
19 from version import VERSION
20
21
22 class Crust(wx.SplitterWindow):
23 """Crust based on SplitterWindow."""
24
25 name = 'Crust'
26 revision = __revision__
27 sashoffset = 300
28
29 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
30 size=wx.DefaultSize, style=wx.SP_3D|wx.SP_LIVE_UPDATE,
31 name='Crust Window', rootObject=None, rootLabel=None,
32 rootIsNamespace=True, intro='', locals=None,
33 InterpClass=None,
34 startupScript=None, execStartupScript=True,
35 *args, **kwds):
36 """Create Crust instance."""
37 wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
38
39 # Turn off the tab-traversal style that is automatically
40 # turned on by wx.SplitterWindow. We do this because on
41 # Windows the event for Ctrl-Enter is stolen and used as a
42 # navigation key, but the Shell window uses it to insert lines.
43 style = self.GetWindowStyle()
44 self.SetWindowStyle(style & ~wx.TAB_TRAVERSAL)
45
46 self.shell = Shell(parent=self, introText=intro,
47 locals=locals, InterpClass=InterpClass,
48 startupScript=startupScript,
49 execStartupScript=execStartupScript,
50 *args, **kwds)
51 self.editor = self.shell
52 if rootObject is None:
53 rootObject = self.shell.interp.locals
54 self.notebook = wx.Notebook(parent=self, id=-1)
55 self.shell.interp.locals['notebook'] = self.notebook
56 self.filling = Filling(parent=self.notebook,
57 rootObject=rootObject,
58 rootLabel=rootLabel,
59 rootIsNamespace=rootIsNamespace)
60 # Add 'filling' to the interpreter's locals.
61 self.shell.interp.locals['filling'] = self.filling
62 self.notebook.AddPage(page=self.filling, text='Namespace', select=True)
63
64 self.display = Display(parent=self.notebook)
65 self.notebook.AddPage(page=self.display, text='Display')
66 # Add 'pp' (pretty print) to the interpreter's locals.
67 self.shell.interp.locals['pp'] = self.display.setItem
68 self.display.nbTab = self.notebook.GetPageCount()-1
69
70 self.calltip = Calltip(parent=self.notebook)
71 self.notebook.AddPage(page=self.calltip, text='Calltip')
72
73 self.sessionlisting = SessionListing(parent=self.notebook)
74 self.notebook.AddPage(page=self.sessionlisting, text='History')
75
76 self.dispatcherlisting = DispatcherListing(parent=self.notebook)
77 self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher')
78
79 self.SplitHorizontally(self.shell, self.notebook, -self.sashoffset)
80 self.SetMinimumPaneSize(100)
81
82 self.Bind(wx.EVT_SIZE, self.SplitterOnSize)
83 self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged)
84
85
86 def OnChanged(self, event):
87 """update sash offset from the bottom of the window"""
88 self.sashoffset = self.GetSize().height - event.GetSashPosition()
89 event.Skip()
90
91
92 # Make the splitter expand the top window when resized
93 def SplitterOnSize(self, event):
94 splitter = event.GetEventObject()
95 sz = splitter.GetSize()
96 splitter.SetSashPosition(sz.height - self.sashoffset, True)
97 event.Skip()
98
99
100 def LoadSettings(self, config):
101 self.shell.LoadSettings(config)
102 self.filling.LoadSettings(config)
103
104 pos = config.ReadInt('Sash/CrustPos', 400)
105 wx.CallAfter(self.SetSashPosition, pos)
106 def _updateSashPosValue():
107 sz = self.GetSize()
108 self.sashoffset = sz.height - self.GetSashPosition()
109 wx.CallAfter(_updateSashPosValue)
110 zoom = config.ReadInt('View/Zoom/Display', -99)
111 if zoom != -99:
112 self.display.SetZoom(zoom)
113
114
115 def SaveSettings(self, config):
116 self.shell.SaveSettings(config)
117 self.filling.SaveSettings(config)
118
119 config.WriteInt('Sash/CrustPos', self.GetSashPosition())
120 config.WriteInt('View/Zoom/Display', self.display.GetZoom())
121
122
123
124
125
126 class Display(editwindow.EditWindow):
127 """STC used to display an object using Pretty Print."""
128
129 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
130 size=wx.DefaultSize,
131 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER,
132 static=False):
133 """Create Display instance."""
134 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
135 # Configure various defaults and user preferences.
136 self.SetReadOnly(True)
137 self.SetWrapMode(False)
138 if not static:
139 dispatcher.connect(receiver=self.push, signal='Interpreter.push')
140
141 def push(self, command, more):
142 """Receiver for Interpreter.push signal."""
143 self.Refresh()
144
145 def Refresh(self):
146 if not hasattr(self, "item"):
147 return
148 self.SetReadOnly(False)
149 text = pprint.pformat(self.item)
150 self.SetText(text)
151 self.SetReadOnly(True)
152
153 def setItem(self, item):
154 """Set item to pretty print in the notebook Display tab."""
155 self.item = item
156 self.Refresh()
157 if self.GetParent().GetSelection() != self.nbTab:
158 focus = wx.Window.FindFocus()
159 self.GetParent().SetSelection(self.nbTab)
160 wx.CallAfter(focus.SetFocus)
161
162
163 # TODO: Switch this to a editwindow.EditWindow
164 class Calltip(wx.TextCtrl):
165 """Text control containing the most recent shell calltip."""
166
167 def __init__(self, parent=None, id=-1):
168 style = (wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2)
169 wx.TextCtrl.__init__(self, parent, id, style=style)
170 self.SetBackgroundColour(wx.Colour(255, 255, 208))
171 dispatcher.connect(receiver=self.display, signal='Shell.calltip')
172
173 df = self.GetFont()
174 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
175 self.SetFont(font)
176
177 def display(self, calltip):
178 """Receiver for Shell.calltip signal."""
179 ## self.SetValue(calltip) # Caused refresh problem on Windows.
180 self.Clear()
181 self.AppendText(calltip)
182
183
184 # TODO: Switch this to a editwindow.EditWindow
185 class SessionListing(wx.TextCtrl):
186 """Text control containing all commands for session."""
187
188 def __init__(self, parent=None, id=-1):
189 style = (wx.TE_MULTILINE | wx.TE_READONLY |
190 wx.TE_RICH2 | wx.TE_DONTWRAP)
191 wx.TextCtrl.__init__(self, parent, id, style=style)
192 dispatcher.connect(receiver=self.addHistory, signal="Shell.addHistory")
193 dispatcher.connect(receiver=self.clearHistory, signal="Shell.clearHistory")
194 dispatcher.connect(receiver=self.loadHistory, signal="Shell.loadHistory")
195
196 df = self.GetFont()
197 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
198 self.SetFont(font)
199
200 def loadHistory(self, history):
201 # preload the existing history, if any
202 hist = history[:]
203 hist.reverse()
204 self.SetValue('\n'.join(hist) + '\n')
205 self.SetInsertionPointEnd()
206
207 def addHistory(self, command):
208 if command:
209 self.SetInsertionPointEnd()
210 self.AppendText(command + '\n')
211
212 def clearHistory(self):
213 self.SetValue("")
214
215
216 class DispatcherListing(wx.TextCtrl):
217 """Text control containing all dispatches for session."""
218
219 def __init__(self, parent=None, id=-1):
220 style = (wx.TE_MULTILINE | wx.TE_READONLY |
221 wx.TE_RICH2 | wx.TE_DONTWRAP)
222 wx.TextCtrl.__init__(self, parent, id, style=style)
223 dispatcher.connect(receiver=self.spy)
224
225 df = self.GetFont()
226 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
227 self.SetFont(font)
228
229 def spy(self, signal, sender):
230 """Receiver for Any signal from Any sender."""
231 text = '%r from %s' % (signal, sender)
232 self.SetInsertionPointEnd()
233 start, end = self.GetSelection()
234 if start != end:
235 self.SetSelection(0, 0)
236 self.AppendText(text + '\n')
237
238
239
240 class CrustFrame(frame.Frame, frame.ShellFrameMixin):
241 """Frame containing all the PyCrust components."""
242
243 name = 'CrustFrame'
244 revision = __revision__
245
246
247 def __init__(self, parent=None, id=-1, title='PyCrust',
248 pos=wx.DefaultPosition, size=wx.DefaultSize,
249 style=wx.DEFAULT_FRAME_STYLE,
250 rootObject=None, rootLabel=None, rootIsNamespace=True,
251 locals=None, InterpClass=None,
252 config=None, dataDir=None,
253 *args, **kwds):
254 """Create CrustFrame instance."""
255 frame.Frame.__init__(self, parent, id, title, pos, size, style)
256 frame.ShellFrameMixin.__init__(self, config, dataDir)
257
258 if size == wx.DefaultSize:
259 self.SetSize((800, 600))
260
261 intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION
262 self.SetStatusText(intro.replace('\n', ', '))
263 self.crust = Crust(parent=self, intro=intro,
264 rootObject=rootObject,
265 rootLabel=rootLabel,
266 rootIsNamespace=rootIsNamespace,
267 locals=locals,
268 InterpClass=InterpClass,
269 startupScript=self.startupScript,
270 execStartupScript=self.execStartupScript,
271 *args, **kwds)
272 self.shell = self.crust.shell
273
274 # Override the filling so that status messages go to the status bar.
275 self.crust.filling.tree.setStatusText = self.SetStatusText
276
277 # Override the shell so that status messages go to the status bar.
278 self.shell.setStatusText = self.SetStatusText
279
280 self.shell.SetFocus()
281 self.LoadSettings()
282
283
284 def OnClose(self, event):
285 """Event handler for closing."""
286 self.SaveSettings()
287 self.crust.shell.destroy()
288 self.Destroy()
289
290
291 def OnAbout(self, event):
292 """Display an About window."""
293 title = 'About PyCrust'
294 text = 'PyCrust %s\n\n' % VERSION + \
295 'Yet another Python shell, only flakier.\n\n' + \
296 'Half-baked by Patrick K. O\'Brien,\n' + \
297 'the other half is still in the oven.\n\n' + \
298 'Shell Revision: %s\n' % self.shell.revision + \
299 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
300 'Platform: %s\n' % sys.platform + \
301 'Python Version: %s\n' % sys.version.split()[0] + \
302 'wxPython Version: %s\n' % wx.VERSION_STRING + \
303 ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
304 dialog = wx.MessageDialog(self, text, title,
305 wx.OK | wx.ICON_INFORMATION)
306 dialog.ShowModal()
307 dialog.Destroy()
308
309
310 def OnHelp(self, event):
311 """Show a help dialog."""
312 frame.ShellFrameMixin.OnHelp(self, event)
313
314
315 def LoadSettings(self):
316 if self.config is not None:
317 frame.ShellFrameMixin.LoadSettings(self)
318 frame.Frame.LoadSettings(self, self.config)
319 self.crust.LoadSettings(self.config)
320
321
322 def SaveSettings(self, force=False):
323 if self.config is not None:
324 frame.ShellFrameMixin.SaveSettings(self)
325 if self.autoSaveSettings or force:
326 frame.Frame.SaveSettings(self, self.config)
327 self.crust.SaveSettings(self.config)
328
329
330 def DoSaveSettings(self):
331 if self.config is not None:
332 self.SaveSettings(force=True)
333 self.config.Flush()
334
335
336