-#----------------------------------------------------------------------
-# Name: wxPython.lib.editor.wxEditor
-# Purpose: An intelligent text editor with colorization capabilities.
-#
-# Author: Dirk Holtwic, Robin Dunn
-#
-# Created: 15-Dec-1999
-# RCS-ID: $Id$
-# Copyright: (c) 1999 by Dirk Holtwick, 1999
-# 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
-
-
-from wxPython.wx import *
-from string import *
-from keyword import *
-from regsub import *
-from tokenizer import *
-
-#---------------------------------------------------------------------------
-
-
-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
-
-#----------------------------------------------------------------------
-
-class wxEditor(wxScrolledWindow):
-
- 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
-
- # cursor pos
- 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.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)
-
- # events
- EVT_LEFT_DOWN(self, self.OnMouseClick)
- EVT_RIGHT_DOWN(self, self.OnMouseClick)
- EVT_SCROLLWIN(self, self.OnScroll)
-
- 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
-
- 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()
- self.SetFocus()
-
-
-#---------------------------------------------------------------------------
-
- 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
-
-
- 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
-
-
- def IsLine(self, line):
- ###############################################################
- """ Schauen, ob alles im grünen Bereich ist """
- return (line>=0) and (line<self.len)
-
-
- def IsEditable(self, line):
- ###############################################################
- return self.text[self.GetLine(line)].editable
-
-
- def GetLine(self, line):
- ###############################################################
- return self.lines[line]
-
-
- def GetTextLine(self, line):
- ###############################################################
- """ Text holen """
- if self.IsLine(line):
- return self.text[self.GetLine(line)].text
- return ""
-
-
- 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 OnMouseClick(self, event):
- ###############################################################
- """
- Wenn es Click gemacht hat => Cursor setzen
- """
- self.SetFocus()
-
- 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 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
-
- x = self.cx - self.sx
- y = self.cy - self.sy
- self.DrawSimpleCursor(x, y, dc)
-
-
- def DrawSimpleCursor(self, xp, yp, dc = None, old=false):
- ###############################################################
- """
- Auch der Cursor muß ja irgendwie gezeichnet werden
- """
- if not dc:
- dc = wxClientDC(self)
-
- if old:
- xp = self.sco_x
- yp = self.sco_y
-
- szx = self.fw
- szy = self.fh
- x = xp * szx
- y = yp * szy
- dc.Blit(x,y,szx,szy,dc,x,y,wxSRC_INVERT)
- self.sco_x = xp
- self.sco_y = yp
-
-
- 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()
-
- if not dc:
- dc = wxClientDC(self)
-
- self.bw,self.bh = self.GetSizeTuple()
- self.sw = self.bw / self.fw
- self.sh = self.bh / self.fh
-
- if self.cy<self.sy:
- self.sy = self.cy
- elif self.cy>(self.sy+self.sh-1):
- self.sy = self.cy-self.sh+1
-
- if self.cx<self.sx:
- self.sx = self.cx
- elif self.cx>(self.sx+self.sw-1):
- self.sx = self.cx-self.sw+1
-
- # left line? change syntax!
- if self.ocy!=self.cy:
- self.OnUpdateSyntax(self.ocy)
- self.ocy = self.cy
-
- # alles beim alten
- if self.osx != self.sx or self.osy != self.sy:
- self.AdjustScrollbars()
-
- 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)
-
- 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 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 DrawLine(self, line, dc=None):
- ###############################################################
- """
- Hier wird einfach die Ansicht der ganzen Seite
- wiederhergestellt.
- !!! Kann modifiziert werden !!!
- """
-
- if not dc:
- dc = wxClientDC(self)
-
- dc.SetBackgroundMode(wxSOLID)
- dc.SetTextBackground(self.bcol)
- dc.SetTextForeground(self.fcol)
- #dc.Clear()
-
- # 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
-
- if not self.text[l].editable:
- dc.SetTextBackground(self.nedcol)
- else:
- dc.SetTextBackground(self.bcol)
-
- dc.SetTextForeground(self.fcol)
-
- 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 Draw(self, odc=None):
- ###############################################################
- """
- Hier wird einfach die Ansicht der ganzen Seite
- wiederhergestellt.
- !!! Kann modifiziert werden !!!
- """
-
- if not odc:
- odc = wxClientDC(self)
-
- 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)
-
-
- 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 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 OnChar(self, event):
- ###############################################################
- """
- Wenn eine Taste gedrückt wird,
- kann an dieser Stelle die Auswertung stattfinden
- """
-
- # get code
- key = event.KeyCode()
-
-# if event.ControlDown:
-# if chr(key)=="k":
-# print "weg"
-
-
- # 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)
-
- elif key==WXK_NEXT:
- self.cVert(self.sh)
- elif key==WXK_PRIOR:
- self.cVert(-self.sh)
-
- 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)
-
- elif key==WXK_RETURN:
- self.InsertText("\n")
-
- elif key==WXK_TAB:
- self.OnTabulator(event)
-
- # clipboard (buggy)
- elif key==WXK_F10:
- if wxTheClipboard.Open():
- data = wxTheClipboard.GetData()
- wxTheClipboard.Close()
- print data
-
- # folding (buggy)
- elif key==WXK_F12:
- self.update = true
- self.OnFold()
-
- # regular ascii
- elif (key>31) and (key<256):
- self.InsertText(chr(key))
-
- self.UpdateView()
- return 0
-
-
- def OnPaint(self, event):
- dc = wxPaintDC(self)
- self.bw,self.bh = self.GetSizeTuple()
- self.UpdateView(dc, true)
-
-
-#-----------------------------------------------------------------------------------------
-
- 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 Goto(self, pos):
- self.cVert(pos-self.cy-1)
- self.UpdateView()
-
-# --------------------------------------------------------
-
- # to be overloaded
- def OnUpdateHighlight(self, line = -1):
- pass
-
- def OnUpdateSyntax(self, line = -1):
- pass
-
- def OnTabulator(self, event):
- pass
-
- def OnInit(self):
- pass
-
- def OnFold(self):
- pass
-