⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 editor.py

📁 Wxpython Implemented on Windows CE, Source code
💻 PY
📖 第 1 页 / 共 2 页
字号:
#----------------------------------------------------------------------
# Name:        wxPython.lib.editor.Editor
# Purpose:     An intelligent text editor with colorization capabilities.
#
# 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: editor.py,v 1.12 2006/01/29 02:36:29 RD Exp $
# Copyright:   (c) 1999 by Dirk Holtwick, 1999
# Licence:     wxWindows license
#----------------------------------------------------------------------
# 12/14/2003 - Jeff Grimmett (grimmtooth@softhome.net)
#
# o 2.5 compatability update.
#
# 12/21/2003 - Jeff Grimmett (grimmtooth@softhome.net)
#
# o wxEditor -> Editor
#

import  os
import  time

import  wx

import  selection
import  images

#----------------------------

def ForceBetween(min, val, max):
    if val  > max:
        return max
    if val < min:
        return min
    return val


def LineTrimmer(lineOfText):
    if len(lineOfText) == 0:
        return ""
    elif lineOfText[-1] == '\r':
        return lineOfText[:-1]
    else:
        return lineOfText

def LineSplitter(text):
    return map (LineTrimmer, text.split('\n'))


#----------------------------

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

#----------------------------------------------------------------------

class Editor(wx.ScrolledWindow):

    def __init__(self, parent, id,
                 pos=wx.DefaultPosition, size=wx.DefaultSize, style=0):

        wx.ScrolledWindow.__init__(self, parent, id,
                                  pos, size,
                                  style|wx.WANTS_CHARS)

        self.isDrawing = False
        
        self.InitCoords()
        self.InitFonts()
        self.SetColors()
        self.MapEvents()
        self.LoadImages()
        self.InitDoubleBuffering()
        self.InitScrolling()
        self.SelectOff()
        self.SetFocus()
        self.SetText([""])
        self.SpacesPerTab = 4

##------------------ Init stuff

    def InitCoords(self):
        self.cx = 0
        self.cy = 0
        self.oldCx = 0
        self.oldCy = 0
        self.sx = 0
        self.sy = 0
        self.sw = 0
        self.sh = 0
        self.sco_x = 0
        self.sco_y = 0

    def MapEvents(self):
        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
        self.Bind(wx.EVT_MOTION, self.OnMotion)
        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
        self.Bind(wx.EVT_CHAR, self.OnChar)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

##------------------- Platform-specific stuff

    def NiceFontForPlatform(self):
        if wx.Platform == "__WXMSW__":
            font = wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL)
        else:
            font = wx.Font(12, wx.MODERN, wx.NORMAL, wx.NORMAL, False)
        if wx.Platform == "__WXMAC__":
            font.SetNoAntiAliasing()
        return font

    def UnixKeyHack(self, key):
        #
        # this will be obsolete when we get the new wxWindows patch
        #
        # 12/14/03 - jmg
        #
        # Which patch? I don't know if this is needed, but I don't know
        # why it's here either. Play it safe; leave it in.
        #
        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.GetClientSize()

        if wx.Platform == "__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 - wx.SystemSettings_GetMetric(wx.SYS_VSCROLL_X)
                self.sw = (self.bw / self.fw) - 1

            self.sw = (self.bw / self.fw) - 1
            if self.CalcMaxLineLen() >= self.sw:
                self.bh = self.bh - wx.SystemSettings_GetMetric(wx.SYS_HSCROLL_Y)
                self.sh = self.bh / self.fh


    def UpdateView(self, dc = None):
        if dc is None:
            dc = wx.ClientDC(self)
        if dc.Ok():
            self.SetCharDimensions()
            self.KeepCursorOnScreen()
            self.DrawSimpleCursor(0,0, dc, True)
            self.Draw(dc)

    def OnPaint(self, event):
        dc = wx.PaintDC(self)
        if self.isDrawing:
            return
        self.isDrawing = True
        self.UpdateView(dc)
        wx.CallAfter(self.AdjustScrollbars)
        self.isDrawing = False

    def OnEraseBackground(self, evt):
        pass

##-------------------- Drawing code

    def InitFonts(self):
        dc = wx.ClientDC(self)
        self.font = self.NiceFontForPlatform()
        dc.SetFont(self.font)
        self.fw = dc.GetCharWidth()
        self.fh = dc.GetCharHeight()

    def SetColors(self):
        self.fgColor = wx.NamedColour('black')
        self.bgColor = wx.NamedColour('white')
        self.selectColor = wx.Colour(238, 220, 120)  # r, g, b = emacsOrange

    def InitDoubleBuffering(self):
        pass

    def DrawEditText(self, t, x, y, dc):
        dc.DrawText(t, x * self.fw, y * self.fh)

    def DrawLine(self, line, dc):
        if self.IsLine(line):
            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 Draw(self, odc=None):
        if not odc:
            odc = wx.ClientDC(self)

        bmp = wx.EmptyBitmap(max(1,self.bw), max(1,self.bh))
        dc = wx.BufferedDC(odc, bmp)
        if dc.Ok():
            dc.SetFont(self.font)
            dc.SetBackgroundMode(wx.SOLID)
            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)
            self.DrawCursor(dc)

##------------------ eofMarker stuff

    def LoadImages(self):
        self.eofMarker = images.GetBitmap(images.EofImageData)

    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):
        if not dc:
            dc = wx.ClientDC(self)

        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
        self.DrawSimpleCursor(x, y, dc)


    def DrawSimpleCursor(self, xp, yp, dc = None, old=False):
        if not dc:
            dc = wx.ClientDC(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, wx.SRC_INVERT)
        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 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)

    def AboveScreen(self, row):
        return row < self.sy

    def BelowScreen(self, row):
        return row >= self.sy + self.sh

    def LeftOfScreen(self, col):
        return col < self.sx

    def RightOfScreen(self, col):
        return col >= self.sx + self.sw

##----------------- data structure helper functions

    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 ""

    def SetTextLine(self, lineNum, text):
        if self.IsLine(lineNum):
            self.lines[lineNum] = text

    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 TouchBuffer(self):
        self.bufferTouched = True


##-------------------------- Mouse scroll timing functions

    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 = wx.Timer(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)
        self.Bind(wx.EVT_TIMER, self.OnTimer)

    def OnTimer(self, event):
        screenX, screenY = wx.GetMousePosition()
        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() and self.HasCapture():
            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()
        self.SetFocus()

    def OnLeftUp(self, event):
        if not self.HasCapture():

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -