comparison python/codeedit.py @ 249:e41e4109addd

Added current position arrow
author Windel Bouwman
date Fri, 26 Jul 2013 20:26:05 +0200
parents b10d46e5c8dd
children f5fba5b554d7
comparison
equal deleted inserted replaced
248:b10d46e5c8dd 249:e41e4109addd
11 if v < mn: return mn 11 if v < mn: return mn
12 if v > mx: return mx 12 if v > mx: return mx
13 return v 13 return v
14 14
15 class InnerCode(QWidget): 15 class InnerCode(QWidget):
16 textChanged = pyqtSignal() 16 textChanged = pyqtSignal()
17 def __init__(self, scrollArea): 17 def __init__(self, scrollArea):
18 super().__init__(scrollArea) 18 super().__init__(scrollArea)
19 self.scrollArea = scrollArea 19 self.scrollArea = scrollArea
20 self.setFont(QFont('Courier', 12)) 20 self.setFont(QFont('Courier', 12))
21 self.setFocusPolicy(Qt.StrongFocus) 21 self.setFocusPolicy(Qt.StrongFocus)
22 # TODO: only beam cursor in text area.. 22 # TODO: only beam cursor in text area..
23 self.setCursor(Qt.IBeamCursor) 23 self.setCursor(Qt.IBeamCursor)
24 h = QFontMetrics(self.font()).height() 24 h = QFontMetrics(self.font()).height()
25 self.errorPixmap = QPixmap('icons/error.png').scaled(h, h) 25 self.errorPixmap = QPixmap('icons/error.png').scaled(h, h)
26 self.arrowPixmap = QPixmap('icons/arrow.png').scaled(h, h)
26 self.blinkcursor = False 27 self.blinkcursor = False
27 self.errorlist = [] 28 self.errorlist = []
29 self.arrow = None
28 # Initial values: 30 # Initial values:
29 self.setSource('') 31 self.setSource('')
30 self.CursorPosition = 0 32 self.CursorPosition = 0
31 t = QTimer(self) 33 t = QTimer(self)
32 t.timeout.connect(self.updateCursor) 34 t.timeout.connect(self.updateCursor)
33 t.setInterval(500) 35 t.setInterval(500)
34 t.start() 36 t.start()
35 def updateCursor(self): 37 def updateCursor(self):
36 self.blinkcursor = not self.blinkcursor 38 self.blinkcursor = not self.blinkcursor
37 self.update() 39 self.update()
38 #self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight) 40 #self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight)
39 def setSource(self, src): 41
42 def setSource(self, src):
40 self.src = src 43 self.src = src
41 self.adjust() 44 self.adjust()
42 def getSource(self): 45
46 def getSource(self):
43 return self.src 47 return self.src
44 def setErrors(self, el): 48
49 def setErrors(self, el):
45 self.errorlist = el 50 self.errorlist = el
46 self.update() 51 self.update()
47 def setCursorPosition(self, c): 52
53 def setCursorPosition(self, c):
48 self.cursorPosition = clipVal(c, 0, len(self.src)) 54 self.cursorPosition = clipVal(c, 0, len(self.src))
49 self.update() 55 self.update()
50 CursorPosition = property(lambda self: self.cursorPosition, setCursorPosition) 56
51 @property 57 CursorPosition = property(lambda self: self.cursorPosition, setCursorPosition)
52 def Rows(self): 58
53 # Make this nicer: 59 @property
54 return self.src.split('\n') 60 def Rows(self):
55 @property 61 # Make this nicer:
56 def CursorRow(self): 62 return self.src.split('\n')
57 # TODO: make this nice. 63
58 txt = self.src[0:self.cursorPosition] 64 @property
59 return len(txt.split('\n')) 65 def CursorRow(self):
60 @property 66 # TODO: make this nice.
61 def CursorCol(self): 67 txt = self.src[0:self.cursorPosition]
62 txt = self.src[0:self.cursorPosition] 68 return len(txt.split('\n'))
63 curLine = txt.split('\n')[-1] 69
64 return len(curLine) + 1 70 @property
65 @property 71 def CursorCol(self):
66 def CurrentLine(self): 72 txt = self.src[0:self.cursorPosition]
67 return self.getRow(self.CursorRow) 73 curLine = txt.split('\n')[-1]
68 def setRowCol(self, r, c): 74 return len(curLine) + 1
75
76 @property
77 def CurrentLine(self):
78 return self.getRow(self.CursorRow)
79
80 def setRowCol(self, r, c):
69 prevRows = self.Rows[:r-1] 81 prevRows = self.Rows[:r-1]
70 txt = '\n'.join(prevRows) 82 txt = '\n'.join(prevRows)
71 c = clipVal(c, 1, len(self.getRow(r))) 83 c = clipVal(c, 1, len(self.getRow(r)))
72 self.CursorPosition = len(txt) + c + 1 84 self.CursorPosition = len(txt) + c + 1
73 self.showRow(self.CursorRow) 85 self.showRow(self.CursorRow)
74 def getRow(self, r): 86
87 def getRow(self, r):
75 rows = self.Rows 88 rows = self.Rows
76 r = r - 1 89 r = r - 1
77 if r < 0 or r > len(rows) - 1: 90 if r < 0 or r > len(rows) - 1:
78 return '' 91 return ''
79 else: 92 else:
80 return rows[r] 93 return rows[r]
81 def showRow(self, r): 94
95 def showRow(self, r):
82 self.scrollArea.ensureVisible(self.xposTXT, r * self.charHeight, 4, self.charHeight) 96 self.scrollArea.ensureVisible(self.xposTXT, r * self.charHeight, 4, self.charHeight)
83 # Annotations: 97 # Annotations:
84 def addAnnotation(self, row, col, ln, msg): 98 def addAnnotation(self, row, col, ln, msg):
85 pass 99 pass
86 # Text modification: 100 # Text modification:
87 def getChar(self, pos): 101 def getChar(self, pos):
88 pass 102 pass
89 def insertText(self, txt): 103 def insertText(self, txt):
90 self.setSource(self.src[0:self.CursorPosition] + txt + self.src[self.CursorPosition:]) 104 self.setSource(self.src[0:self.CursorPosition] + txt + self.src[self.CursorPosition:])
91 self.CursorPosition += len(txt) 105 self.CursorPosition += len(txt)
92 self.textChanged.emit() 106 self.textChanged.emit()
93 def deleteChar(self): 107 def deleteChar(self):
94 self.setSource(self.src[0:self.CursorPosition] + self.src[self.CursorPosition+1:]) 108 self.setSource(self.src[0:self.CursorPosition] + self.src[self.CursorPosition+1:])
95 self.textChanged.emit() 109 self.textChanged.emit()
96 def GotoNextChar(self): 110 def GotoNextChar(self):
97 if self.src[self.CursorPosition] != '\n': 111 if self.src[self.CursorPosition] != '\n':
98 self.CursorPosition += 1 112 self.CursorPosition += 1
99 def GotoPrevChar(self): 113 def GotoPrevChar(self):
100 if self.src[self.CursorPosition - 1] != '\n': 114 if self.src[self.CursorPosition - 1] != '\n':
101 self.CursorPosition -= 1 115 self.CursorPosition -= 1
102 def GotoNextLine(self): 116 def GotoNextLine(self):
103 curLine = self.CurrentLine 117 curLine = self.CurrentLine
104 c = self.CursorCol - 1 # go to zero based 118 c = self.CursorCol - 1 # go to zero based
105 self.CursorPosition += len(curLine) - c + 1 # line break char! 119 self.CursorPosition += len(curLine) - c + 1 # line break char!
106 curLine = self.CurrentLine 120 curLine = self.CurrentLine
107 if len(curLine) < c: 121 if len(curLine) < c:
108 self.CursorPosition += len(curLine) 122 self.CursorPosition += len(curLine)
109 else: 123 else:
110 self.CursorPosition += c 124 self.CursorPosition += c
111 self.showRow(self.CursorRow) 125 self.showRow(self.CursorRow)
112 def GotoPrevLine(self): 126 def GotoPrevLine(self):
113 c = self.CursorCol - 1 # go to zero based 127 c = self.CursorCol - 1 # go to zero based
114 self.CursorPosition -= c + 1 # line break char! 128 self.CursorPosition -= c + 1 # line break char!
115 curLine = self.CurrentLine 129 curLine = self.CurrentLine
116 if len(curLine) > c: 130 if len(curLine) > c:
117 self.CursorPosition -= len(curLine) - c 131 self.CursorPosition -= len(curLine) - c
118 self.showRow(self.CursorRow) 132 self.showRow(self.CursorRow)
119 def paintEvent(self, event): 133 def paintEvent(self, event):
120 # Helper variables: 134 # Helper variables:
121 er = event.rect() 135 er = event.rect()
122 chw, chh = self.charWidth, self.charHeight 136 chw, chh = self.charWidth, self.charHeight
123 painter = QPainter(self) 137 painter = QPainter(self)
124 # Background: 138 # Background:
142 painter.fillRect(cursorX, cursorY, 2, chh, Qt.black) 156 painter.fillRect(cursorX, cursorY, 2, chh, Qt.black)
143 painter.setPen(Qt.black) 157 painter.setPen(Qt.black)
144 painter.drawText(self.xposLNA, ypos, '{0}'.format(row)) 158 painter.drawText(self.xposLNA, ypos, '{0}'.format(row))
145 xpos = self.xposTXT 159 xpos = self.xposTXT
146 painter.drawText(xpos, ypos, self.getRow(row)) 160 painter.drawText(xpos, ypos, self.getRow(row))
161 if self.arrow and self.arrow.row == row:
162 painter.drawPixmap(self.xposERR, ypos + ydt, self.arrowPixmap)
147 curErrors = [e for e in self.errorlist if e.loc.row == row] 163 curErrors = [e for e in self.errorlist if e.loc.row == row]
148 for e in curErrors: 164 for e in curErrors:
149 painter.drawPixmap(self.xposERR, ypos + ydt, self.errorPixmap) 165 painter.drawPixmap(self.xposERR, ypos + ydt, self.errorPixmap)
150 painter.setPen(errorPen) 166 painter.setPen(errorPen)
151 x = self.xposTXT + (e.loc.col - 1) * chw - 2 167 x = self.xposTXT + (e.loc.col - 1) * chw - 2
155 #painter.drawRoundedRect(x, ypos + ydt, wt, chh, 7, 7) 171 #painter.drawRoundedRect(x, ypos + ydt, wt, chh, 7, 7)
156 # print error balloon 172 # print error balloon
157 #painter.drawText(x, ypos + chh, e.msg) 173 #painter.drawText(x, ypos + chh, e.msg)
158 #if len(curErrors) > 0: 174 #if len(curErrors) > 0:
159 # ypos += chh 175 # ypos += chh
160
161 ypos += chh 176 ypos += chh
162 def keyPressEvent(self, event): 177
178 def keyPressEvent(self, event):
163 if event.matches(QKeySequence.MoveToNextChar): 179 if event.matches(QKeySequence.MoveToNextChar):
164 self.GotoNextChar() 180 self.GotoNextChar()
165 elif event.matches(QKeySequence.MoveToPreviousChar): 181 elif event.matches(QKeySequence.MoveToPreviousChar):
166 self.GotoPrevChar() 182 self.GotoPrevChar()
167 elif event.matches(QKeySequence.MoveToNextLine): 183 elif event.matches(QKeySequence.MoveToNextLine):
188 else: 204 else:
189 char = event.text() 205 char = event.text()
190 if char: 206 if char:
191 self.insertText(char) 207 self.insertText(char)
192 self.update() 208 self.update()
193 def mousePressEvent(self, event): 209
210 def mousePressEvent(self, event):
194 pos = event.pos() 211 pos = event.pos()
195 if pos.x() > self.xposTXT and pos.x(): 212 if pos.x() > self.xposTXT and pos.x():
196 c = round((pos.x() - self.xposTXT) / self.charWidth) 213 c = round((pos.x() - self.xposTXT) / self.charWidth)
197 r = int(pos.y() / self.charHeight) + 1 214 r = int(pos.y() / self.charHeight) + 1
198 self.setRowCol(r, c) 215 self.setRowCol(r, c)
199 def adjust(self): 216
217 def adjust(self):
200 metrics = self.fontMetrics() 218 metrics = self.fontMetrics()
201 self.charHeight = metrics.height() 219 self.charHeight = metrics.height()
202 self.charWidth = metrics.width('x') 220 self.charWidth = metrics.width('x')
203 self.charDescent = metrics.descent() 221 self.charDescent = metrics.descent()
204 self.xposERR = GAP 222 self.xposERR = GAP
221 self.setFocusPolicy(Qt.NoFocus) 239 self.setFocusPolicy(Qt.NoFocus)
222 self.showRow = self.ic.showRow 240 self.showRow = self.ic.showRow
223 self.setRowCol = self.ic.setRowCol 241 self.setRowCol = self.ic.setRowCol
224 self.FileName = None 242 self.FileName = None
225 Source = property(lambda s: s.ic.getSource(), lambda s, v: s.ic.setSource(v)) 243 Source = property(lambda s: s.ic.getSource(), lambda s, v: s.ic.setSource(v))
244
226 def setErrors(self, el): 245 def setErrors(self, el):
227 self.ic.setErrors(el) 246 self.ic.setErrors(el)
228 247
229 def setFocus(self): 248 def setFocus(self):
230 self.ic.setFocus() 249 self.ic.setFocus()
232 def setFileName(self, fn): 251 def setFileName(self, fn):
233 self.filename = fn 252 self.filename = fn
234 if not fn: 253 if not fn:
235 fn = 'Untitled' 254 fn = 'Untitled'
236 self.setWindowTitle(fn) 255 self.setWindowTitle(fn)
256
237 def getFileName(self): 257 def getFileName(self):
238 return self.filename 258 return self.filename
239 FileName = property(getFileName, setFileName) 259 FileName = property(getFileName, setFileName)
240 260
241 261
242 if __name__ == '__main__': 262 if __name__ == '__main__':
243 app = QApplication(sys.argv) 263 app = QApplication(sys.argv)
244 ce = CodeEdit() 264 ce = CodeEdit()
245 ce.show() 265 ce.show()
246 src = ''.join(inspect.getsourcelines(InnerCode)[0]) 266 src = ''.join(inspect.getsourcelines(InnerCode)[0])
247 ce.Source = src 267 ce.Source = src
248 print(ce.Source) 268 ce.resize(600, 800)
249 ce.resize(600, 800) 269 app.exec()
250 app.exec() 270
251