~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/conch/ui/tkvt100.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-17 14:52:35 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20070117145235-btmig6qfmqfen0om
Tags: 2.5.0-0ubuntu1
New upstream version, compatible with python2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
#
 
5
 
 
6
"""Module to emulate a VT100 terminal in Tkinter.
 
7
 
 
8
Maintainer: U{Paul Swartz <mailto:z3p@twistedmatrix.com>}
 
9
"""
 
10
 
 
11
import Tkinter, tkFont
 
12
import ansi
 
13
import string
 
14
 
 
15
ttyFont = None#tkFont.Font(family = 'Courier', size = 10)
 
16
fontWidth, fontHeight = None,None#max(map(ttyFont.measure, string.letters+string.digits)), int(ttyFont.metrics()['linespace'])
 
17
 
 
18
colorKeys = (
 
19
    'b', 'r', 'g', 'y', 'l', 'm', 'c', 'w',
 
20
    'B', 'R', 'G', 'Y', 'L', 'M', 'C', 'W'
 
21
)
 
22
 
 
23
colorMap = {
 
24
    'b': '#000000', 'r': '#c40000', 'g': '#00c400', 'y': '#c4c400',
 
25
    'l': '#000080', 'm': '#c400c4', 'c': '#00c4c4', 'w': '#c4c4c4',
 
26
    'B': '#626262', 'R': '#ff0000', 'G': '#00ff00', 'Y': '#ffff00',
 
27
    'L': '#0000ff', 'M': '#ff00ff', 'C': '#00ffff', 'W': '#ffffff',
 
28
}
 
29
 
 
30
class VT100Frame(Tkinter.Frame):
 
31
    def __init__(self, *args, **kw):
 
32
        global ttyFont, fontHeight, fontWidth
 
33
        ttyFont = tkFont.Font(family = 'Courier', size = 10)
 
34
        fontWidth, fontHeight = max(map(ttyFont.measure, string.letters+string.digits)), int(ttyFont.metrics()['linespace'])
 
35
        self.width = kw.get('width', 80)
 
36
        self.height = kw.get('height', 25)
 
37
        self.callback = kw['callback']
 
38
        del kw['callback']
 
39
        kw['width'] = w = fontWidth * self.width
 
40
        kw['height'] = h = fontHeight * self.height
 
41
        Tkinter.Frame.__init__(self, *args, **kw)
 
42
        self.canvas = Tkinter.Canvas(bg='#000000', width=w, height=h)
 
43
        self.canvas.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1)
 
44
        self.canvas.bind('<Key>', self.keyPressed)
 
45
        self.canvas.bind('<1>', lambda x: 'break')
 
46
        self.canvas.bind('<Up>', self.upPressed)
 
47
        self.canvas.bind('<Down>', self.downPressed)
 
48
        self.canvas.bind('<Left>', self.leftPressed)
 
49
        self.canvas.bind('<Right>', self.rightPressed)
 
50
        self.canvas.focus()
 
51
 
 
52
        self.ansiParser = ansi.AnsiParser(ansi.ColorText.WHITE, ansi.ColorText.BLACK)
 
53
        self.ansiParser.writeString = self.writeString
 
54
        self.ansiParser.parseCursor = self.parseCursor
 
55
        self.ansiParser.parseErase = self.parseErase
 
56
        #for (a, b) in colorMap.items():
 
57
        #    self.canvas.tag_config(a, foreground=b)
 
58
        #    self.canvas.tag_config('b'+a, background=b)
 
59
        #self.canvas.tag_config('underline', underline=1)
 
60
 
 
61
        self.x = 0 
 
62
        self.y = 0
 
63
        self.cursor = self.canvas.create_rectangle(0,0,fontWidth-1,fontHeight-1,fill='green',outline='green')
 
64
 
 
65
    def _delete(self, sx, sy, ex, ey):
 
66
        csx = sx*fontWidth + 1
 
67
        csy = sy*fontHeight + 1
 
68
        cex = ex*fontWidth + 3
 
69
        cey = ey*fontHeight + 3
 
70
        items = self.canvas.find_overlapping(csx,csy, cex,cey)
 
71
        for item in items:
 
72
            self.canvas.delete(item)
 
73
 
 
74
    def _write(self, ch, fg, bg):
 
75
        if self.x == self.width:
 
76
            self.x = 0
 
77
            self.y+=1
 
78
            if self.y == self.height:
 
79
                [self.canvas.move(x,0,-fontHeight) for x in self.canvas.find_all()]
 
80
                self.y-=1
 
81
        canvasX = self.x*fontWidth + 1
 
82
        canvasY = self.y*fontHeight + 1
 
83
        items = self.canvas.find_overlapping(canvasX, canvasY, canvasX+2, canvasY+2)
 
84
        if items:
 
85
            [self.canvas.delete(item) for item in items]
 
86
        if bg:
 
87
            self.canvas.create_rectangle(canvasX, canvasY, canvasX+fontWidth-1, canvasY+fontHeight-1, fill=bg, outline=bg)
 
88
        self.canvas.create_text(canvasX, canvasY, anchor=Tkinter.NW, font=ttyFont, text=ch, fill=fg)
 
89
        self.x+=1
 
90
            
 
91
    def write(self, data):
 
92
        #print self.x,self.y,repr(data)
 
93
        #if len(data)>5: raw_input()
 
94
        self.ansiParser.parseString(data)
 
95
        self.canvas.delete(self.cursor)
 
96
        canvasX = self.x*fontWidth + 1
 
97
        canvasY = self.y*fontHeight + 1
 
98
        self.cursor = self.canvas.create_rectangle(canvasX,canvasY,canvasX+fontWidth-1,canvasY+fontHeight-1, fill='green', outline='green')
 
99
        self.canvas.lower(self.cursor)
 
100
 
 
101
    def writeString(self, i):
 
102
        if not i.display:
 
103
            return
 
104
        fg = colorMap[i.fg]
 
105
        bg = i.bg != 'b' and colorMap[i.bg]
 
106
        for ch in i.text:
 
107
            b = ord(ch)
 
108
            if b == 7: # bell
 
109
                self.bell() 
 
110
            elif b == 8: # BS
 
111
                if self.x:
 
112
                    self.x-=1
 
113
            elif b == 9: # TAB
 
114
                [self._write(' ',fg,bg) for i in range(8)]
 
115
            elif b == 10:
 
116
                if self.y == self.height-1:
 
117
                    self._delete(0,0,self.width,0)
 
118
                    [self.canvas.move(x,0,-fontHeight) for x in self.canvas.find_all()]
 
119
                else:   
 
120
                    self.y+=1
 
121
            elif b == 13:
 
122
                self.x = 0
 
123
            elif 32 <= b < 127:
 
124
                self._write(ch, fg, bg)
 
125
 
 
126
    def parseErase(self, erase):
 
127
        if ';' in erase:
 
128
            end = erase[-1]
 
129
            parts = erase[:-1].split(';')
 
130
            [self.parseErase(x+end) for x in parts]
 
131
            return
 
132
        start = 0
 
133
        x,y = self.x, self.y
 
134
        if len(erase) > 1:
 
135
            start = int(erase[:-1])
 
136
        if erase[-1] == 'J':
 
137
            if start == 0: 
 
138
                self._delete(x,y,self.width,self.height)
 
139
            else:
 
140
                self._delete(0,0,self.width,self.height)
 
141
                self.x = 0
 
142
                self.y = 0 
 
143
        elif erase[-1] == 'K':
 
144
            if start == 0:
 
145
                self._delete(x,y,self.width,y)
 
146
            elif start == 1:
 
147
                self._delete(0,y,x,y)
 
148
                self.x = 0
 
149
            else:
 
150
                self._delete(0,y,self.width,y)
 
151
                self.x = 0
 
152
        elif erase[-1] == 'P':
 
153
            self._delete(x,y,x+start,y)
 
154
 
 
155
    def parseCursor(self, cursor):
 
156
        #if ';' in cursor and cursor[-1]!='H':
 
157
        #    end = cursor[-1]
 
158
        #    parts = cursor[:-1].split(';')
 
159
        #    [self.parseCursor(x+end) for x in parts]
 
160
        #    return
 
161
        start = 1
 
162
        if len(cursor) > 1 and cursor[-1]!='H':
 
163
            start = int(cursor[:-1])
 
164
        if cursor[-1] == 'C':
 
165
            self.x+=start
 
166
        elif cursor[-1] == 'D':
 
167
            self.x-=start
 
168
        elif cursor[-1]=='d':
 
169
            self.y=start-1
 
170
        elif cursor[-1]=='G':
 
171
            self.x=start-1
 
172
        elif cursor[-1]=='H':
 
173
            if len(cursor)>1:
 
174
                y,x = map(int, cursor[:-1].split(';'))
 
175
                y-=1
 
176
                x-=1
 
177
            else:
 
178
                x,y=0,0
 
179
            self.x = x
 
180
            self.y = y
 
181
 
 
182
    def keyPressed(self, event):
 
183
        if self.callback and event.char:
 
184
            self.callback(event.char)
 
185
        return 'break'
 
186
 
 
187
    def upPressed(self, event):
 
188
        self.callback('\x1bOA')
 
189
 
 
190
    def downPressed(self, event):
 
191
        self.callback('\x1bOB')
 
192
 
 
193
    def rightPressed(self, event):
 
194
        self.callback('\x1bOC')
 
195
 
 
196
    def leftPressed(self, event):
 
197
        self.callback('\x1bOD')