OLD | NEW |
| (Empty) |
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.d
igits)), 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.B
LACK) | |
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, canvas
Y+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=ttyFon
t, 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+fontW
idth-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') | |
OLD | NEW |