]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/py/editor.py
Add code to remove the selection (if any) in wxTextCtrl::WriteText for multi-line...
[wxWidgets.git] / wxPython / wx / py / editor.py
CommitLineData
d14a1e28 1"""PyAlaCarte and PyAlaMode editors."""
1fded56b 2
d14a1e28
RD
3__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
4__cvsid__ = "$Id$"
5__revision__ = "$Revision$"[11:-2]
1fded56b 6
d14a1e28
RD
7import wx
8
9from buffer import Buffer
10import crust
11import dispatcher
12import editwindow
13import frame
14from shell import Shell
15import version
16
d14a1e28
RD
17
18class EditorFrame(frame.Frame):
19 """Frame containing one editor."""
20
21 def __init__(self, parent=None, id=-1, title='PyAlaCarte',
22 pos=wx.DefaultPosition, size=(800, 600),
23 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE,
24 filename=None):
25 """Create EditorFrame instance."""
26 frame.Frame.__init__(self, parent, id, title, pos, size, style)
27 self.buffers = {}
28 self.buffer = None # Current buffer.
29 self.editor = None
30 self._defaultText = title + ' - the tastiest Python editor.'
31 self._statusText = self._defaultText
32 self.SetStatusText(self._statusText)
02b800ce 33 self.Bind(wx.EVT_IDLE, self.OnIdle)
d14a1e28
RD
34 self._setup()
35 if filename:
36 self.bufferCreate(filename)
37
38 def _setup(self):
39 """Setup prior to first buffer creation.
40
41 Useful for subclasses."""
42 pass
43
44 def setEditor(self, editor):
45 self.editor = editor
46 self.buffer = self.editor.buffer
47 self.buffers[self.buffer.id] = self.buffer
48
49 def OnAbout(self, event):
50 """Display an About window."""
51 title = 'About PyAlaCarte'
52 text = 'Another fine, flaky program.'
53 dialog = wx.MessageDialog(self, text, title,
54 wx.OK | wx.ICON_INFORMATION)
55 dialog.ShowModal()
56 dialog.Destroy()
57
58 def OnClose(self, event):
59 """Event handler for closing."""
60 for buffer in self.buffers.values():
61 self.buffer = buffer
62 if buffer.hasChanged():
63 cancel = self.bufferSuggestSave()
64 if cancel and event.CanVeto():
65 event.Veto()
66 return
67 self.Destroy()
68
69 def OnIdle(self, event):
70 """Event handler for idle time."""
71 self._updateStatus()
72 if hasattr(self, 'notebook'):
73 self._updateTabText()
74 self._updateTitle()
75 event.Skip()
76
77 def _updateStatus(self):
78 """Show current status information."""
79 if self.editor and hasattr(self.editor, 'getStatus'):
80 status = self.editor.getStatus()
81 text = 'File: %s | Line: %d | Column: %d' % status
82 else:
83 text = self._defaultText
84 if text != self._statusText:
85 self.SetStatusText(text)
86 self._statusText = text
87
88 def _updateTabText(self):
89 """Show current buffer information on notebook tab."""
90## suffix = ' **'
91## notebook = self.notebook
92## selection = notebook.GetSelection()
93## if selection == -1:
94## return
95## text = notebook.GetPageText(selection)
96## window = notebook.GetPage(selection)
97## if window.editor and window.editor.buffer.hasChanged():
98## if text.endswith(suffix):
99## pass
100## else:
101## notebook.SetPageText(selection, text + suffix)
102## else:
103## if text.endswith(suffix):
104## notebook.SetPageText(selection, text[:len(suffix)])
105
106 def _updateTitle(self):
107 """Show current title information."""
108 title = self.GetTitle()
109 if self.bufferHasChanged():
110 if title.startswith('* '):
111 pass
112 else:
113 self.SetTitle('* ' + title)
114 else:
115 if title.startswith('* '):
116 self.SetTitle(title[2:])
117
118 def hasBuffer(self):
119 """Return True if there is a current buffer."""
120 if self.buffer:
121 return True
122 else:
123 return False
124
125 def bufferClose(self):
126 """Close buffer."""
127 if self.bufferHasChanged():
128 cancel = self.bufferSuggestSave()
129 if cancel:
130 return cancel
131 self.bufferDestroy()
132 cancel = False
133 return cancel
134
135 def bufferCreate(self, filename=None):
136 """Create new buffer."""
137 self.bufferDestroy()
138 buffer = Buffer()
139 self.panel = panel = wx.Panel(parent=self, id=-1)
02b800ce 140 panel.Bind (wx.EVT_ERASE_BACKGROUND, lambda x: x)
d14a1e28
RD
141 editor = Editor(parent=panel)
142 panel.editor = editor
143 sizer = wx.BoxSizer(wx.VERTICAL)
144 sizer.Add(editor.window, 1, wx.EXPAND)
145 panel.SetSizer(sizer)
146 panel.SetAutoLayout(True)
147 sizer.Layout()
148 buffer.addEditor(editor)
149 buffer.open(filename)
150 self.setEditor(editor)
151 self.editor.setFocus()
152 self.SendSizeEvent()
153
154
155 def bufferDestroy(self):
156 """Destroy the current buffer."""
157 if self.buffer:
158 for editor in self.buffer.editors.values():
159 editor.destroy()
160 self.editor = None
161 del self.buffers[self.buffer.id]
162 self.buffer = None
163 self.panel.Destroy()
164
165
166 def bufferHasChanged(self):
167 """Return True if buffer has changed since last save."""
168 if self.buffer:
169 return self.buffer.hasChanged()
170 else:
171 return False
172
173 def bufferNew(self):
174 """Create new buffer."""
175 if self.bufferHasChanged():
176 cancel = self.bufferSuggestSave()
177 if cancel:
178 return cancel
179 self.bufferCreate()
180 cancel = False
181 return cancel
182
183 def bufferOpen(self):
184 """Open file in buffer."""
185 if self.bufferHasChanged():
186 cancel = self.bufferSuggestSave()
187 if cancel:
188 return cancel
189 filedir = ''
190 if self.buffer and self.buffer.doc.filedir:
191 filedir = self.buffer.doc.filedir
192 result = openSingle(directory=filedir)
193 if result.path:
194 self.bufferCreate(result.path)
195 cancel = False
196 return cancel
197
198## def bufferPrint(self):
199## """Print buffer."""
200## pass
201
202## def bufferRevert(self):
203## """Revert buffer to version of file on disk."""
204## pass
205
206 def bufferSave(self):
207 """Save buffer to its file."""
208 if self.buffer.doc.filepath:
209 self.buffer.save()
210 cancel = False
211 else:
212 cancel = self.bufferSaveAs()
213 return cancel
214
215 def bufferSaveAs(self):
216 """Save buffer to a new filename."""
217 if self.bufferHasChanged() and self.buffer.doc.filepath:
218 cancel = self.bufferSuggestSave()
219 if cancel:
220 return cancel
221 filedir = ''
222 if self.buffer and self.buffer.doc.filedir:
223 filedir = self.buffer.doc.filedir
224 result = saveSingle(directory=filedir)
225 if result.path:
226 self.buffer.saveAs(result.path)
227 cancel = False
228 else:
229 cancel = True
230 return cancel
231
232 def bufferSuggestSave(self):
233 """Suggest saving changes. Return True if user selected Cancel."""
234 result = messageDialog(parent=None,
235 message='%s has changed.\n'
236 'Would you like to save it first'
237 '?' % self.buffer.name,
238 title='Save current file?')
239 if result.positive:
240 cancel = self.bufferSave()
241 else:
242 cancel = result.text == 'Cancel'
243 return cancel
244
245 def updateNamespace(self):
246 """Update the buffer namespace for autocompletion and calltips."""
247 if self.buffer.updateNamespace():
248 self.SetStatusText('Namespace updated')
249 else:
250 self.SetStatusText('Error executing, unable to update namespace')
251
252
253class EditorNotebookFrame(EditorFrame):
254 """Frame containing one or more editors in a notebook."""
255
256 def __init__(self, parent=None, id=-1, title='PyAlaMode',
257 pos=wx.DefaultPosition, size=(800, 600),
258 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE,
259 filename=None):
260 """Create EditorNotebookFrame instance."""
261 self.notebook = None
262 EditorFrame.__init__(self, parent, id, title, pos,
263 size, style, filename)
264 if self.notebook:
265 dispatcher.connect(receiver=self._editorChange,
266 signal='EditorChange', sender=self.notebook)
267
268 def _setup(self):
269 """Setup prior to first buffer creation.
270
271 Called automatically by base class during init."""
272 self.notebook = EditorNotebook(parent=self)
273 intro = 'Py %s' % version.VERSION
274 import imp
275 module = imp.new_module('__main__')
276 import __builtin__
277 module.__dict__['__builtins__'] = __builtin__
278 namespace = module.__dict__.copy()
279 self.crust = crust.Crust(parent=self.notebook, intro=intro, locals=namespace)
280 self.shell = self.crust.shell
281 # Override the filling so that status messages go to the status bar.
282 self.crust.filling.tree.setStatusText = self.SetStatusText
283 # Override the shell so that status messages go to the status bar.
284 self.shell.setStatusText = self.SetStatusText
285 # Fix a problem with the sash shrinking to nothing.
286 self.crust.filling.SetSashPosition(200)
287 self.notebook.AddPage(page=self.crust, text='*Shell*', select=True)
288 self.setEditor(self.crust.editor)
289 self.crust.editor.SetFocus()
290
291 def _editorChange(self, editor):
292 """Editor change signal receiver."""
293 self.setEditor(editor)
294
295 def OnAbout(self, event):
296 """Display an About window."""
297 title = 'About PyAlaMode'
298 text = 'Another fine, flaky program.'
299 dialog = wx.MessageDialog(self, text, title,
300 wx.OK | wx.ICON_INFORMATION)
301 dialog.ShowModal()
302 dialog.Destroy()
303
304 def _updateTitle(self):
305 """Show current title information."""
306 pass
307## title = self.GetTitle()
308## if self.bufferHasChanged():
309## if title.startswith('* '):
310## pass
311## else:
312## self.SetTitle('* ' + title)
313## else:
314## if title.startswith('* '):
315## self.SetTitle(title[2:])
316
317 def bufferCreate(self, filename=None):
318 """Create new buffer."""
319 buffer = Buffer()
320 panel = wx.Panel(parent=self.notebook, id=-1)
02b800ce 321 panel.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: x)
d14a1e28
RD
322 editor = Editor(parent=panel)
323 panel.editor = editor
324 sizer = wx.BoxSizer(wx.VERTICAL)
325 sizer.Add(editor.window, 1, wx.EXPAND)
326 panel.SetSizer(sizer)
327 panel.SetAutoLayout(True)
328 sizer.Layout()
329 buffer.addEditor(editor)
330 buffer.open(filename)
331 self.setEditor(editor)
332 self.notebook.AddPage(page=panel, text=self.buffer.name, select=True)
333 self.editor.setFocus()
334
335 def bufferDestroy(self):
336 """Destroy the current buffer."""
337 selection = self.notebook.GetSelection()
338## print "Destroy Selection:", selection
339 if selection > 0: # Don't destroy the PyCrust tab.
340 if self.buffer:
341 del self.buffers[self.buffer.id]
342 self.buffer = None # Do this before DeletePage().
343 self.notebook.DeletePage(selection)
344
345 def bufferNew(self):
346 """Create new buffer."""
347 self.bufferCreate()
348 cancel = False
349 return cancel
350
351 def bufferOpen(self):
352 """Open file in buffer."""
353 filedir = ''
354 if self.buffer and self.buffer.doc.filedir:
355 filedir = self.buffer.doc.filedir
356 result = openMultiple(directory=filedir)
357 for path in result.paths:
358 self.bufferCreate(path)
359 cancel = False
360 return cancel
361
362
363class EditorNotebook(wx.Notebook):
364 """A notebook containing a page for each editor."""
365
366 def __init__(self, parent):
367 """Create EditorNotebook instance."""
c6ca8c02 368 wx.Notebook.__init__(self, parent, id=-1, style=wx.CLIP_CHILDREN)
02b800ce
RD
369 self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging, id=self.GetId())
370 self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged, id=self.GetId())
371 self.Bind(wx.EVT_IDLE, self.OnIdle)
d14a1e28
RD
372
373 def OnIdle(self, event):
374 """Event handler for idle time."""
375 self._updateTabText()
376 event.Skip()
377
378 def _updateTabText(self):
379 """Show current buffer display name on all but first tab."""
380 size = 3
381 changed = ' **'
382 unchanged = ' --'
383 selection = self.GetSelection()
384 if selection < 1:
385 return
386 text = self.GetPageText(selection)
387 window = self.GetPage(selection)
388 if not window.editor:
389 return
390 if text.endswith(changed) or text.endswith(unchanged):
391 name = text[:-size]
392 else:
393 name = text
394 if name != window.editor.buffer.name:
395 text = window.editor.buffer.name
396 if window.editor.buffer.hasChanged():
397 if text.endswith(changed):
398 text = None
399 elif text.endswith(unchanged):
400 text = text[:-size] + changed
401 else:
402 text += changed
403 else:
404 if text.endswith(changed):
405 text = text[:-size] + unchanged
406 elif text.endswith(unchanged):
407 text = None
408 else:
409 text += unchanged
410 if text is not None:
411 self.SetPageText(selection, text)
412 self.Refresh() # Needed on Win98.
413
414 def OnPageChanging(self, event):
415 """Page changing event handler."""
416 event.Skip()
417
418 def OnPageChanged(self, event):
419 """Page changed event handler."""
420 new = event.GetSelection()
421 window = self.GetPage(new)
422 dispatcher.send(signal='EditorChange', sender=self,
423 editor=window.editor)
424 window.SetFocus()
425 event.Skip()
426
427
428class EditorShellNotebookFrame(EditorNotebookFrame):
429 """Frame containing a notebook containing EditorShellNotebooks."""
430
431 def __init__(self, parent=None, id=-1, title='PyAlaModeTest',
432 pos=wx.DefaultPosition, size=(600, 400),
433 style=wx.DEFAULT_FRAME_STYLE,
434 filename=None, singlefile=False):
435 """Create EditorShellNotebookFrame instance."""
436 self._singlefile = singlefile
437 EditorNotebookFrame.__init__(self, parent, id, title, pos,
438 size, style, filename)
439
440 def _setup(self):
441 """Setup prior to first buffer creation.
442
443 Called automatically by base class during init."""
444 if not self._singlefile:
445 self.notebook = EditorNotebook(parent=self)
446
447 def OnAbout(self, event):
448 """Display an About window."""
449 title = 'About PyAlaModePlus'
450 text = 'Another fine, flaky program.'
451 dialog = wx.MessageDialog(self, text, title,
452 wx.OK | wx.ICON_INFORMATION)
453 dialog.ShowModal()
454 dialog.Destroy()
455
456 def bufferCreate(self, filename=None):
457 """Create new buffer."""
458 if self._singlefile:
459 self.bufferDestroy()
460 notebook = EditorShellNotebook(parent=self,
461 filename=filename)
462 self.notebook = notebook
463 else:
464 notebook = EditorShellNotebook(parent=self.notebook,
465 filename=filename)
466 self.setEditor(notebook.editor)
467 if not self._singlefile:
468 self.notebook.AddPage(page=notebook, text=self.buffer.name,
469 select=True)
470 self.editor.setFocus()
471
472 def bufferDestroy(self):
473 """Destroy the current buffer."""
474 if self.buffer:
475 self.editor = None
476 del self.buffers[self.buffer.id]
477 self.buffer = None # Do this before DeletePage().
478 if self._singlefile:
479 self.notebook.Destroy()
480 self.notebook = None
481 else:
482 selection = self.notebook.GetSelection()
483## print "Destroy Selection:", selection
484 self.notebook.DeletePage(selection)
485
486 def bufferNew(self):
487 """Create new buffer."""
488 if self._singlefile and self.bufferHasChanged():
489 cancel = self.bufferSuggestSave()
490 if cancel:
491 return cancel
492 self.bufferCreate()
493 cancel = False
494 return cancel
495
496 def bufferOpen(self):
497 """Open file in buffer."""
498 if self._singlefile and self.bufferHasChanged():
499 cancel = self.bufferSuggestSave()
500 if cancel:
501 return cancel
502 filedir = ''
503 if self.buffer and self.buffer.doc.filedir:
504 filedir = self.buffer.doc.filedir
505 if self._singlefile:
506 result = openSingle(directory=filedir)
507 if result.path:
508 self.bufferCreate(result.path)
509 else:
510 result = openMultiple(directory=filedir)
511 for path in result.paths:
512 self.bufferCreate(path)
513 cancel = False
514 return cancel
515
516
517class EditorShellNotebook(wx.Notebook):
518 """A notebook containing an editor page and a shell page."""
519
520 def __init__(self, parent, filename=None):
521 """Create EditorShellNotebook instance."""
522 wx.Notebook.__init__(self, parent, id=-1)
523 usePanels = True
524 if usePanels:
525 editorparent = editorpanel = wx.Panel(self, -1)
526 shellparent = shellpanel = wx.Panel(self, -1)
527 else:
528 editorparent = self
529 shellparent = self
530 self.buffer = Buffer()
531 self.editor = Editor(parent=editorparent)
532 self.buffer.addEditor(self.editor)
533 self.buffer.open(filename)
534 self.shell = Shell(parent=shellparent, locals=self.buffer.interp.locals,
535 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
536 self.buffer.interp.locals.clear()
537 if usePanels:
538 self.AddPage(page=editorpanel, text='Editor', select=True)
539 self.AddPage(page=shellpanel, text='Shell')
540 # Setup sizers
541 editorsizer = wx.BoxSizer(wx.VERTICAL)
542 editorsizer.Add(self.editor.window, 1, wx.EXPAND)
543 editorpanel.SetSizer(editorsizer)
544 editorpanel.SetAutoLayout(True)
545 shellsizer = wx.BoxSizer(wx.VERTICAL)
546 shellsizer.Add(self.shell, 1, wx.EXPAND)
547 shellpanel.SetSizer(shellsizer)
548 shellpanel.SetAutoLayout(True)
549 else:
550 self.AddPage(page=self.editor.window, text='Editor', select=True)
551 self.AddPage(page=self.shell, text='Shell')
552 self.editor.setFocus()
02b800ce 553 self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged, id=self.GetId())
d14a1e28
RD
554
555 def OnPageChanged(self, event):
556 """Page changed event handler."""
557 selection = event.GetSelection()
558 if selection == 0:
559 self.editor.setFocus()
560 else:
561 self.shell.SetFocus()
562 event.Skip()
563
564 def SetFocus(self):
565 wx.Notebook.SetFocus(self)
566 selection = self.GetSelection()
567 if selection == 0:
568 self.editor.setFocus()
569 else:
570 self.shell.SetFocus()
571
572
573class Editor:
574 """Editor having an EditWindow."""
575
576 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
577 size=wx.DefaultSize,
578 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
579 """Create Editor instance."""
580 self.window = EditWindow(self, parent, id, pos, size, style)
581 self.id = self.window.GetId()
582 self.buffer = None
583 # Assign handlers for keyboard events.
02b800ce
RD
584 self.window.Bind(wx.EVT_CHAR, self.OnChar)
585 self.window.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
d14a1e28
RD
586
587 def _setBuffer(self, buffer, text):
588 """Set the editor to a buffer. Private callback called by buffer."""
589 self.buffer = buffer
590 self.autoCompleteKeys = buffer.interp.getAutoCompleteKeys()
591 self.clearAll()
592 self.setText(text)
593 self.emptyUndoBuffer()
594 self.setSavePoint()
595
596 def destroy(self):
597 """Destroy all editor objects."""
598 self.window.Destroy()
599
600 def clearAll(self):
601 self.window.ClearAll()
602
603 def emptyUndoBuffer(self):
604 self.window.EmptyUndoBuffer()
605
606 def getStatus(self):
607 """Return (filepath, line, column) status tuple."""
9513c5b6
RD
608 if self.window:
609 pos = self.window.GetCurrentPos()
610 line = self.window.LineFromPosition(pos) + 1
611 col = self.window.GetColumn(pos)
612 if self.buffer:
613 name = self.buffer.doc.filepath or self.buffer.name
614 else:
615 name = ''
616 status = (name, line, col)
617 return status
d14a1e28 618 else:
9513c5b6 619 return ('', 0, 0)
d14a1e28
RD
620
621 def getText(self):
622 """Return contents of editor."""
623 return self.window.GetText()
624
625 def hasChanged(self):
626 """Return True if contents have changed."""
627 return self.window.GetModify()
628
629 def setFocus(self):
630 """Set the input focus to the editor window."""
631 self.window.SetFocus()
632
633 def setSavePoint(self):
634 self.window.SetSavePoint()
635
636 def setText(self, text):
637 """Set contents of editor."""
638 self.window.SetText(text)
639
640 def OnChar(self, event):
641 """Keypress event handler.
642
643 Only receives an event if OnKeyDown calls event.Skip() for the
644 corresponding event."""
645
646 key = event.KeyCode()
647 if key in self.autoCompleteKeys:
648 # Usually the dot (period) key activates auto completion.
649 if self.window.AutoCompActive():
650 self.window.AutoCompCancel()
651 self.window.ReplaceSelection('')
652 self.window.AddText(chr(key))
653 text, pos = self.window.GetCurLine()
654 text = text[:pos]
655 if self.window.autoComplete:
656 self.autoCompleteShow(text)
657 elif key == ord('('):
658 # The left paren activates a call tip and cancels an
659 # active auto completion.
660 if self.window.AutoCompActive():
661 self.window.AutoCompCancel()
662 self.window.ReplaceSelection('')
663 self.window.AddText('(')
664 text, pos = self.window.GetCurLine()
665 text = text[:pos]
666 self.autoCallTipShow(text)
667 else:
668 # Allow the normal event handling to take place.
669 event.Skip()
670
671 def OnKeyDown(self, event):
672 """Key down event handler."""
673
674 key = event.KeyCode()
675 # If the auto-complete window is up let it do its thing.
676 if self.window.AutoCompActive():
677 event.Skip()
678 return
679 controlDown = event.ControlDown()
680 altDown = event.AltDown()
681 shiftDown = event.ShiftDown()
682 # Let Ctrl-Alt-* get handled normally.
683 if controlDown and altDown:
684 event.Skip()
685 # Increase font size.
686 elif controlDown and key in (ord(']'),):
687 dispatcher.send(signal='FontIncrease')
688 # Decrease font size.
689 elif controlDown and key in (ord('['),):
690 dispatcher.send(signal='FontDecrease')
691 # Default font size.
692 elif controlDown and key in (ord('='),):
693 dispatcher.send(signal='FontDefault')
694 else:
695 event.Skip()
696
697 def autoCompleteShow(self, command):
698 """Display auto-completion popup list."""
699 list = self.buffer.interp.getAutoCompleteList(command,
700 includeMagic=self.window.autoCompleteIncludeMagic,
701 includeSingle=self.window.autoCompleteIncludeSingle,
702 includeDouble=self.window.autoCompleteIncludeDouble)
703 if list:
704 options = ' '.join(list)
705 offset = 0
706 self.window.AutoCompShow(offset, options)
707
708 def autoCallTipShow(self, command):
709 """Display argument spec and docstring in a popup window."""
710 if self.window.CallTipActive():
711 self.window.CallTipCancel()
712 (name, argspec, tip) = self.buffer.interp.getCallTip(command)
713 if tip:
714 dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
715 if not self.window.autoCallTip:
716 return
717 if argspec:
718 startpos = self.window.GetCurrentPos()
719 self.window.AddText(argspec + ')')
720 endpos = self.window.GetCurrentPos()
721 self.window.SetSelection(endpos, startpos)
722 if tip:
723 curpos = self.window.GetCurrentPos()
724 size = len(name)
725 tippos = curpos - (size + 1)
726 fallback = curpos - self.window.GetColumn(curpos)
727 # In case there isn't enough room, only go back to the
728 # fallback.
729 tippos = max(tippos, fallback)
730 self.window.CallTipShow(tippos, tip)
731 self.window.CallTipSetHighlight(0, size)
732
733
734class EditWindow(editwindow.EditWindow):
735 """EditWindow based on StyledTextCtrl."""
736
737 def __init__(self, editor, parent, id=-1, pos=wx.DefaultPosition,
738 size=wx.DefaultSize,
739 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
740 """Create EditWindow instance."""
741 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
742 self.editor = editor
743
744
745class DialogResults:
746 """DialogResults class."""
747
748 def __init__(self, returned):
749 """Create wrapper for results returned by dialog."""
750 self.returned = returned
751 self.positive = returned in (wx.ID_OK, wx.ID_YES)
752 self.text = self._asString()
753
754
755 def __repr__(self):
756 return str(self.__dict__)
757
758 def _asString(self):
759 returned = self.returned
760 if returned == wx.ID_OK:
761 return "Ok"
762 elif returned == wx.ID_CANCEL:
763 return "Cancel"
764 elif returned == wx.ID_YES:
765 return "Yes"
766 elif returned == wx.ID_NO:
767 return "No"
768
769
770def fileDialog(parent=None, title='Open', directory='', filename='',
771 wildcard='All Files (*.*)|*.*',
772 style=wx.OPEN | wx.MULTIPLE):
773 """File dialog wrapper function."""
774 dialog = wx.FileDialog(parent, title, directory, filename,
775 wildcard, style)
776 result = DialogResults(dialog.ShowModal())
777 if result.positive:
778 result.paths = dialog.GetPaths()
779 else:
780 result.paths = []
781 dialog.Destroy()
782 return result
783
784
785def openSingle(parent=None, title='Open', directory='', filename='',
786 wildcard='All Files (*.*)|*.*', style=wx.OPEN):
787 """File dialog wrapper function."""
788 dialog = wx.FileDialog(parent, title, directory, filename,
789 wildcard, style)
790 result = DialogResults(dialog.ShowModal())
791 if result.positive:
792 result.path = dialog.GetPath()
793 else:
794 result.path = None
795 dialog.Destroy()
796 return result
797
798
799def openMultiple(parent=None, title='Open', directory='', filename='',
800 wildcard='All Files (*.*)|*.*',
801 style=wx.OPEN | wx.MULTIPLE):
802 """File dialog wrapper function."""
803 return fileDialog(parent, title, directory, filename, wildcard, style)
804
805
806def saveSingle(parent=None, title='Save', directory='', filename='',
807 wildcard='All Files (*.*)|*.*',
808 style=wx.SAVE | wx.HIDE_READONLY | wx.OVERWRITE_PROMPT):
809 """File dialog wrapper function."""
810 dialog = wx.FileDialog(parent, title, directory, filename,
811 wildcard, style)
812 result = DialogResults(dialog.ShowModal())
813 if result.positive:
814 result.path = dialog.GetPath()
815 else:
816 result.path = None
817 dialog.Destroy()
818 return result
819
820
821def directory(parent=None, message='Choose a directory', path='', style=0,
822 pos=wx.DefaultPosition, size=wx.DefaultSize):
823 """Dir dialog wrapper function."""
824 dialog = wx.DirDialog(parent, message, path, style, pos, size)
825 result = DialogResults(dialog.ShowModal())
826 if result.positive:
827 result.path = dialog.GetPath()
828 else:
829 result.path = None
830 dialog.Destroy()
831 return result
832
833
834def messageDialog(parent=None, message='', title='Message box',
835 style=wx.YES_NO | wx.CANCEL | wx.CENTRE | wx.ICON_QUESTION,
836 pos=wx.DefaultPosition):
837 """Message dialog wrapper function."""
838 dialog = wx.MessageDialog(parent, message, title, style, pos)
839 result = DialogResults(dialog.ShowModal())
840 dialog.Destroy()
841 return result