true/false or TRUE/FALSE to prepare for the new boolean type and constants being added to Python. Added code to wx.py to test for the existence of the new constants and to create suitable values if not present. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_4_BRANCH@19335 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
348 lines
13 KiB
Python
348 lines
13 KiB
Python
|
|
from wxPython.wx import *
|
|
from wxPython.stc import *
|
|
|
|
import keyword
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
demoText = """\
|
|
## This version of the editor has been set up to edit Python source
|
|
## code. Here is a copy of wxPython/demo/Main.py to play with.
|
|
|
|
|
|
"""
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
|
|
if wxPlatform == '__WXMSW__':
|
|
faces = { 'times': 'Times New Roman',
|
|
'mono' : 'Courier New',
|
|
'helv' : 'Arial',
|
|
'other': 'Comic Sans MS',
|
|
'size' : 10,
|
|
'size2': 8,
|
|
}
|
|
else:
|
|
faces = { 'times': 'Times',
|
|
'mono' : 'Courier',
|
|
'helv' : 'Helvetica',
|
|
'other': 'new century schoolbook',
|
|
'size' : 12,
|
|
'size2': 10,
|
|
}
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
class PythonSTC(wxStyledTextCtrl):
|
|
def __init__(self, parent, ID):
|
|
wxStyledTextCtrl.__init__(self, parent, ID,
|
|
style = wxNO_FULL_REPAINT_ON_RESIZE)
|
|
|
|
self.CmdKeyAssign(ord('B'), wxSTC_SCMOD_CTRL, wxSTC_CMD_ZOOMIN)
|
|
self.CmdKeyAssign(ord('N'), wxSTC_SCMOD_CTRL, wxSTC_CMD_ZOOMOUT)
|
|
|
|
self.SetLexer(wxSTC_LEX_PYTHON)
|
|
self.SetKeyWords(0, " ".join(keyword.kwlist))
|
|
|
|
self.SetProperty("fold", "1")
|
|
self.SetProperty("tab.timmy.whinge.level", "1")
|
|
self.SetMargins(0,0)
|
|
|
|
self.SetViewWhiteSpace(False)
|
|
#self.SetBufferedDraw(False)
|
|
|
|
self.SetEdgeMode(wxSTC_EDGE_BACKGROUND)
|
|
self.SetEdgeColumn(78)
|
|
|
|
# Setup a margin to hold fold markers
|
|
#self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
|
|
self.SetMarginType(2, wxSTC_MARGIN_SYMBOL)
|
|
self.SetMarginMask(2, wxSTC_MASK_FOLDERS)
|
|
self.SetMarginSensitive(2, True)
|
|
self.SetMarginWidth(2, 12)
|
|
|
|
if 0: # simple folder marks, like the old version
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_ARROW, "navy", "navy")
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_ARROWDOWN, "navy", "navy")
|
|
# Set these to an invisible mark
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BACKGROUND, "white", "black")
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_BACKGROUND, "white", "black")
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_BACKGROUND, "white", "black")
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_BACKGROUND, "white", "black")
|
|
|
|
else: # more involved "outlining" folder marks
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUSCONNECTED, "white", "black")
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUSCONNECTED, "white", "black")
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_TCORNER, "white", "black")
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER, "white", "black")
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE, "white", "black")
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS, "white", "black")
|
|
self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS, "white", "black")
|
|
|
|
|
|
EVT_STC_UPDATEUI(self, ID, self.OnUpdateUI)
|
|
EVT_STC_MARGINCLICK(self, ID, self.OnMarginClick)
|
|
|
|
|
|
# Make some styles, The lexer defines what each style is used for, we
|
|
# just have to define what each style looks like. This set is adapted from
|
|
# Scintilla sample property files.
|
|
|
|
self.StyleClearAll()
|
|
|
|
# Global default styles for all languages
|
|
self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
|
|
self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
|
|
self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
|
|
self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
|
|
self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
|
|
|
|
# Python styles
|
|
# White space
|
|
self.StyleSetSpec(wxSTC_P_DEFAULT, "fore:#808080,face:%(helv)s,size:%(size)d" % faces)
|
|
# Comment
|
|
self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
|
|
# Number
|
|
self.StyleSetSpec(wxSTC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
|
|
# String
|
|
self.StyleSetSpec(wxSTC_P_STRING, "fore:#7F007F,italic,face:%(times)s,size:%(size)d" % faces)
|
|
# Single quoted string
|
|
self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7F007F,italic,face:%(times)s,size:%(size)d" % faces)
|
|
# Keyword
|
|
self.StyleSetSpec(wxSTC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
|
|
# Triple quotes
|
|
self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces)
|
|
# Triple double quotes
|
|
self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces)
|
|
# Class name definition
|
|
self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces)
|
|
# Function or method name definition
|
|
self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces)
|
|
# Operators
|
|
self.StyleSetSpec(wxSTC_P_OPERATOR, "bold,size:%(size)d" % faces)
|
|
# Identifiers
|
|
self.StyleSetSpec(wxSTC_P_IDENTIFIER, "fore:#808080,face:%(helv)s,size:%(size)d" % faces)
|
|
# Comment-blocks
|
|
self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces)
|
|
# End of line where string is not closed
|
|
self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)
|
|
|
|
|
|
self.SetCaretForeground("BLUE")
|
|
|
|
EVT_KEY_DOWN(self, self.OnKeyPressed)
|
|
|
|
|
|
def OnKeyPressed(self, event):
|
|
if self.CallTipActive():
|
|
self.CallTipCancel()
|
|
key = event.KeyCode()
|
|
if key == 32 and event.ControlDown():
|
|
pos = self.GetCurrentPos()
|
|
# Tips
|
|
if event.ShiftDown():
|
|
self.CallTipSetBackground("yellow")
|
|
self.CallTipShow(pos, 'param1, param2')
|
|
# Code completion
|
|
else:
|
|
#lst = []
|
|
#for x in range(50000):
|
|
# lst.append('%05d' % x)
|
|
#st = " ".join(lst)
|
|
#print len(st)
|
|
#self.AutoCompShow(0, st)
|
|
|
|
kw = keyword.kwlist[:]
|
|
kw.append("zzzzzz")
|
|
kw.append("aaaaa")
|
|
kw.append("__init__")
|
|
kw.append("zzaaaaa")
|
|
kw.append("zzbaaaa")
|
|
kw.append("this_is_a_longer_value")
|
|
kw.append("this_is_a_much_much_much_much_much_much_much_longer_value")
|
|
|
|
kw.sort() # Python sorts are case sensitive
|
|
self.AutoCompSetIgnoreCase(False) # so this needs to match
|
|
|
|
self.AutoCompShow(0, " ".join(kw))
|
|
else:
|
|
event.Skip()
|
|
|
|
|
|
def OnUpdateUI(self, evt):
|
|
# check for matching braces
|
|
braceAtCaret = -1
|
|
braceOpposite = -1
|
|
charBefore = None
|
|
caretPos = self.GetCurrentPos()
|
|
if caretPos > 0:
|
|
charBefore = self.GetCharAt(caretPos - 1)
|
|
styleBefore = self.GetStyleAt(caretPos - 1)
|
|
|
|
# check before
|
|
if charBefore and chr(charBefore) in "[]{}()" and styleBefore == wxSTC_P_OPERATOR:
|
|
braceAtCaret = caretPos - 1
|
|
|
|
# check after
|
|
if braceAtCaret < 0:
|
|
charAfter = self.GetCharAt(caretPos)
|
|
styleAfter = self.GetStyleAt(caretPos)
|
|
if charAfter and chr(charAfter) in "[]{}()" and styleAfter == wxSTC_P_OPERATOR:
|
|
braceAtCaret = caretPos
|
|
|
|
if braceAtCaret >= 0:
|
|
braceOpposite = self.BraceMatch(braceAtCaret)
|
|
|
|
if braceAtCaret != -1 and braceOpposite == -1:
|
|
self.BraceBadLight(braceAtCaret)
|
|
else:
|
|
self.BraceHighlight(braceAtCaret, braceOpposite)
|
|
#pt = self.PointFromPosition(braceOpposite)
|
|
#self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
|
|
#print pt
|
|
#self.Refresh(False)
|
|
|
|
|
|
def OnMarginClick(self, evt):
|
|
# fold and unfold as needed
|
|
if evt.GetMargin() == 2:
|
|
if evt.GetShift() and evt.GetControl():
|
|
self.FoldAll()
|
|
else:
|
|
lineClicked = self.LineFromPosition(evt.GetPosition())
|
|
if self.GetFoldLevel(lineClicked) & wxSTC_FOLDLEVELHEADERFLAG:
|
|
if evt.GetShift():
|
|
self.SetFoldExpanded(lineClicked, True)
|
|
self.Expand(lineClicked, True, True, 1)
|
|
elif evt.GetControl():
|
|
if self.GetFoldExpanded(lineClicked):
|
|
self.SetFoldExpanded(lineClicked, False)
|
|
self.Expand(lineClicked, False, True, 0)
|
|
else:
|
|
self.SetFoldExpanded(lineClicked, True)
|
|
self.Expand(lineClicked, True, True, 100)
|
|
else:
|
|
self.ToggleFold(lineClicked)
|
|
|
|
|
|
def FoldAll(self):
|
|
lineCount = self.GetLineCount()
|
|
expanding = True
|
|
|
|
# find out if we are folding or unfolding
|
|
for lineNum in range(lineCount):
|
|
if self.GetFoldLevel(lineNum) & wxSTC_FOLDLEVELHEADERFLAG:
|
|
expanding = not self.GetFoldExpanded(lineNum)
|
|
break;
|
|
|
|
lineNum = 0
|
|
while lineNum < lineCount:
|
|
level = self.GetFoldLevel(lineNum)
|
|
if level & wxSTC_FOLDLEVELHEADERFLAG and \
|
|
(level & wxSTC_FOLDLEVELNUMBERMASK) == wxSTC_FOLDLEVELBASE:
|
|
|
|
if expanding:
|
|
self.SetFoldExpanded(lineNum, True)
|
|
lineNum = self.Expand(lineNum, True)
|
|
lineNum = lineNum - 1
|
|
else:
|
|
lastChild = self.GetLastChild(lineNum, -1)
|
|
self.SetFoldExpanded(lineNum, False)
|
|
if lastChild > lineNum:
|
|
self.HideLines(lineNum+1, lastChild)
|
|
|
|
lineNum = lineNum + 1
|
|
|
|
|
|
|
|
def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
|
|
lastChild = self.GetLastChild(line, level)
|
|
line = line + 1
|
|
while line <= lastChild:
|
|
if force:
|
|
if visLevels > 0:
|
|
self.ShowLines(line, line)
|
|
else:
|
|
self.HideLines(line, line)
|
|
else:
|
|
if doExpand:
|
|
self.ShowLines(line, line)
|
|
|
|
if level == -1:
|
|
level = self.GetFoldLevel(line)
|
|
|
|
if level & wxSTC_FOLDLEVELHEADERFLAG:
|
|
if force:
|
|
if visLevels > 1:
|
|
self.SetFoldExpanded(line, True)
|
|
else:
|
|
self.SetFoldExpanded(line, False)
|
|
line = self.Expand(line, doExpand, force, visLevels-1)
|
|
|
|
else:
|
|
if doExpand and self.GetFoldExpanded(line):
|
|
line = self.Expand(line, True, force, visLevels-1)
|
|
else:
|
|
line = self.Expand(line, False, force, visLevels-1)
|
|
else:
|
|
line = line + 1;
|
|
|
|
return line
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
_USE_PANEL = 1
|
|
|
|
def runTest(frame, nb, log):
|
|
if not _USE_PANEL:
|
|
ed = p = PythonSTC(nb, -1)
|
|
else:
|
|
p = wxPanel(nb, -1, style = wxNO_FULL_REPAINT_ON_RESIZE)
|
|
ed = PythonSTC(p, -1)
|
|
s = wxBoxSizer(wxHORIZONTAL)
|
|
s.Add(ed, 1, wxEXPAND)
|
|
p.SetSizer(s)
|
|
p.SetAutoLayout(True)
|
|
|
|
|
|
ed.SetText(demoText + open('Main.py').read())
|
|
ed.EmptyUndoBuffer()
|
|
ed.Colourise(0, -1)
|
|
|
|
# line numbers in the margin
|
|
ed.SetMarginType(1, wxSTC_MARGIN_NUMBER)
|
|
ed.SetMarginWidth(1, 25)
|
|
|
|
return p
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
|
|
overview = """\
|
|
<html><body>
|
|
Once again, no docs yet. <b>Sorry.</b> But <a href="data/stc.h.html">this</a>
|
|
and <a href="http://www.scintilla.org/ScintillaDoc.html">this</a> should
|
|
be helpful.
|
|
</body><html>
|
|
"""
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import sys,os
|
|
import run
|
|
run.main(['', os.path.basename(sys.argv[0])])
|
|
|
|
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
#----------------------------------------------------------------------
|
|
|