Added wxEditableListBox gizmo.
+Added a greatly enhanced wxEditor from Steve Howell and Adam Feuer.
+
include samples/StyleEditor/*.cfg
include samples/pySketch/*.py
include samples/pySketch/images/*.bmp
+include samples/frogedit/*.py
include wxPython/lib/*.py
from wxPython.wx import *
-from wxPython.lib.editor import wxEditor, wxPyEditor
+from wxPython.lib.editor import wxEditor
#----------------------------------------------------------------------
def runTest(frame, nb, log):
win = wxPanel(nb, -1)
ed = wxEditor(win, -1, style=wxSUNKEN_BORDER)
- pyed = wxPyEditor(win, -1, style=wxSUNKEN_BORDER)
box = wxBoxSizer(wxVERTICAL)
box.Add(ed, 1, wxALL|wxGROW, 5)
- box.Add(pyed, 1, wxALL|wxGROW, 5)
win.SetSizer(box)
win.SetAutoLayout(true)
ed.SetText(["",
"This is a simple text editor, the class name is",
"wxEditor. Type a few lines and try it out.",
+ "",
+ "It uses Windows-style key commands that can be overriden by subclassing.",
+ "Mouse select works. Here are the key commands:",
+ "",
+ "Cursor movement: Arrow keys or mouse",
+ "Beginning of line: Home",
+ "End of line: End",
+ "Beginning of buffer: Control-Home",
+ "End of the buffer: Control-End",
+ "Select text: Hold down Shift while moving the cursor",
+ "Copy: Control-Insert, Control-C",
+ "Cut: Shift-Delete, Control-X",
+ "Paste: Shift-Insert, Control-V",
""])
- pyed.SetText(["# This one is a derived class named wxPyEditor.",
- "# It adds syntax highlighting, folding (press",
- "# F12 on the \"def\" line below) and other stuff.",
- "import sys",
- "def hello():",
- " print 'hello'",
- " for x in sys.path:",
- " print x",
- ""])
return win
#----------------------------------------------------------------------
+overview = """
+The wxEditor class implements a simple text editor using wxPython. You
+can create a custom editor by subclassing wxEditor. Even though much of
+the editor is implemented in Python, it runs surprisingly smoothly on
+normal hardware with small files.
+How to use it
+-------------
+The demo code (demo/wxEditor.py) shows how to use wxEditor as a simple text
+box. Use the SetText() and GetText() methods to set or get text from
+the component; these both use a list of strings.
+
+The samples/FrogEdit directory has an example of a simple text editor
+application that uses the wxEditor component.
+
+Subclassing
+-----------
+To add or change functionality, you can subclass this
+component. One example of this might be to change the key
+Alt key commands. In that case you would (for example) override the
+SetAltFuncs() method.
-overview = """\
"""
Source: "samples\pySketch\*.py"; DestDir: "{app}\wxPython\samples\pySketch"; Components: samples
Source: "samples\pySketch\images\*.bmp"; DestDir: "{app}\wxPython\samples\pySketch\images"; Components: samples
+Source: "samples\frogedit\*.py"; DestDir: "{app}\wxPython\samples\frogedit"; Components: samples
;;------------------------------------------------------------
Type: files; Name: "{app}\wxPython\samples\stxview\*.pyo";
Type: files; Name: "{app}\wxPython\samples\stxview\StructuredText\*.pyc";
Type: files; Name: "{app}\wxPython\samples\stxview\StructuredText\*.pyo";
+Type: files; Name: "{app}\wxPython\samples\frogedit\*.pyc";
+Type: files; Name: "{app}\wxPython\samples\frogedit\*.pyo";
'''
--- /dev/null
+#!/usr/local/bin/python
+
+# simple text editor
+#
+# Copyright 2001 Adam Feuer and Steve Howell
+#
+# License: Python
+
+import os, string, re
+import sys
+from wxPython.wx import *
+from StatusBar import *
+from FrogEditor import FrogEditor
+
+TRUE = 1
+FALSE = 0
+
+ABOUT_TEXT = """FrogEdit : Copyright 2001 Adam Feuer and Steve Howell
+wxEditor component : Copyright 1999 - 2001 Dirk Holtwic, Robin Dunn, Adam Feuer, Steve Howell
+
+FrogEdit was built using Python, wxPython, and wxWindows."""
+
+
+##---------------------------------------------------------------------
+
+def chomp(line):
+ line = string.split(line,'\n')[0]
+ return string.split(line,'\r')[0]
+
+##---------------------------------------------------------------------
+
+class OutlinerPanel(wxPanel):
+
+ def Close(self, event):
+ self.parent.Close()
+ wxPanel.Close(self)
+
+##----------------------------------------------------------------------
+
+
+class FrogEditFrame(wxFrame):
+ def __init__(self, parent, ID, title, pos=wxDefaultPosition,
+ size=wxDefaultSize, style=wxDEFAULT_FRAME_STYLE):
+
+ wxFrame.__init__(self, parent, ID, title, pos, size, style)
+
+ splitter = wxSplitterWindow(self, -1, style=wxNO_3D|wxSP_3D)
+ win = OutlinerPanel(splitter, -1, style=wxCLIP_CHILDREN)
+ win.parent = self
+ log = self.MakeLogWindow(splitter)
+
+ self.MakeStatusbar()
+ self.MakeEditorWindow(win, log)
+ self.SetUpSplitter(splitter, win, log)
+ self.MakeMenus()
+ self.MakeMainWindow(win)
+ self.RegisterEventHandlers()
+ self.InitVariables()
+
+
+##------------- Init Misc
+
+ def RegisterEventHandlers(self):
+ EVT_CLOSE(self,self.OnCloseWindow)
+
+ def InitVariables(self):
+ self.fileName = None
+ self.edl.UnTouchBuffer()
+
+ def MakeMenus(self):
+ self.MainMenu = wxMenuBar()
+ self.AddMenus(self.MainMenu)
+ self.SetMenuBar(self.MainMenu)
+
+##------------- Init Subwindows
+
+ def MakeEditorWindow(self, win, log):
+ self.edl = FrogEditor(win, -1, style=wxSUNKEN_BORDER, statusBar = self.sb)
+ self.edl.SetControlFuncs = self.SetControlFuncs
+ self.edl.SetAltFuncs = self.SetAltFuncs
+ self.edl.SetStatus(log)
+
+ def MakeStatusbar(self):
+ self.sb = CustomStatusBar(self)
+ self.SetStatusBar(self.sb)
+
+ def MakeLogWindow(self, container):
+ log = wxTextCtrl(container, -1,
+ style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
+ wxLog_SetActiveTarget(wxLogTextCtrl(log))
+ wxLogMessage('window handle: %s' % self.GetHandle())
+ return log
+
+ def SetUpSplitter(self, splitter, win, log):
+ splitter.SplitHorizontally(win, log)
+ splitter.SetSashPosition(360, true)
+ splitter.SetMinimumPaneSize(40)
+
+ def MakeToolbar(self, win):
+ toolbarBox = wxBoxSizer(wxHORIZONTAL)
+ self.AddButtons(win, toolbarBox)
+ return toolbarBox
+
+ def MakeMainWindow(self, win):
+ mainBox = wxBoxSizer(wxVERTICAL)
+ mainBox.Add(self.MakeToolbar(win))
+ borderWidth = 5
+ mainBox.Add(self.edl, 1, wxALL|wxGROW, borderWidth)
+ win.SetSizer(mainBox)
+ win.SetAutoLayout(true)
+
+##-------------- Init Menus
+
+ # override this to add more menus
+ def AddMenus(self, menu):
+ self.AddFileMenu(menu)
+ self.AddEditMenu(menu)
+ self.AddHelpMenu(menu)
+
+ def AddMenuItem(self, menu, itemText, itemDescription, itemHandler):
+ menuId = wxNewId()
+ menu.Append(menuId, itemText, itemDescription)
+ EVT_MENU(self, menuId, itemHandler)
+ return menuId
+
+ def AddFileMenu(self, menu):
+ fileMenu = wxMenu()
+ self.AddMenuItem(fileMenu, '&New File\tCtrl-N', 'New File', self.OnNewFile)
+ self.AddMenuItem(fileMenu, '&Open File\tCtrl-O', 'Open File', self.OnOpenFile)
+ self.AddMenuItem(fileMenu, '&Save File\tCtrl-S', 'Save File', self.OnSaveFile)
+ self.AddMenuItem(fileMenu, 'Save File &As\tCtrl-A', 'Save File As',self.OnSaveFileAs)
+ self.AddMenuItem(fileMenu, 'E&xit\tAlt-X', 'Exit', self.OnFileExit)
+ menu.Append(fileMenu, 'File')
+
+ def AddEditMenu(self, menu):
+ editMenu = wxMenu()
+ self.AddMenuItem(editMenu, 'Cut\tCtrl-X', 'Cut', self.edl.OnCutSelection)
+ self.AddMenuItem(editMenu, '&Copy\tCtrl-C', 'Copy', self.edl.OnCopySelection)
+ self.AddMenuItem(editMenu, 'Paste\tCtrl-V', 'Paste', self.edl.OnPaste)
+ self.AddMenuItem(editMenu, 'Edit preferences', 'Edit Preferences', self.OnEditPreferences)
+ menu.Append(editMenu, 'Edit')
+
+ def AddHelpMenu(self, menu):
+ helpMenu = wxMenu()
+ self.AddMenuItem(helpMenu, 'About', 'About the program', self.OnHelpAbout)
+ menu.Append(helpMenu, 'Help')
+
+##---------------- Init Buttons
+
+
+ def NewButton(self, window, container, name, pos, size, handler):
+ buttonId = wxNewId()
+ if pos == None or size == None:
+ container.Add(wxButton(window, buttonId, name), 0, 0)
+ else:
+ container.Add(wxButton(window, buttonId, name, pos, size), 0, 0)
+ EVT_BUTTON(self, buttonId, handler)
+ return buttonId
+
+ # override this to make more buttons
+ def AddButtons(self, window, container):
+ buttonPos = None
+ buttonSize = None
+ self.NewButton(window, container, "New", buttonPos, buttonSize, self.OnNewFile)
+ self.NewButton(window, container, "Open", buttonPos, buttonSize, self.OnOpenFile)
+ self.NewButton(window, container, "Save", buttonPos, buttonSize, self.OnSaveFile)
+
+
+##-------------- Init Dialogs
+
+ def MessageDialog(self, text, title):
+ messageDialog = wxMessageDialog(self, text, title, wxOK | wxICON_INFORMATION)
+ messageDialog.ShowModal()
+ messageDialog.Destroy()
+
+ def OkCancelDialog(self, text, title):
+ dialog = wxMessageDialog(self, text, title, wxOK | wxCANCEL | wxICON_INFORMATION)
+ result = dialog.ShowModal()
+ dialog.Destroy()
+ if result == wxID_OK:
+ return TRUE
+ else:
+ return FALSE
+
+ def SelectFileDialog(self, defaultDir=None, defaultFile=None, wildCard=None):
+ if defaultDir == None:
+ defaultDir = "."
+ if defaultFile == None:
+ defaultFile = ""
+ if wildCard == None:
+ wildCard = "*.*"
+ fileName = None
+ fileDialog = wxFileDialog(self, "Choose a file", defaultDir, defaultFile, wildCard, wxOPEN|wxMULTIPLE)
+ result = fileDialog.ShowModal()
+ if result == wxID_OK:
+ fileName = fileDialog.GetPath()
+ wxLogMessage('You selected: %s\n' % fileName)
+ fileDialog.Destroy()
+ return fileName
+
+ def OpenFileError(self, fileName):
+ wxLogMessage('Open file error.')
+ self.MessageDialog("Error opening file '%s'!" % fileName, "Error")
+
+
+ def SaveFileError(self, fileName):
+ wxLogMessage('Save file error.')
+ self.MessageDialog("Error saving file '%s'!" % fileName, "Error")
+
+##---------------- Utility functions
+
+
+ def SetControlFuncs(self, action):
+ "for overriding editor's keys"
+ FrogEditor.SetControlFuncs(self.edl, action)
+ action['a'] = self.OnSaveFileAs
+ action['o'] = self.OnOpenFile
+ action['n'] = self.OnNewFile
+ action['s'] = self.OnSaveFile
+
+ def SetAltFuncs(self, action):
+ FrogEditor.SetAltFuncs(self.edl, action)
+ action['x'] = self.OnFileExit
+
+ def GetCurrentDir(self):
+ if self.fileName is not None:
+ return os.path.split(self.fileName)[0]
+ return "."
+
+ def GetFileName(self):
+ if self.fileName is not None:
+ return os.path.split(self.fileName)[1]
+ return ""
+
+ def NewFile(self):
+ self.edl.SetText([""])
+ self.fileName = None
+ self.sb.setFileName("")
+
+ def SaveFile(self, fileName):
+ try:
+ contents = string.join(self.edl.GetText(), '\n')
+ f = open(fileName, 'w')
+ f.write(contents)
+ f.close()
+ self.edl.UnTouchBuffer()
+ self.sb.setFileName(fileName)
+ return TRUE
+ except:
+ return FALSE
+
+ def OpenFile(self, fileName):
+ try:
+ f = open(fileName, 'r')
+ contents = f.readlines()
+ f.close()
+ contents = [chomp(line) for line in contents]
+ if len(contents) == 0:
+ contents = [""]
+ self.edl.SetText(contents)
+ self.fileName = fileName
+ self.sb.setFileName(fileName)
+ return TRUE
+ except:
+ return FALSE
+
+
+
+##---------------- Event handlers
+
+
+ def OnCloseWindow(self, event):
+ self.edl.OnCloseWindow(event)
+ self.Destroy()
+
+ def OnNewFile(self, event):
+ if self.edl.BufferWasTouched():
+ if not self.OkCancelDialog("New file - abandon changes?", "New File"):
+ return
+ self.NewFile()
+ self.edl.SetFocus()
+
+ def OnOpenFile(self, event):
+ if self.edl.BufferWasTouched():
+ if not self.OkCancelDialog("Open file - abandon changes?", "Open File"):
+ return
+ fileName = self.SelectFileDialog(self.GetCurrentDir())
+ if fileName is not None:
+ if self.OpenFile(fileName) is FALSE:
+ self.OpenFileError(fileName)
+ self.edl.SetFocus()
+
+ def OnSaveFile(self, event):
+ if self.fileName is None:
+ return self.OnSaveFileAs(event)
+ wxLogMessage("Saving %s..." % self.fileName)
+ if self.SaveFile(self.fileName) is not TRUE:
+ self.SaveFileError(self.fileName)
+ self.edl.SetFocus()
+
+ def OnSaveFileAs(self, event):
+ fileName = self.SelectFileDialog(self.GetCurrentDir(),self.GetFileName())
+ if fileName is not None:
+ self.fileName = fileName
+ wxLogMessage("Saving %s..." % self.fileName)
+ if self.SaveFile(self.fileName) is not TRUE:
+ self.SaveFileError(self.fileName)
+ self.edl.SetFocus()
+
+ def OnFileExit(self, event):
+ if self.edl.BufferWasTouched():
+ if not self.OkCancelDialog("Exit program - abandon changes?", "Exit"):
+ return
+ self.OnCloseWindow(event)
+
+ def OnEditPreferences(self, event):
+ self.MessageDialog("Edit preferences is not implemented yet.", "Not implemented.")
+ pass
+
+ def OnHelpAbout(self, event):
+ self.MessageDialog(ABOUT_TEXT, "About FrogEdit")
+ pass
+
+ def Show(self, show):
+ wxFrame.Show(self, show)
+ self.edl.SetFocus()
+
+##------------- Startup stuff
+
+ def LoadInitialFile(self, fileName):
+ if fileName is not None:
+ if self.OpenFile(fileName) is FALSE:
+ self.OpenFileError(fileName)
+
+
+
+
+##-------------- Application Launcher utility class
+
+class FrogEditLauncher:
+
+ def MakeAppFrame(self):
+ return FrogEditFrame(None, -1, "FrogEdit", size=(640, 480),
+ style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
+ def GetArgvFilename(self):
+ if len(sys.argv) > 1:
+ return sys.argv[1]
+ else:
+ return None
+
+ def Main(self):
+ win = self.MakeAppFrame()
+ app = wxPySimpleApp()
+ win.Show(true)
+ win.LoadInitialFile(self.GetArgvFilename())
+ app.MainLoop()
+
+
+##-------------- Main program
+
+
+if __name__ == '__main__':
+
+ launcher = FrogEditLauncher()
+ launcher.Main()
+
--- /dev/null
+#!/usr/local/bin/python
+
+# simple text editor
+#
+# Copyright 2001 Adam Feuer and Steve Howell
+#
+# License: Python
+
+import re
+from wxPython.wx import *
+from wxPython.lib.editor import wxEditor
+
+#---------------------------------------------------------------------
+
+class FrogEditor(wxEditor):
+ def __init__(self, parent, id,
+ pos=wxDefaultPosition, size=wxDefaultSize, style=0, statusBar=None):
+ self.StatusBar = statusBar
+ wxEditor.__init__(self, parent, id, pos, size, style)
+ self.parent = parent
+
+ ##------------------------------------
+
+ def TouchBuffer(self):
+ wxEditor.TouchBuffer(self)
+ self.StatusBar.setDirty(1)
+
+ def UnTouchBuffer(self):
+ wxEditor.UnTouchBuffer(self)
+ self.StatusBar.setDirty(0)
+
+
+ #--------- utility function -------------
+
+ # override our base class method
+ def DrawCursor(self, dc = None):
+ wxEditor.DrawCursor(self,dc)
+ self.StatusBar.setRowCol(self.cy,self.cx)
+
+ def lastLine(self):
+ lastline = self.sy + self.sh - 1
+ return min(lastline, self.LinesInFile() - 1)
+
+ def rawLines(self):
+ return [l.text for l in self.text]
+
+ def save(self):
+ if self.page:
+ self.ds.store(self.page,self.rawLines())
+
+ def SetRawText(self, rawtext=""):
+ self.rawText= rawtext
+ self.SetText(self.RenderText())
+
+ def RenderText(self):
+ return(self.rawText)
+
+ #---------- logging -------------
+
+ def SetStatus(self, log):
+ self.log = log
+ self.status = []
+
+ def PrintSeparator(self, event):
+ self.Print("..........................")
+
+ def Print(self, data):
+ self.status.append(data)
+ if data[-1:] == '\n':
+ data = data[:-1]
+ wxLogMessage(data)
+
+ #--------- wxEditor keyboard overrides
+
+ def SetControlFuncs(self, action):
+ wxEditor.SetControlFuncs(self, action)
+ action['-'] = self.PrintSeparator
+
+ def SetAltFuncs(self, action):
+ wxEditor.SetAltFuncs(self, action)
+ action['x'] = self.Exit
+
+ #----------- commands -----------
+
+ def OnCloseWindow(self, event):
+ # xxx - We don't fully understand how exit logic works.
+ # This event is actually called by our parent frame.
+ pass
+
+ def Exit(self,event):
+ self.parent.Close(None)
+
--- /dev/null
+from wxPython.wx import *
+
+import os.path
+
+class CustomStatusBar(wxStatusBar):
+ def __init__(self, parent):
+ wxStatusBar.__init__(self, parent, -1)
+ self.SetFieldsCount(3)
+
+ def setFileName(self, fn):
+ path, fileName = os.path.split(fn)
+ self.SetStatusText(fileName, 0)
+
+ def setRowCol(self, row, col):
+ self.SetStatusText("%d,%d" % (row,col), 1)
+
+ def setDirty(self, dirty):
+ if dirty:
+ self.SetStatusText("...", 2)
+ else:
+ self.SetStatusText(" ", 2)
+
+++ /dev/null
-#!/usr/bin/env python
-"""PyCrust is a python shell and namespace browser application."""
-
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
-__version__ = "$Revision$"[11:-2]
-
-from wxPython.wx import *
-from crust import CrustFrame
-
-
-class App(wxApp):
- """PyCrust standalone application."""
-
- def OnInit(self):
- locals = {'__app__': 'PyCrust Standalone Application'}
- self.crustFrame = CrustFrame(locals=locals)
- self.crustFrame.Show(true)
- # Set focus to the shell editor.
- #self.crustFrame.crust.shell.SetFocus()
- self.SetTopWindow(self.crustFrame)
- # Add the application object to the sys module's namespace.
- # This allows a shell user to do:
- # >>> import sys
- # >>> sys.application.whatever
- import sys
- sys.application = self
- return true
-
-
-def main():
- application = App(0)
- application.MainLoop()
-
-if __name__ == '__main__':
- main()
-
--- /dev/null
+#!/usr/bin/env python
+"""PyCrustApp is a python shell and namespace browser application."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__version__ = "$Revision$"[11:-2]
+
+from wxPython.wx import *
+from PyCrust.crust import CrustFrame
+
+
+class App(wxApp):
+ """PyCrust standalone application."""
+
+ def OnInit(self):
+ locals = {'__app__': 'PyCrust Standalone Application'}
+ self.crustFrame = CrustFrame(locals=locals)
+ self.crustFrame.Show(true)
+ self.SetTopWindow(self.crustFrame)
+ # Add the application object to the sys module's namespace.
+ # This allows a shell user to do:
+ # >>> import sys
+ # >>> sys.application.whatever
+ import sys
+ sys.application = self
+ return true
+
+
+def main():
+ application = App(0)
+ application.MainLoop()
+
+if __name__ == '__main__':
+ main()
+
+
+++ /dev/null
-#!/usr/bin/env python
-"""PyFilling is a python namespace inspection application."""
-
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "August 21, 2001"
-__version__ = "$Revision$"[11:-2]
-
-# We use this object to get more introspection when run standalone.
-application = None
-
-import filling
-
-# These are imported just to have something interesting to inspect.
-import crust
-import interpreter
-import introspect
-import pseudo
-import shell
-import sys
-from wxPython import wx
-
-
-def main():
- """Create and run the application."""
- global application
- application = filling.App(0)
- root = application.fillingFrame.filling.fillingTree.root
- application.fillingFrame.filling.fillingTree.Expand(root)
- application.MainLoop()
-
-
-if __name__ == '__main__':
- main()
-
--- /dev/null
+#!/usr/bin/env python
+"""PyFillingApp is a python namespace inspection application."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__version__ = "$Revision$"[11:-2]
+
+# We use this object to get more introspection when run standalone.
+application = None
+
+from PyCrust import filling
+
+# These are imported just to have something interesting to inspect.
+from PyCrust import crust
+from PyCrust import interpreter
+from PyCrust import introspect
+from PyCrust import pseudo
+from PyCrust import shell
+import sys
+from wxPython import wx
+
+
+def main():
+ """Create and run the application."""
+ global application
+ application = filling.App(0)
+ root = application.fillingFrame.filling.fillingTree.root
+ application.fillingFrame.filling.fillingTree.Expand(root)
+ application.MainLoop()
+
+
+if __name__ == '__main__':
+ main()
+
+
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-"""PyShell is a python shell application."""
-
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
-__version__ = "$Revision$"[11:-2]
-
-from wxPython.wx import *
-from shell import ShellFrame
-
-
-class App(wxApp):
- """PyShell standalone application."""
-
- def OnInit(self):
- locals = {'__app__': 'PyShell Standalone Application'}
- self.shellFrame = ShellFrame(locals=locals)
- self.shellFrame.Show(true)
- self.SetTopWindow(self.shellFrame)
- # Add the application object to the sys module's namespace.
- # This allows a shell user to do:
- # >>> import sys
- # >>> sys.application.whatever
- import sys
- sys.application = self
- return true
-
-
-def main():
- application = App(0)
- application.MainLoop()
-
-if __name__ == '__main__':
- main()
-
--- /dev/null
+#!/usr/bin/env python
+"""PyShellApp is a python shell application."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__version__ = "$Revision$"[11:-2]
+
+from wxPython.wx import *
+from PyCrust.shell import ShellFrame
+
+
+class App(wxApp):
+ """PyShell standalone application."""
+
+ def OnInit(self):
+ locals = {'__app__': 'PyShell Standalone Application'}
+ self.shellFrame = ShellFrame(locals=locals)
+ self.shellFrame.Show(true)
+ self.SetTopWindow(self.shellFrame)
+ # Add the application object to the sys module's namespace.
+ # This allows a shell user to do:
+ # >>> import sys
+ # >>> sys.application.whatever
+ import sys
+ sys.application = self
+ return true
+
+
+def main():
+ application = App(0)
+ application.MainLoop()
+
+if __name__ == '__main__':
+ main()
+
+
+
\ No newline at end of file
PyCrust - The Flakiest Python Shell
Half-baked by Patrick K. O'Brien (pobrien@orbtech.com)
-======================================================
+
+==============================================================
+* Orbtech - "Your Source For Python Development Services" *
+* Sample all our half-baked Python goods at www.orbtech.com. *
+==============================================================
What is PyCrust?
----------------
Where can I get the latest release of PyCrust?
-------------------------------------------------------------
+----------------------------------------------
The latest PyCrust releases are available at:
http://sourceforge.net/project/showfiles.php?group_id=31263
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
__version__ = "$Revision$"[11:-2]
from wxPython.wx import *
revision = __version__
def __init__(self, parent=None, id=-1, title='PyCrust', \
+ pos=wxDefaultPosition, size=wxDefaultSize, \
+ style=wxDEFAULT_FRAME_STYLE, \
rootObject=None, rootLabel=None, rootIsNamespace=1, \
locals=None, InterpClass=None, *args, **kwds):
"""Create a PyCrust CrustFrame instance."""
- wxFrame.__init__(self, parent, id, title)
+ wxFrame.__init__(self, parent, id, title, pos, size, style)
intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
+ intro += '\nSponsored by Orbtech.com \96 Your Source For Python Development Services'
self.CreateStatusBar()
self.SetStatusText(intro)
if wxPlatform == '__WXMSW__':
- icon = wxIcon('PyCrust.ico', wxBITMAP_TYPE_ICO)
+ import os
+ filename = os.path.join(os.path.dirname(__file__), 'PyCrust.ico')
+ icon = wxIcon(filename, wxBITMAP_TYPE_ICO)
self.SetIcon(icon)
self.crust = Crust(parent=self, intro=intro, \
rootObject=rootObject, \
self.createMenus()
+
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
-__date__ = "August 21, 2001"
__version__ = "$Revision$"[11:-2]
from wxPython.wx import *
self.SetViewWhiteSpace(0)
self.SetTabWidth(4)
self.SetUseTabs(0)
+ self.SetReadOnly(1)
def setStyles(self, faces):
"""Configure font size, typeface and color for lexer."""
self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F")
self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces)
+ def SetText(self, *args, **kwds):
+ self.SetReadOnly(0)
+ wxStyledTextCtrl.SetText(self, *args, **kwds)
+ self.SetReadOnly(1)
+
class Filling(wxSplitterWindow):
"""PyCrust Filling based on wxSplitterWindow."""
self.CreateStatusBar()
self.SetStatusText(intro)
if wxPlatform == '__WXMSW__':
- icon = wxIcon('PyCrust.ico', wxBITMAP_TYPE_ICO)
+ import os
+ filename = os.path.join(os.path.dirname(__file__), 'PyCrust.ico')
+ icon = wxIcon(filename, wxBITMAP_TYPE_ICO)
self.SetIcon(icon)
self.filling = Filling(parent=self, rootObject=rootObject, \
rootLabel=rootLabel, \
+
\ No newline at end of file
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
__version__ = "$Revision$"[11:-2]
import os
sys.ps1 = ps1
sys.ps2 = ps2
-
\ No newline at end of file
+
\ No newline at end of file
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
-__date__ = "August 8, 2001"
__version__ = "$Revision$"[11:-2]
import inspect
return root
+
\ No newline at end of file
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
__version__ = "$Revision$"[11:-2]
class PseudoKeyword:
return 1
+
\ No newline at end of file
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
__version__ = "$Revision$"[11:-2]
from wxPython.wx import *
# If the auto-complete window is up let it do its thing.
elif self.AutoCompActive():
event.Skip()
+ # Cut to the clipboard.
+ elif event.ControlDown() and key in (ord('X'), ord('x')):
+ self.Cut()
+ # Copy to the clipboard.
+ elif event.ControlDown() and not event.ShiftDown() \
+ and key in (ord('C'), ord('c')):
+ self.Copy()
+ # Copy to the clipboard, including prompts.
+ elif event.ControlDown() and event.ShiftDown() \
+ and key in (ord('C'), ord('c')):
+ self.CopyWithPrompts()
+ # Paste from the clipboard.
+ elif event.ControlDown() and key in (ord('V'), ord('v')):
+ self.Paste()
# Retrieve the previous command from the history buffer.
elif (event.ControlDown() and key == WXK_UP) \
or (event.AltDown() and key in (ord('P'), ord('p'))):
# Don't toggle between insert mode and overwrite mode.
elif key == WXK_INSERT:
pass
+ # Protect the readonly portion of the shell.
+ elif not self.CanEdit():
+ pass
else:
event.Skip()
The command may not necessarily be valid Python syntax."""
if not text:
text = self.GetCurLine()[0]
- # XXX Need to extract real prompts here. Need to keep track of the
- # prompt every time a command is issued.
+ # Strip the prompt off the front of text leaving just the command.
+ command = self.lstripPrompt(text)
+ if command == text:
+ command = '' # Real commands have prompts.
+ if rstrip:
+ command = command.rstrip()
+ return command
+
+ def lstripPrompt(self, text):
+ """Return text without a leading prompt."""
ps1 = str(sys.ps1)
ps1size = len(ps1)
ps2 = str(sys.ps2)
ps2size = len(ps2)
- # Strip the prompt off the front of text leaving just the command.
+ # Strip the prompt off the front of text.
if text[:ps1size] == ps1:
- command = text[ps1size:]
+ text = text[ps1size:]
elif text[:ps2size] == ps2:
- command = text[ps2size:]
- else:
- command = ''
- if rstrip:
- command = command.rstrip()
- return command
+ text = text[ps2size:]
+ return text
def push(self, command):
"""Send command to the interpreter for execution."""
if self.CanCopy():
command = self.GetSelectedText()
command = command.replace(os.linesep + sys.ps2, os.linesep)
+ command = command.replace(os.linesep + sys.ps1, os.linesep)
+ command = self.lstripPrompt(text=command)
+ data = wxTextDataObject(command)
+ if wxTheClipboard.Open():
+ wxTheClipboard.SetData(data)
+ wxTheClipboard.Close()
+
+ def CopyWithPrompts(self):
+ """Copy selection, including prompts, and place it on the clipboard."""
+ if self.CanCopy():
+ command = self.GetSelectedText()
data = wxTextDataObject(command)
if wxTheClipboard.Open():
wxTheClipboard.SetData(data)
if wxTheClipboard.GetData(data):
command = data.GetText()
command = self.fixLineEndings(command)
+ command = self.lstripPrompt(text=command)
command = command.replace(os.linesep + sys.ps2, '\n')
command = command.replace(os.linesep, '\n')
command = command.replace('\n', os.linesep + sys.ps2)
"""Create a PyCrust ShellFrame instance."""
wxFrame.__init__(self, parent, id, title, pos, size, style)
intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
+ intro += '\nSponsored by Orbtech.com \96 Your Source For Python Development Services'
self.CreateStatusBar()
self.SetStatusText(intro)
if wxPlatform == '__WXMSW__':
- icon = wxIcon('PyCrust.ico', wxBITMAP_TYPE_ICO)
+ import os
+ filename = os.path.join(os.path.dirname(__file__), 'PyCrust.ico')
+ icon = wxIcon(filename, wxBITMAP_TYPE_ICO)
self.SetIcon(icon)
self.shell = Shell(parent=self, id=-1, introText=intro, \
locals=locals, InterpClass=InterpClass, \
+
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
__version__ = "$Revision$"[11:-2]
VERSION = '0.7'
+
\ No newline at end of file
-PLEASE NOTE: This is experimental code. It needs an overhall in the
- drawing and update code, and there is occasionally a
- mysteriously disappearing line...
+wxEditor component
+------------------
- I am working on a StyledTextEditor that will likely
- render this editor obsolete... But this one is at
- least somewhat functional now while the other is still
- vapor.
+The wxEditor class implements a simple text editor using wxPython. You
+can create a custom editor by subclassing wxEditor. Even though much of
+the editor is implemented in Python, it runs surprisingly smoothly on
+normal hardware with small files.
- - Robin
+
+Keys
+----
+Keys are similar to Windows-based editors:
+
+Tab: 1 to 4 spaces (to next tab stop)
+Cursor movement: Arrow keys
+Beginning of line: Home
+End of line: End
+Beginning of buffer: Control-Home
+End of the buffer: Control-End
+Select text: Hold down Shift while moving the cursor
+Copy: Shift-Insert, Control-C
+Cut: Shift-Delete, Control-X
+Paste: Control-Insert, Control-V
+
+How to use it
+-------------
+The demo code (demo/wxEditor.py) shows how to use it as a simple text
+box. Use the SetText() and GetText() methods to set or get text from
+the component; these both return a list of strings.
+
+The samples/FrogEdit directory has an example of a simple text editor
+application that uses the wxEditor component.
+
+Subclassing
+-----------
+To add or change functionality, you can subclass this
+component. One example of this might be to change the key
+Alt key commands. In that case you would (for example) override the
+SetAltFuncs() method.
+
+History
+-------
+The original author of this component was Dirk Holtwic. It originally
+had limited support for syntax highlighting, but was not a usable text
+editor, as it didn't implement select (with keys or mouse), or any of
+the usual key sequences you'd expect in an editor. Robin Dunn did some
+refactoring work to make it more usable. Steve Howell and Adam Feuer
+did a lot of refactoring, and added some functionality, including
+keyboard and mouse select, properly working scrollbars, and
+overridable keys. Adam and Steve also removed support for
+syntax-highlighting while refactoring the code.
+
+To do
+-----
+Alt/Ctrl Arrow keys move by word
+Descriptive help text for keys
+Speed improvements
+Different fonts/colors
+
+
+Authors
+-------
+Steve Howell, Adam Feuer, Dirk Holtwic, Robin Dunn
+
+
+Contact
+-------
+You can find the latest code for wxEditor here:
+http://www.pobox.com/~adamf/software/
+
+We're not actively maintaining this code, but we can answer
+questions about it. You can email us at:
+
+Adam Feuer <adamf at pobox dot com>
+Steve Howell <showell at zipcon dot net>
+
+29 November 2001
# import the main classes into the package namespace.
from editor import wxEditor
-from py_editor import wxPyEditor
# Name: wxPython.lib.editor.wxEditor
# Purpose: An intelligent text editor with colorization capabilities.
#
-# Author: Dirk Holtwic, Robin Dunn
+# Original
+# Authors: Dirk Holtwic, Robin Dunn
+#
+# New
+# Authors: Adam Feuer, Steve Howell
+#
+# History:
+# This code used to support a fairly complex subclass that did
+# syntax coloring and outliner collapse mode. Adam and Steve
+# inherited the code, and added a lot of basic editor
+# functionality that had not been there before, such as cut-and-paste.
+#
#
# Created: 15-Dec-1999
# RCS-ID: $Id$
# Licence: wxWindows license
#----------------------------------------------------------------------
-
-# PLEASE NOTE: This is experimental code. It needs an overhall in the
-# drawing and update code, and there is occasionally a
-# mysteriously disappearing line...
-#
-# I am working on a StyledTextEditor that will likely
-# render this editor obsolete... But this one is at
-# least somewhat functional now while the other is still
-# vapor.
-#
-# - Robin
-
+import os, time
from wxPython.wx import *
from string import *
-from keyword import *
-from regsub import *
-from tokenizer import *
-#---------------------------------------------------------------------------
+import selection
+import images
+#----------------------------
-class Line:
- def __init__(self, text=""):
- self.text = text # the string itself
- self.syntax = [] # the colors of the line
- self.editable = true # edit?
- self.visible = 0 # will be incremented if not
- self.indent = 0 # not used yet
+def ForceBetween(min, val, max):
+ if val > max:
+ return max
+ if val < min:
+ return min
+ return val
+
+#----------------------------
+
+class Scroller:
+ def __init__(self, parent):
+ self.parent = parent
+ self.ow = 0
+ self.oh = 0
+ self.ox = 0
+ self.oy = 0
+
+ def SetScrollbars(self, fw, fh, w, h, x, y):
+ if (self.ow != w or self.oh != h or self.ox != x or self.oy != y):
+ self.parent.SetScrollbars(fw, fh, w, h, x, y)
+ self.ow = w
+ self.oh = h
+ self.ox = x
+ self.oy = y
#----------------------------------------------------------------------
def __init__(self, parent, id,
pos=wxDefaultPosition, size=wxDefaultSize, style=0):
- ###############################################################
- """
- Alles hat einen Anfang
- """
wxScrolledWindow.__init__(self, parent, id,
pos, size,
style|wxWANTS_CHARS)
- # the syntax informations, if they don't exist,
- # all syntax stuff will be ignored
+ self.InitCoords()
+ self.InitFonts()
+ self.SetColors()
+ self.MapEvents()
+ self.LoadImages()
+ self.InitDoubleBuffering()
+ self.InitScrolling()
+ self.SelectOff()
+ self.CopiedData = None
+ self.SetFocus()
+ self.SetText([""])
+ self.SpacesPerTab = 4
+
+##------------------ Init stuff
- # cursor pos
+ def InitCoords(self):
self.cx = 0
self.cy = 0
-
- # the lines that are visible
- self.lines = []
- self.line = 0
- self.len = 0
-
- self.ocy = 0
-
- # border pos
- #self.bx = 0
- #self.by = 0
-
- # screen
+ self.oldCx = 0
+ self.oldCy = 0
self.sx = 0
self.sy = 0
self.sw = 0
self.sh = 0
- self.osx= 0
- self.osy= 0
-
- # font
- dc = wxClientDC(self)
-
- if wxPlatform == "__WXMSW__":
- self.font = wxFont(10, wxMODERN, wxNORMAL, wxNORMAL)
- else:
- self.font = wxFont(12, wxMODERN, wxNORMAL, wxNORMAL, false)
- dc.SetFont(self.font)
-
- # font weight, height
- self.fw = dc.GetCharWidth()
- self.fh = dc.GetCharHeight()
-
- # back, for colour
- self.bcol = wxNamedColour('white')
- self.fcol = wxNamedColour('black')
-
- self.cfcol = wxNamedColour('black')
- self.cbcol = wxNamedColour('red')
-
- # nicht edierbare zeile (hintergrund)
- self.nedcol = wxNamedColour('grey')
-
- self.SetBackgroundColour(self.bcol)
- #dc.SetForegroundColour(self.fcol)
+ self.sco_x = 0
+ self.sco_y = 0
- # events
- EVT_LEFT_DOWN(self, self.OnMouseClick)
- EVT_RIGHT_DOWN(self, self.OnMouseClick)
+ def MapEvents(self):
+ EVT_LEFT_DOWN(self, self.OnLeftDown)
+ EVT_LEFT_UP(self, self.OnLeftUp)
+ EVT_MOTION(self, self.OnMotion)
EVT_SCROLLWIN(self, self.OnScroll)
EVT_CHAR(self, self.OnChar)
EVT_PAINT(self, self.OnPaint)
+ EVT_SIZE(self, self.OnSize)
+ EVT_WINDOW_DESTROY(self, self.OnDestroy)
- self.o_cx = self.cx
- self.o_cy = self.cy
- self.o_sx = self.sx
- self.o_sy = self.sy
- self.o_line = self.line
- self.sco_x = 0
- self.sco_y = 0
-
- self.tabsize = 4
+##------------------- Platform-specific stuff
- self.update = true
- self.in_scroll =FALSE
- self.inUpdate = FALSE
-
-
- bw,bh = self.GetSizeTuple()
- # double buffering
- self.mdc = wxMemoryDC()
- self.mdc.SelectObject(wxEmptyBitmap(bw,bh))
- # disable physical scrolling because invisible parts are not drawn
- self.EnableScrolling(FALSE, FALSE)
-
- # the ordinary text as it is
- self.SetText()
+ def NiceFontForPlatform(self):
+ if wxPlatform == "__WXMSW__":
+ return wxFont(10, wxMODERN, wxNORMAL, wxNORMAL)
+ else:
+ return wxFont(12, wxMODERN, wxNORMAL, wxNORMAL, false)
+
+ def UnixKeyHack(self, key):
+ # this will be obsolete when we get the new wxWindows patch
+ if key <= 26:
+ key += ord('a') - 1
+ return key
+
+##-------------------- UpdateView/Cursor code
+
+ def OnSize(self, event):
+ self.AdjustScrollbars()
self.SetFocus()
+ def SetCharDimensions(self):
+ # TODO: We need a code review on this. It appears that Linux
+ # improperly reports window dimensions when the scrollbar's there.
+ self.bw, self.bh = self.GetClientSizeTuple()
-#---------------------------------------------------------------------------
-
- def CalcLines(self):
- ###############################################################
- self.lines = []
- x =maxlen =0
- for line in self.text:
- if line.visible==0:
- self.lines.append(x)
- else:
- if len(line.text) >maxlen:
- maxlen =len(line.text)
- x = x + 1
- self.len = len(self.lines)
- self.max_linelength =maxlen
-
-
- def SetFontTab(self, fonttab):
- ###############################################################
- """ Fonttabelle zum schnellen Zugriff """
- self.ftab = fonttab
-
-
- def SetText(self, text = [""]):
- ###############################################################
- """ Text mittels Liste setzen """
- self.cx = 0
- self.cy = 0
- self.text = []
-
- for t in text:
- self.text.append(Line(t))
-
- for l in range(0,len(text)-1):
- #self.UpdateSyntax(l)
- self.OnUpdateHighlight(l)
-
- self.OnInit()
-
- self.update = true
- self.UpdateView(None, true)
-
-
- # show new text
- def GetText(self):
- ###############################################################
- """ Der gesamte Text als Liste """
- text = []
- for line in self.text:
- text.append(line.text)
- return text
-
+ if wxPlatform == "__WXMSW__":
+ self.sh = self.bh / self.fh
+ self.sw = (self.bw / self.fw) - 1
+ else:
+ self.sh = self.bh / self.fh
+ if self.LinesInFile() >= self.sh:
+ self.bw = self.bw - wxSystemSettings_GetSystemMetric(wxSYS_VSCROLL_X)
+ self.sw = (self.bw / self.fw) - 1
- def IsEmpty(self):
- ###############################################################
- """see if at least one text line is not empty"""
- for line in self.text:
- if line.text: return 0
- return 1
+ self.sw = (self.bw / self.fw) - 1
+ if self.CalcMaxLineLen() >= self.sw:
+ self.bh = self.bh - wxSystemSettings_GetSystemMetric(wxSYS_HSCROLL_Y)
+ self.sh = self.bh / self.fh
- def IsLine(self, line):
- ###############################################################
- """ Schauen, ob alles im grünen Bereich ist """
- return (line>=0) and (line<self.len)
+ def UpdateView(self, dc = None):
+ if not dc:
+ dc = wxClientDC(self)
+ self.SetCharDimensions()
+ self.KeepCursorOnScreen()
+ self.DrawSimpleCursor(0,0,dc, true)
+ self.Draw(dc)
+
+ def OnPaint(self, event):
+ dc = wxPaintDC(self)
+ self.UpdateView(dc)
+ self.AdjustScrollbars()
+##-------------------- Drawing code
- def IsEditable(self, line):
- ###############################################################
- return self.text[self.GetLine(line)].editable
+ def InitFonts(self):
+ dc = wxClientDC(self)
+ self.font = self.NiceFontForPlatform()
+ dc.SetFont(self.font)
+ self.fw = dc.GetCharWidth()
+ self.fh = dc.GetCharHeight()
+ def SetColors(self):
+ self.fgColor = wxNamedColour('black')
+ self.bgColor = wxNamedColour('white')
+ self.selectColor = wxColour(238, 220, 120) # r, g, b = emacsOrange
- def GetLine(self, line):
- ###############################################################
- return self.lines[line]
+ def InitDoubleBuffering(self):
+ bw,bh = self.GetClientSizeTuple()
+ self.mdc = wxMemoryDC()
+ self.mdc.SelectObject(wxEmptyBitmap(bw,bh))
+ def DrawEditText(self, t, x, y, dc):
+ dc.DrawText(t, x * self.fw, y * self.fh)
- def GetTextLine(self, line):
- ###############################################################
- """ Text holen """
+ def DrawLine(self, line, dc):
if self.IsLine(line):
- return self.text[self.GetLine(line)].text
- return ""
-
+ l = line
+ t = self.lines[l]
+ dc.SetTextForeground(self.fgColor)
+ fragments = selection.Selection(
+ self.SelectBegin, self.SelectEnd,
+ self.sx, self.sw, line, t)
+ x = 0
+ for (data, selected) in fragments:
+ if selected:
+ dc.SetTextBackground(self.selectColor)
+ if x == 0 and len(data) == 0 and len(fragments) == 1:
+ data = ' '
+ else:
+ dc.SetTextBackground(self.bgColor)
+ self.DrawEditText(data, x, line - self.sy, dc)
+ x += len(data)
- def SetTextLine(self, line, text):
- ###############################################################
- """ Nur den Text ändern """
- if self.IsLine(line):
- l = self.GetLine(line)
- self.text[l].text = text
- #self.UpdateSyntax(l)
- self.OnUpdateHighlight(l)
- self.update = true
+ def Draw(self, odc=None):
+ if not odc:
+ odc = wxClientDC(self)
+ dc = self.mdc
+ dc.SetFont(self.font)
+ dc.SelectObject(wxEmptyBitmap(self.bw,self.bh))
+ dc.SetBackgroundMode(wxSOLID)
+ dc.SetTextBackground(self.bgColor)
+ dc.SetTextForeground(self.fgColor)
+ dc.Clear()
+ for line in range(self.sy, self.sy + self.sh):
+ self.DrawLine(line, dc)
+ if len(self.lines) < self.sh + self.sy:
+ self.DrawEofMarker(dc)
+ odc.Blit(0,0,self.bw,self.bh,dc,0,0,wxCOPY)
+ self.DrawCursor(odc)
-#---------------------------------------------------------------------------
+##------------------ eofMarker stuff
- def OnMouseClick(self, event):
- ###############################################################
- """
- Wenn es Click gemacht hat => Cursor setzen
- """
- self.SetFocus()
+ def LoadImages(self):
+ self.eofMarker = images.GetBitmap(images.EofImageData)
- self.cy = self.sy + (event.GetY() / self.fh)
- if self.cy >= self.len: self.cy =max(self.len -1, 0)
- linelen =len(self.text[self.GetLine(self.cy)].text)
- self.cx = self.sx + (event.GetX() / self.fw)
- # allow positioning right behind the last character
- if self.cx > linelen: self.cx =linelen
- if event.GetEventType() ==wxEVT_RIGHT_DOWN:
- self.update = true
- self.OnFold()
- self.UpdateView()
+ def DrawEofMarker(self,dc):
+ x = 0
+ y = (len(self.lines) - self.sy) * self.fh
+ hasTransparency = 1
+ dc.DrawBitmap(self.eofMarker, x, y, hasTransparency)
+##------------------ cursor-related functions
def DrawCursor(self, dc = None):
- ###############################################################
- """
- Auch der Cursor muß ja irgendwie gezeichnet werden
- """
if not dc:
dc = wxClientDC(self)
- if (self.len)<self.cy: #-1 ?
- self.cy = self.len-1
- s = self.text[self.GetLine(self.cy)].text
+ if (self.LinesInFile())<self.cy: #-1 ?
+ self.cy = self.LinesInFile()-1
+ s = self.lines[self.cy]
x = self.cx - self.sx
y = self.cy - self.sy
def DrawSimpleCursor(self, xp, yp, dc = None, old=false):
- ###############################################################
- """
- Auch der Cursor muß ja irgendwie gezeichnet werden
- """
if not dc:
dc = wxClientDC(self)
self.sco_x = xp
self.sco_y = yp
+##-------- Enforcing screen boundaries, cursor movement
+
+ def CalcMaxLineLen(self):
+ """get length of longest line on screen"""
+ maxlen = 0
+ for line in self.lines[self.sy:self.sy+self.sh]:
+ if len(line) >maxlen:
+ maxlen = len(line)
+ return maxlen
+
+ def KeepCursorOnScreen(self):
+ self.sy = ForceBetween(max(0, self.cy-self.sh), self.sy, self.cy)
+ self.sx = ForceBetween(max(0, self.cx-self.sw), self.sx, self.cx)
+ self.AdjustScrollbars()
+
+ def HorizBoundaries(self):
+ self.SetCharDimensions()
+ maxLineLen = self.CalcMaxLineLen()
+ self.sx = ForceBetween(0, self.sx, max(self.sw, maxLineLen - self.sw + 1))
+ self.cx = ForceBetween(self.sx, self.cx, self.sx + self.sw - 1)
+
+ def VertBoundaries(self):
+ self.SetCharDimensions()
+ self.sy = ForceBetween(0, self.sy, max(self.sh, self.LinesInFile() - self.sh + 1))
+ self.cy = ForceBetween(self.sy, self.cy, self.sy + self.sh - 1)
+
+ def cVert(self, num):
+ self.cy = self.cy + num
+ self.cy = ForceBetween(0, self.cy, self.LinesInFile() - 1)
+ self.sy = ForceBetween(self.cy - self.sh + 1, self.sy, self.cy)
+ self.cx = min(self.cx, self.CurrentLineLength())
- def OnScroll(self, event):
- dir =event.GetOrientation()
- evt =event.GetEventType()
- if dir ==wxHORIZONTAL:
- if evt ==wxEVT_SCROLLWIN_LINEUP: self.sx =self.sx -1
- elif evt ==wxEVT_SCROLLWIN_LINEDOWN: self.sx =self.sx +1
- elif evt ==wxEVT_SCROLLWIN_PAGEUP: self.sx =self.sx -self.sw
- elif evt ==wxEVT_SCROLLWIN_PAGEDOWN: self.sx =self.sx +self.sw
- elif evt ==wxEVT_SCROLLWIN_TOP: self.sx =self.cx =0
- elif evt ==wxEVT_SCROLLWIN_BOTTOM:
- self.sx =self.max_linelength -self.sw
- self.cx =self.max_linelength
- else:
- self.sx =event.GetPosition()
-
- if self.sx >(self.max_linelength -self.sw +1):
- self.sx =self.max_linelength -self.sw +1
- if self.sx <0: self.sx =0
- if self.cx >(self.sx +self.sw -1): self.cx =self.sx +self.sw -1
- if self.cx <self.sx: self.cx =self.sx
-
- else:
- if evt ==wxEVT_SCROLLWIN_LINEUP: self.sy =self.sy -1
- elif evt ==wxEVT_SCROLLWIN_LINEDOWN: self.sy =self.sy +1
- elif evt ==wxEVT_SCROLLWIN_PAGEUP: self.sy =self.sy -self.sh
- elif evt ==wxEVT_SCROLLWIN_PAGEDOWN: self.sy =self.sy +self.sh
- elif evt ==wxEVT_SCROLLWIN_TOP: self.sy =self.cy =0
- elif evt ==wxEVT_SCROLLWIN_BOTTOM:
- self.sy =self.len -self.sh
- self.cy =self.len
- else:
- self.sy =event.GetPosition()
-
- if self.sy >(self.len -self.sh +1):
- self.sy =self.len -self.sh +1
- if self.sy <0: self.sy =0
- if self.cy >(self.sy +self.sh -1): self.cy =self.sy +self.sh -1
- if self.cy <self.sy: self.cy =self.sy
-
- self.UpdateView()
-
-
- def AdjustScrollbars(self):
- # there appears to be endless recursion:
- # SetScrollbars issue EvtPaint which calls UpdateView
- # which calls AdjustScrollbars
- if not self.in_scroll:
- self.in_scroll =TRUE
- self.SetScrollbars(self.fw, self.fh, self.max_linelength +1,
- # it seem to be a bug in scrollbars:
- # the scrollbar is hidden
- # even if current position >0
- max(self.len +1, self.sy +self.sh),
- self.sx, self.sy)
- self.osx, self.osy = self.sx, self.sy
- self.in_scroll =FALSE
-
-
- # adapts the output to what it should be
- def UpdateView(self, dc = None, doup=false):
- ###############################################################
- """
- Diese Routine wird immer dann aufgerufen, wenn
- sich etwas verändert hat
- """
- if self.inUpdate:
- return
- self.inUpdate = true
-
- self.CalcLines()
+ def cHoriz(self, num):
+ self.cx = self.cx + num
+ self.cx = ForceBetween(0, self.cx, self.CurrentLineLength())
+ self.sx = ForceBetween(self.cx - self.sw + 1, self.sx, self.cx)
- if not dc:
- dc = wxClientDC(self)
+ def AboveScreen(self, row):
+ return row < self.sy
- self.bw,self.bh = self.GetSizeTuple()
- self.sw = self.bw / self.fw
- self.sh = self.bh / self.fh
+ def BelowScreen(self, row):
+ return row >= self.sy + self.sh
- if self.cy<self.sy:
- self.sy = self.cy
- elif self.cy>(self.sy+self.sh-1):
- self.sy = self.cy-self.sh+1
+ def LeftOfScreen(self, col):
+ return col < self.sx
- if self.cx<self.sx:
- self.sx = self.cx
- elif self.cx>(self.sx+self.sw-1):
- self.sx = self.cx-self.sw+1
+ def RightOfScreen(self, col):
+ return col >= self.sx + self.sw
- # left line? change syntax!
- if self.ocy!=self.cy:
- self.OnUpdateSyntax(self.ocy)
- self.ocy = self.cy
+##----------------- data structure helper functions
- # alles beim alten
- if self.osx != self.sx or self.osy != self.sy:
- self.AdjustScrollbars()
+ def GetText(self):
+ return self.lines
+
+ def SetText(self, lines):
+ self.InitCoords()
+ self.lines = lines
+ self.UnTouchBuffer()
+ self.SelectOff()
+ self.AdjustScrollbars()
+ self.UpdateView(None)
+
+ def IsLine(self, lineNum):
+ return (0<=lineNum) and (lineNum<self.LinesInFile())
+
+ def GetTextLine(self, lineNum):
+ if self.IsLine(lineNum):
+ return self.lines[lineNum]
+ return ""
- self.DrawSimpleCursor(0,0,dc, true)
- # [als] i don't really understand how the following condition works
- #if self.update or doup:
- self.Draw(dc)
- # self.update = false
- #else:
- # self.DrawCursor(dc)
+ def SetTextLine(self, lineNum, text):
+ if self.IsLine(lineNum):
+ self.lines[lineNum] = text
- self.o_cx = self.cx
- self.o_cy = self.cy
- self.o_sx = self.sx
- self.o_sy = self.sy
- self.o_line = self.line
- self.inUpdate = false
+ def CurrentLineLength(self):
+ return len(self.lines[self.cy])
+ def LinesInFile(self):
+ return len(self.lines)
+ def UnTouchBuffer(self):
+ self.bufferTouched = FALSE
+ def BufferWasTouched(self):
+ return self.bufferTouched
- def DrawEditText(self, t, x, y, dc = None):
- ###############################################################
- """ Einfache Hilfsroutine um Text zu schreiben
- """
- if not dc:
- dc = wxClientDC(self)
- dc.SetFont(self.font)
- dc.DrawText(t, x * self.fw, y * self.fh)
+ def TouchBuffer(self):
+ self.bufferTouched = TRUE
+
+##-------------------------- Mouse scroll timing functions
- def DrawLine(self, line, dc=None):
- ###############################################################
- """
- Hier wird einfach die Ansicht der ganzen Seite
- wiederhergestellt.
- !!! Kann modifiziert werden !!!
- """
+ def InitScrolling(self):
+ # we don't rely on the windows system to scroll for us; we just
+ # redraw the screen manually every time
+ self.EnableScrolling(FALSE, FALSE)
+ self.nextScrollTime = 0
+ self.SCROLLDELAY = 0.050 # seconds
+ self.scrollTimer = wxTimer(self)
+ self.scroller = Scroller(self)
+
+ def CanScroll(self):
+ if time.time() > self.nextScrollTime:
+ self.nextScrollTime = time.time() + self.SCROLLDELAY
+ return true
+ else:
+ return false
+
+ def SetScrollTimer(self):
+ oneShot = true
+ self.scrollTimer.Start(1000*self.SCROLLDELAY/2, oneShot)
+ EVT_TIMER(self, -1, self.OnTimer)
+
+ def OnTimer(self, event):
+ screenX, screenY = wxGetMousePosition()
+ x, y = self.ScreenToClientXY(screenX, screenY)
+ self.MouseToRow(y)
+ self.MouseToCol(x)
+ self.SelectUpdate()
+
+##-------------------------- Mouse off screen functions
+
+ def HandleAboveScreen(self, row):
+ self.SetScrollTimer()
+ if self.CanScroll():
+ row = self.sy - 1
+ row = max(0, row)
+ self.cy = row
+
+ def HandleBelowScreen(self, row):
+ self.SetScrollTimer()
+ if self.CanScroll():
+ row = self.sy + self.sh
+ row = min(row, self.LinesInFile() - 1)
+ self.cy = row
+
+ def HandleLeftOfScreen(self, col):
+ self.SetScrollTimer()
+ if self.CanScroll():
+ col = self.sx - 1
+ col = max(0,col)
+ self.cx = col
+
+ def HandleRightOfScreen(self, col):
+ self.SetScrollTimer()
+ if self.CanScroll():
+ col = self.sx + self.sw
+ col = min(col, self.CurrentLineLength())
+ self.cx = col
+
+##------------------------ mousing functions
+
+ def MouseToRow(self, mouseY):
+ row = self.sy + (mouseY/ self.fh)
+ if self.AboveScreen(row):
+ self.HandleAboveScreen(row)
+ elif self.BelowScreen(row):
+ self.HandleBelowScreen(row)
+ else:
+ self.cy = min(row, self.LinesInFile() - 1)
+
+ def MouseToCol(self, mouseX):
+ col = self.sx + (mouseX / self.fw)
+ if self.LeftOfScreen(col):
+ self.HandleLeftOfScreen(col)
+ elif self.RightOfScreen(col):
+ self.HandleRightOfScreen(col)
+ else:
+ self.cx = min(col, self.CurrentLineLength())
+
+ def MouseToCursor(self, event):
+ self.MouseToRow(event.GetY())
+ self.MouseToCol(event.GetX())
+
+ def OnMotion(self, event):
+ if event.LeftIsDown():
+ self.Selecting = true
+ self.MouseToCursor(event)
+ self.SelectUpdate()
+
+ def OnLeftDown(self, event):
+ self.MouseToCursor(event)
+ self.SelectBegin = (self.cy, self.cx)
+ self.SelectEnd = None
+ self.UpdateView()
+ self.CaptureMouse()
- if not dc:
- dc = wxClientDC(self)
+ def OnLeftUp(self, event):
+ if self.SelectEnd is None:
+ self.OnClick()
+ else:
+ self.Selecting = false
+ self.SelectNotify(false, self.SelectBegin, self.SelectEnd)
+
+ self.ReleaseMouse()
+ self.scrollTimer.Stop()
+
+
+#------------------------- Scrolling
+
+ def HorizScroll(self, event, eventType):
+ maxLineLen = self.CalcMaxLineLen()
+
+ if eventType == wxEVT_SCROLLWIN_LINEUP:
+ self.sx -= 1
+ elif eventType == wxEVT_SCROLLWIN_LINEDOWN:
+ self.sx += 1
+ elif eventType == wxEVT_SCROLLWIN_PAGEUP:
+ self.sx -= self.sw
+ elif eventType == wxEVT_SCROLLWIN_PAGEDOWN:
+ self.sx += self.sw
+ elif eventType == wxEVT_SCROLLWIN_TOP:
+ self.sx = self.cx = 0
+ elif eventType == wxEVT_SCROLLWIN_BOTTOM:
+ self.sx = maxLineLen - self.sw
+ self.cx = maxLineLen
+ else:
+ self.sx = event.GetPosition()
+
+ self.HorizBoundaries()
+
+ def VertScroll(self, event, eventType):
+ if eventType == wxEVT_SCROLLWIN_LINEUP:
+ self.sy -= 1
+ elif eventType == wxEVT_SCROLLWIN_LINEDOWN:
+ self.sy += 1
+ elif eventType == wxEVT_SCROLLWIN_PAGEUP:
+ self.sy -= self.sh
+ elif eventType == wxEVT_SCROLLWIN_PAGEDOWN:
+ self.sy += self.sh
+ elif eventType == wxEVT_SCROLLWIN_TOP:
+ self.sy = self.cy = 0
+ elif eventType == wxEVT_SCROLLWIN_BOTTOM:
+ self.sy = self.LinesInFile() - self.sh
+ self.cy = self.LinesInFile()
+ else:
+ self.sy = event.GetPosition()
+
+ self.VertBoundaries()
- dc.SetBackgroundMode(wxSOLID)
- dc.SetTextBackground(self.bcol)
- dc.SetTextForeground(self.fcol)
- #dc.Clear()
+ def OnScroll(self, event):
+ dir = event.GetOrientation()
+ eventType = event.GetEventType()
+ if dir == wxHORIZONTAL:
+ self.HorizScroll(event, eventType)
+ else:
+ self.VertScroll(event, eventType)
+ self.UpdateView()
- # delimiter
- ll = self.sx
- lr = self.sx + self.sw
- y = line - self.sy
- # text + syntax
- if self.IsLine(line):
- l = self.GetLine(line)
- t = self.text[l].text
- syn = self.text[l].syntax
+ def AdjustScrollbars(self):
+ for i in range(2):
+ self.SetCharDimensions()
+ self.scroller.SetScrollbars(
+ self.fw, self.fh,
+ self.CalcMaxLineLen()+3, max(self.LinesInFile()+1, self.sh),
+ self.sx, self.sy)
+
+#------------ backspace, delete, return
+
+ def BreakLine(self, event):
+ if self.IsLine(self.cy):
+ t = self.lines[self.cy]
+ self.lines = self.lines[:self.cy] + [t[:self.cx],t[self.cx:]] + self.lines[self.cy+1:]
+ self.cVert(1)
+ self.cx = 0
+ self.TouchBuffer()
- if not self.text[l].editable:
- dc.SetTextBackground(self.nedcol)
+ def InsertChar(self,char):
+ if self.IsLine(self.cy):
+ t = self.lines[self.cy]
+ t = t[:self.cx] + char + t[self.cx:]
+ self.SetTextLine(self.cy, t)
+ self.cHoriz(1)
+ self.TouchBuffer()
+
+ def JoinLines(self):
+ t1 = self.lines[self.cy]
+ t2 = self.lines[self.cy+1]
+ self.cx = len(t1)
+ self.lines = self.lines[:self.cy] + [t1 + t2] + self.lines[self.cy+2:]
+ self.TouchBuffer()
+
+
+ def DeleteChar(self,x,y,oldtext):
+ newtext = oldtext[:x] + oldtext[x+1:]
+ self.SetTextLine(y, newtext)
+ self.TouchBuffer()
+
+
+ def BackSpace(self, event):
+ t = self.GetTextLine(self.cy)
+ if self.cx>0:
+ self.DeleteChar(self.cx-1,self.cy,t)
+ self.cHoriz(-1)
+ self.TouchBuffer()
+ elif self.cx == 0:
+ if self.cy > 0:
+ self.cy -= 1
+ self.JoinLines()
+ self.TouchBuffer()
else:
- dc.SetTextBackground(self.bcol)
+ wxBell()
+
+ def Delete(self, event):
+ t = self.GetTextLine(self.cy)
+ if self.cx<len(t):
+ self.DeleteChar(self.cx,self.cy,t)
+ self.TouchBuffer()
+ else:
+ if self.cy < len(self.lines) - 1:
+ self.JoinLines()
+ self.TouchBuffer()
- dc.SetTextForeground(self.fcol)
+ def Escape(self, event):
+ self.SelectOff()
- pos = ll
- for h in syn:
- xp, col = h
- if xp>=ll:
- self.DrawEditText(t[pos:xp], (pos-ll), y, dc)
- pos = xp
- dc.SetTextForeground(self.ftab[col])
- self.DrawEditText(t[pos:], (pos-ll), y, dc)
+ def TabKey(self, event):
+ numSpaces = self.SpacesPerTab - (self.cx % self.SpacesPerTab)
+ self.SingleLineInsert(' ' * numSpaces)
+##----------- selection routines
- def Draw(self, odc=None):
- ###############################################################
- """
- Hier wird einfach die Ansicht der ganzen Seite
- wiederhergestellt.
- !!! Kann modifiziert werden !!!
- """
+ def SelectUpdate(self):
+ self.SelectEnd = (self.cy, self.cx)
+ self.SelectNotify(self.Selecting, self.SelectBegin, self.SelectEnd)
+ self.UpdateView()
- if not odc:
- odc = wxClientDC(self)
+ def NormalizedSelect(self):
+ (begin, end) = (self.SelectBegin, self.SelectEnd)
+ (bRow, bCol) = begin
+ (eRow, eCol) = end
+ if (bRow < eRow):
+ return (begin, end)
+ elif (eRow < bRow):
+ return (end, begin)
+ else:
+ if (bCol < eCol):
+ return (begin, end)
+ else:
+ return (end, begin)
+
+ def FindSelection(self):
+ if self.SelectEnd is None or self.SelectBegin is None:
+ wxBell()
+ return None
+ (begin, end) = self.NormalizedSelect()
+ (bRow, bCol) = begin
+ (eRow, eCol) = end
+ return (bRow, bCol, eRow, eCol)
+
+ def SelectOff(self):
+ self.SelectBegin = None
+ self.SelectEnd = None
+ self.Selecting = false
+ self.SelectNotify(false,None,None)
+
+ def CopySelection(self, event):
+ selection = self.FindSelection()
+ if selection is None:
+ return
+ (bRow, bCol, eRow, eCol) = selection
+
+ if bRow == eRow:
+ self.SingleLineCopy(bRow, bCol, eCol)
+ else:
+ self.MultipleLineCopy(bRow, bCol, eRow, eCol)
+
+ def OnCopySelection(self, event):
+ self.CopySelection(event)
+ self.SelectOff()
+
+ def CopyData(self, data):
+ self.CopiedData = data
+
+ def SingleLineCopy(self, Row, bCol, eCol):
+ Line = self.GetTextLine(Row)
+ self.CopyData([Line[bCol:eCol]])
+
+ def MultipleLineCopy(self, bRow, bCol, eRow, eCol):
+ bLine = self.GetTextLine(bRow)[bCol:]
+ eLine = self.GetTextLine(eRow)[:eCol]
+ self.CopyData([bLine] + [l for l in self.lines[bRow + 1:eRow]] + [eLine])
+
+ def OnDeleteSelection(self, event):
+ selection = self.FindSelection()
+ if selection is None:
+ return
+ (bRow, bCol, eRow, eCol) = selection
+
+ if bRow == eRow:
+ self.SingleLineDelete(bRow, bCol, eCol)
+ else:
+ self.MultipleLineDelete(bRow, bCol, eRow, eCol)
- dc = self.mdc
- dc.SelectObject(wxEmptyBitmap(self.bw,self.bh))
- dc.SetBackgroundMode(wxSOLID)
- dc.SetTextBackground(self.bcol)
- dc.SetTextForeground(self.fcol)
- dc.Clear()
- for line in range(self.sy, self.sy + self.sh): self.DrawLine(line, dc)
- odc.Blit(0,0,self.bw,self.bh,dc,0,0,wxCOPY)
- self.DrawCursor(odc)
+ self.TouchBuffer()
+ self.cy = bRow
+ self.cx = bCol
+ self.SelectOff()
+ self.UpdateView()
- def cVert(self, num):
- ###############################################################
- """ Vertikale Cursorverschiebung
- """
- cy = self.cy + num
- if cy <0: cy =0
- elif cy >(self.len -1): cy =self.len -1
- # scroll when edge hit
- if cy >(self.sy +self.sh -1): self.sy =cy -self.sh +1
- elif cy <self.sy: self.sy =cy
- self.cy =cy
- # disallow positioning behind the end of the line
- linelen =len(self.text[self.GetLine(cy)].text)
- if self.cx >linelen: self.cx =linelen
+ def SingleLineDelete(self, Row, bCol, eCol):
+ ModLine = self.GetTextLine(Row)
+ ModLine = ModLine[:bCol] + ModLine[eCol:]
+ self.SetTextLine(Row,ModLine)
- def cHoriz(self, num):
- ###############################################################
- """ Horizontale Cursorverschiebung
- """
- cx = self.cx + num
- linelen =len(self.text[self.GetLine(self.cy)].text)
- if cx <0: cx =0
- elif cx >linelen: cx =linelen
- # scroll when edge hit
- if cx >(self.sx +self.sw -2): self.sx =cx -self.sw +2
- elif cx <self.sx: self.sx =cx
- self.cx =cx
-
-
- def InsertText(self, text):
- ###############################################################
- """
- Simple Routine um Text - auch über mehrere
- Zeilen - einzufügen
- """
-
- if self.IsEditable(self.cy):
- tis = split(text, "\n")
-
- t = self.GetTextLine(self.cy)
-
- if len(tis)==1:
- t = t[:self.cx] + text + t[self.cx:]
- self.SetTextLine(self.cy, t)
- self.cHoriz(len(text))
- else:
- rest = t[self.cx:]
- t = t[:self.cx] + tis[0]
- self.SetTextLine(self.cy, t)
- for i in range(1,len(tis)):
- self.text.insert(self.GetLine(self.cy)+1, Line())
- self.lines.insert(self.cy+1,self.GetLine(self.cy)+1)
- self.cVert(+1)
- self.SetTextLine(self.cy, tis[i])
- t = self.GetTextLine(self.cy)
- self.cx = len(t)
- t = t + rest
- self.SetTextLine(self.cy, t)
- self.update = true
- #self.UpdateView()
-
-#-----------------------------------------------------------------------------------------
-
- def RemoveLine(self, line):
- pass
+ def MultipleLineDelete(self, bRow, bCol, eRow, eCol):
+ bLine = self.GetTextLine(bRow)
+ eLine = self.GetTextLine(eRow)
+ ModLine = bLine[:bCol] + eLine[eCol:]
+ self.lines[bRow:eRow + 1] = [ModLine]
+ def OnPaste(self, event):
+ if self.CopiedData is None:
+ wxBell()
+ return
+ elif len(self.CopiedData) == 0:
+ wxBell()
+ return
+ elif len(self.CopiedData) == 1:
+ self.SingleLineInsert(self.CopiedData[0])
+ else:
+ self.MultipleLinePaste()
+
+ def SingleLineInsert(self, newText):
+ ModLine = self.GetTextLine(self.cy)
+ ModLine = ModLine[:self.cx] + newText + ModLine[self.cx:]
+ self.SetTextLine(self.cy, ModLine)
+ self.cHoriz(len(newText))
+ self.TouchBuffer()
+ self.UpdateView()
- def OnChar(self, event):
- ###############################################################
- """
- Wenn eine Taste gedrückt wird,
- kann an dieser Stelle die Auswertung stattfinden
- """
+ def MultipleLinePaste(self):
+ FirstLine = LastLine = self.GetTextLine(self.cy)
+ FirstLine = FirstLine[:self.cx] + self.CopiedData[0]
+ LastLine = self.CopiedData[-1] + LastLine[self.cx:]
- # get code
- key = event.KeyCode()
+ NewSlice = [FirstLine]
+ NewSlice += [l for l in self.CopiedData[1:-1]]
+ NewSlice += [LastLine]
+ self.lines[self.cy:self.cy + 1] = NewSlice
-# if event.ControlDown:
-# if chr(key)=="k":
-# print "weg"
+ self.cy = self.cy + len(self.CopiedData)-1
+ self.cx = len(self.CopiedData[-1])
+ self.TouchBuffer()
+ self.UpdateView()
+ def OnCutSelection(self,event):
+ self.CopySelection(event)
+ self.OnDeleteSelection(event)
+
+#-------------- Keyboard movement implementations
- # movements
- if key==WXK_DOWN:
- self.cVert(+1)
- elif key==WXK_UP:
- self.cVert(-1)
- elif key==WXK_LEFT:
- self.cHoriz(-1)
- elif key==WXK_RIGHT:
- self.cHoriz(+1)
+ def MoveDown(self, event):
+ self.cVert(+1)
- elif key==WXK_NEXT:
- self.cVert(self.sh)
- elif key==WXK_PRIOR:
- self.cVert(-self.sh)
+ def MoveUp(self, event):
+ self.cVert(-1)
- elif key==WXK_HOME:
- self.cx = 0
- elif key==WXK_END:
- self.cx = len(self.GetTextLine(self.cy))
-
- elif key==WXK_BACK:
- t = self.GetTextLine(self.cy)
- if self.cx>0:
- t = t[:self.cx-1] + t[self.cx:]
- self.SetTextLine(self.cy, t)
- self.cHoriz(-1)
-
- elif key==WXK_DELETE:
- t = self.GetTextLine(self.cy)
- if self.cx<len(t):
- t = t[:self.cx] + t[self.cx+1:]
- self.SetTextLine(self.cy, t)
+ def MoveLeft(self, event):
+ if self.cx == 0:
+ if self.cy == 0:
+ wxBell()
+ else:
+ self.cVert(-1)
+ self.cx = self.CurrentLineLength()
+ else:
+ self.cx -= 1
- elif key==WXK_RETURN:
- self.InsertText("\n")
+ def MoveRight(self, event):
+ linelen = self.CurrentLineLength()
+ if self.cx == linelen:
+ if self.cy == len(self.lines) - 1:
+ wxBell()
+ else:
+ self.cx = 0
+ self.cVert(1)
+ else:
+ self.cx += 1
+
- elif key==WXK_TAB:
- self.OnTabulator(event)
+ def MovePageDown(self, event):
+ self.cVert(self.sh)
- # clipboard (buggy)
- elif key==WXK_F10:
- if wxTheClipboard.Open():
- data = wxTheClipboard.GetData()
- wxTheClipboard.Close()
- print data
+ def MovePageUp(self, event):
+ self.cVert(-self.sh)
- # folding (buggy)
- elif key==WXK_F12:
- self.update = true
- self.OnFold()
+ def MoveHome(self, event):
+ self.cx = 0
- # regular ascii
- elif (key>31) and (key<256):
- self.InsertText(chr(key))
+ def MoveEnd(self, event):
+ self.cx = self.CurrentLineLength()
- self.UpdateView()
- return 0
+ def MoveStartOfFile(self, event):
+ self.cy = 0
+ self.cx = 0
+ def MoveEndOfFile(self, event):
+ self.cy = len(self.lines) - 1
+ self.cx = self.CurrentLineLength()
- def OnPaint(self, event):
- dc = wxPaintDC(self)
- self.bw,self.bh = self.GetSizeTuple()
- self.UpdateView(dc, true)
+#-------------- Key handler mapping tables
+ def SetMoveSpecialFuncs(self, action):
+ action[WXK_DOWN] = self.MoveDown
+ action[WXK_UP] = self.MoveUp
+ action[WXK_LEFT] = self.MoveLeft
+ action[WXK_RIGHT] = self.MoveRight
+ action[WXK_NEXT] = self.MovePageDown
+ action[WXK_PRIOR] = self.MovePageUp
+ action[WXK_HOME] = self.MoveHome
+ action[WXK_END] = self.MoveEnd
-#-----------------------------------------------------------------------------------------
+ def SetMoveSpecialControlFuncs(self, action):
+ action[WXK_HOME] = self.MoveStartOfFile
+ action[WXK_END] = self.MoveEndOfFile
- def GetIndent(self, line):
- p = 0
- for c in line:
- if c==" ": p = p + 1
- elif c=="\t": p =(p /self.tabsize +1) *self.tabsize
- else: break
- return p
+ def SetAltFuncs(self, action):
+ # subclass implements
+ pass
+ def SetControlFuncs(self, action):
+ action['c'] = self.OnCopySelection
+ action['d'] = self.OnDeleteSelection
+ action['v'] = self.OnPaste
+ action['x'] = self.OnCutSelection
+
+ def SetSpecialControlFuncs(self, action):
+ action[WXK_INSERT] = self.OnCopySelection
+
+ def SetShiftFuncs(self, action):
+ action[WXK_DELETE] = self.OnCutSelection
+ action[WXK_INSERT] = self.OnPaste
+
+ def SetSpecialFuncs(self, action):
+ action[WXK_BACK] = self.BackSpace
+ action[WXK_DELETE] = self.Delete
+ action[WXK_RETURN] = self.BreakLine
+ action[WXK_ESCAPE] = self.Escape
+ action[WXK_TAB] = self.TabKey
+
+##-------------- Logic for key handlers
+
+
+ def Move(self, keySettingFunction, key, event):
+ action = {}
+ keySettingFunction(action)
+
+ if not action.has_key(key):
+ return false
+
+ if event.ShiftDown():
+ if not self.Selecting:
+ self.Selecting = true
+ self.SelectBegin = (self.cy, self.cx)
+ action[key](event)
+ self.SelectEnd = (self.cy, self.cx)
+ else:
+ action[key](event)
+ if self.Selecting:
+ self.Selecting = false
+
+ self.SelectNotify(self.Selecting, self.SelectBegin, self.SelectEnd)
+ self.UpdateView()
+ return true
+
+ def MoveSpecialKey(self, event, key):
+ return self.Move(self.SetMoveSpecialFuncs, key, event)
+
+ def MoveSpecialControlKey(self, event, key):
+ if not event.ControlDown():
+ return false
+ return self.Move(self.SetMoveSpecialControlFuncs, key, event)
+
+ def Dispatch(self, keySettingFunction, key, event):
+ action = {}
+ keySettingFunction(action)
+ if action.has_key(key):
+ action[key](event)
+ self.UpdateView()
+ return true
+ return false
+
+ def ModifierKey(self, key, event, modifierKeyDown, MappingFunc):
+ if not modifierKeyDown:
+ return false
+
+ key = self.UnixKeyHack(key)
+ try:
+ key = chr(key)
+ except:
+ return false
+ if not self.Dispatch(MappingFunc, key, event):
+ wxBell()
+ return true
+
+ def ControlKey(self, event, key):
+ return self.ModifierKey(key, event, event.ControlDown(), self.SetControlFuncs)
+
+ def AltKey(self, event, key):
+ return self.ModifierKey(key, event, event.AltDown(), self.SetAltFuncs)
+
+ def SpecialControlKey(self, event, key):
+ if not event.ControlDown():
+ return false
+ if not self.Dispatch(self.SetSpecialControlFuncs, key, event):
+ wxBell()
+ return true
+
+ def ShiftKey(self, event, key):
+ if not event.ShiftDown():
+ return false
+ return self.Dispatch(self.SetShiftFuncs, key, event)
+
+ def NormalChar(self, event, key):
+ self.SelectOff()
- def Goto(self, pos):
- self.cVert(pos-self.cy-1)
+ # regular ascii
+ if not self.Dispatch(self.SetSpecialFuncs, key, event):
+ if (key>31) and (key<256):
+ self.InsertChar(chr(key))
+ else:
+ wxBell()
+ return
self.UpdateView()
+ self.AdjustScrollbars()
-# --------------------------------------------------------
+ def OnChar(self, event):
+ key = event.KeyCode()
+ filters = [self.AltKey,
+ self.MoveSpecialControlKey,
+ self.ControlKey,
+ self.SpecialControlKey,
+ self.MoveSpecialKey,
+ self.ShiftKey,
+ self.NormalChar]
+ for filter in filters:
+ if filter(event,key):
+ break
+ return 0
- # to be overloaded
- def OnUpdateHighlight(self, line = -1):
- pass
+#----------------------- Eliminate memory leaks
- def OnUpdateSyntax(self, line = -1):
- pass
+ def OnDestroy(self, event):
+ self.mdc = None
+ self.odc = None
+ self.bgColor = None
+ self.fgColor = None
+ self.font = None
+ self.selectColor = None
+ self.scrollTimer = None
+ self.eofMarker = None
- def OnTabulator(self, event):
- pass
+#-------------------- Abstract methods for subclasses
- def OnInit(self):
+ def OnClick(self):
pass
-
- def OnFold(self):
+
+ def SelectNotify(self, Selecting, SelectionBegin, SelectionEnd):
pass
--- /dev/null
+
+# images converted with wxPython's img2py.py tool
+
+from wxPython.wx import wxBitmapFromXPMData, wxImageFromBitmap
+import cPickle, zlib
+
+##----------- Common Functions
+
+def GetBitmap(ImageData):
+ return wxBitmapFromXPMData(ImageData)
+
+def GetImage(ImageData):
+ return wxImageFromBitmap(GetBitmap(ImageData))
+
+##----------- Image Data
+
+EofImageData = cPickle.loads(zlib.decompress(
+'x\xda\xd3\xc8)0\xe4\nV7W0W0R0T\xe7J\x0cV\xd7SHVp\xcaIL\xce\x06\xf3\x14\x80<\
+\xbf\xfc\xbcT(GA\x0f\x88\xa1l===\x18[\x0f\x04 l=\x08\xc0\x10GQ\x0f7G\x0f\x00\
+\xec\xa2\x19\x96' ))
+++ /dev/null
-# (C)opyright by Dirk Holtwick, 1999
-# ----------------------------------
-# holtwick@spirito.de
-# http://www.spirito.de/pyde
-
-from editor import *
-from string import *
-from keyword import *
-from tokenizer import *
-
-"""
-This module will be loaded by the main
-window. It implements some methods that
-are typical for Python sources.
-"""
-
-class wxPyEditor(wxEditor):
-
- # ------------------------------------------------------------------
-
- def __init__(self, parent, id,
- pos=wxDefaultPosition, size=wxDefaultSize, style=0):
- wxEditor.__init__(self, parent, id, pos, size, style)
- self.SetFontTab([
- wxNamedColour('black'),
- wxNamedColour('blue'),
- wxNamedColour('red'),
- wxNamedColour('darkgreen'),
- wxNamedColour('brown')
- ])
-
- # ------------------------------------------------------------------
-
- def OnUpdateHighlight(self, line = -1):
- if line>=0:
- t = self.text[line].text
- syn = []
-
- toks = Tokenizer(t).tokens()
- for type, string, begin, end in toks:
- if type == "KEY":
- syn.append((begin, 1))
- syn.append((end, 0))
- elif type == "COMMENT":
- syn.append((begin, 2))
- elif type == "STRING":
- syn.append((begin, 3))
- syn.append((end, 0))
- elif type == "NUMBER":
- syn.append((begin, 4))
- syn.append((end, 0))
- elif type == "NAME":
- if string=="self":
- syn.append((begin, 4))
- syn.append((end, 0))
- else:
- pass
- self.text[line].syntax = syn
-
- # ------------------------------------------------------------------
-
- def OnUpdateSyntax(self, line = -1):
- if line>=0:
- """
- tx, syn, m = self.text[line]
- pre = 0
- for i in range(0,len(tx)):
- if tx[i] != " ":
- pre = i
- break
- t = tx[pre:]
-
- t = Tokenizer(t).line()
-
- t = tx[:pre] + t
- self.text[line] = t, syn, m
- """
- self.OnUpdateHighlight(line)
-
- # ------------------------------------------------------------------
-
- def OnTabulator(self, event):
- add = +1
- if event.ShiftDown():
- add = -1
- t = self.GetTextLine(self.cy)
- if strip(t):
- indent = self.GetIndent(t)
-# print indent
- t = t[indent:]
- tabs = indent / self.tabsize
-# for i in range(0,tabs+add):
- t = (" " * 4 * (tabs+add)) + t
- self.SetTextLine(self.cy, t)
- elif add>0:
- self.InsertText(" ")
-
- # ------------------------------------------------------------------
-
- def FindQuote(self, lineno, quote_type='"""', direction=1):
- """find line containing the matching quote"""
- l =lineno +direction
- while (l < len(self.text)-1) and (l >= 0):
- if find(self.text[l].text, quote_type) >=0: return l
- l =l +direction
- return None
-
- def FindNextLine(self, lineno, direction=1):
- """get the next line of code (skipping comment lines and empty lines)"""
- l =lineno +direction
- while (l < len(self.text)-1) and (l >= 0):
- str =lstrip(self.text[l].text)
- if (len(str) >0) and (str[0] !="#"): return l
- l =l +direction
- return None
-
- def Fold(self):
- l = self.GetLine(self.cy)
- line = self.text[l]
- t = line.text
-
- # fold ...
- if line.editable:
-
- # 3*quotes
- qpos =find(t, '"""')
- if qpos >=0: qtype ='"""'
- else:
- qpos =find(t, "'''")
- if qpos >=0: qtype ="'''"
-
- if (qpos >=0) and (find(t[qpos+3:], qtype) <0):
- closing_quote =self.FindQuote(l, qtype)
- if closing_quote !=None:
- line.editable = not line.editable
- l =l +1
- while l <= closing_quote:
- self.text[l].visible =self.text[l].visible +1
- l =l +1
-
- else: # try normal fold on leading whitespace
- lim = self.GetIndent(t)
- lnext =self.FindNextLine(l)
- if (lnext !=None) \
- and (self.GetIndent(self.text[lnext].text) >lim):
- line.editable =FALSE
- lstart =l +1
- l =self.FindNextLine(l)
- while (l !=None) \
- and (self.GetIndent(self.text[l].text) >lim):
- l =self.FindNextLine(l)
- if l ==None:
- # fold till the end
- l =len(self.text)
- for line in self.text[lstart:l]:
- line.visible =line.visible +1
-
- # ... or unfold
- else:
- lim = line.visible + 1
- line.editable = not line.editable
-
- l = l + 1
- line = self.text[l]
- while (l < (len(self.text) -1)) and (line.visible>=lim):
- line.visible = line.visible - 1
- l = l + 1
- line = self.text[l]
-
- def FoldAll(self):
- self.CalcLines()
- self.cx = 0
- self.cy = len(self.lines) - 1
- prev_indent =0
- # following loop is exited in two cases:
- # when self.cy becomes 0 (topmost level is not folded by FoldAll)
- # or when FindNextLine() returns None (all remaining lines till
- # the beginning of the text are empty or comments)
- while self.cy:
- t = self.GetTextLine(self.cy)
- # indent-based folding
- indent =self.GetIndent(t)
- if indent <prev_indent:
- self.Fold()
- prev_indent =indent
- # triple-quote folding
- qpos =find(t, '"""')
- if qpos >=0: qtype ='"""'
- else:
- qpos =find(t, "'''")
- if qpos >=0: qtype ="'''"
- if (qpos >=0) and (find(t[qpos+3:], qtype) <0):
- closing_quote =self.FindQuote(self.cy, qtype, -1)
- if closing_quote !=None:
- # XXX potential bug: unmatched triple quotes
- self.cy =closing_quote
- self.Fold()
- self.cy =self.FindNextLine(self.cy, -1)
- if self.cy ==None: self.cy =0
-
- # ------------------------------------------------------------------
-
- def OnFold(self):
- self.Fold()
-
- # ------------------------------------------------------------------
-
- def OnInit(self):
- #self.FoldAll()
- pass
-
--- /dev/null
+TRUE = 1
+FALSE = 0
+
+def RestOfLine(sx, width, data, bool):
+ if len(data) == 0 and sx == 0:
+ return [('', bool)]
+ if sx >= len(data):
+ return []
+ return [(data[sx:sx+width], bool)]
+
+def Selection(SelectBegin,SelectEnd, sx, width, line, data):
+ if SelectEnd is None or SelectBegin is None:
+ return RestOfLine(sx, width, data, FALSE)
+ (bRow, bCol) = SelectBegin
+ (eRow, eCol) = SelectEnd
+ if (eRow < bRow):
+ (bRow, bCol) = SelectEnd
+ (eRow, eCol) = SelectBegin
+ if (line < bRow or eRow < line):
+ return RestOfLine(sx, width, data, FALSE)
+ if (bRow < line and line < eRow):
+ return RestOfLine(sx, width, data, TRUE)
+ if (bRow == eRow) and (eCol < bCol):
+ (bCol, eCol) = (eCol, bCol)
+ # selection either starts or ends on this line
+ end = min(sx+width, len(data))
+ if (bRow < line):
+ bCol = 0
+ if (line < eRow):
+ eCol = end
+ pieces = []
+ if (sx < bCol):
+ if bCol <= end:
+ pieces += [(data[sx:bCol], FALSE)]
+ else:
+ return [(data[sx:end], FALSE)]
+ pieces += [(data[max(bCol,sx):min(eCol,end)], TRUE)]
+ if (eCol < end):
+ pieces += [(data[eCol:end], FALSE)]
+ return pieces
+
+
+++ /dev/null
-from tokenize import *
-from keyword import *
-from string import *
-
-class Tokenizer:
- """
- Simple class to create a list of token-tuples like:
-
- (type, string, first, last)
-
- Example:
- t = Tokenizer('def hallo(du): # juchee')
- print t.tokens()
- """
-
- def __init__(self, text):
- self.text = text
- self.toks = []
- try:
- tokenize(self.readline, self.get)
- except TokenError:
- pass
-
- def tokens(self):
- return self.toks
-
- def get(self, type, string, begin, end, l):
- #print begin,end
- h1, b = begin
- h2, e = end
- tname = tok_name[type]
- if iskeyword(string):
- tname = "KEY"
- self.toks.append( (tname, string, b, e) )
-
- def readline(self):
- t = self.text
- self.text = ""
- return t
-
- def line(self):
- pre = ""
- out = ""
- for type, string, begin, end in self.toks:
- if (pre in ["NAME","KEY"]) and (not string in [".",",","("]):
- out = out + " "
-
- if type in ["NAME","KEY"]:
- out = out + string
- elif type=="OP":
- if string in [",",":"]:
- out = out + string + " "
- else:
- out = out + string
- else:
- out = out + string
- pre = type
- return out
-
-