diff python/codeedit.py @ 160:10330be89bc2

Started from scratch with code edit
author Windel Bouwman
date Sat, 09 Mar 2013 11:56:48 +0100
parents
children 956f8e5ee48a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/codeedit.py	Sat Mar 09 11:56:48 2013 +0100
@@ -0,0 +1,159 @@
+#!/usr/bin/python
+
+import sys
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+import inspect
+
+GAP = 5
+
+def clipVal(v, mn, mx):
+   if v < mn: return mn
+   if v > mx: return mx
+   return v
+
+class InnerCode(QWidget):
+   def __init__(self, scrollArea):
+      super().__init__(scrollArea)
+      self.scrollArea = scrollArea
+      self.setFont(QFont('Courier', 16))
+      self.setFocusPolicy(Qt.StrongFocus)
+      self.blinkcursor = False
+      # Initial values:
+      self.setSource('')
+      self.CursorPosition = 0
+      t = QTimer(self)
+      t.timeout.connect(self.updateCursor)
+      t.setInterval(500)
+      t.start()
+   def updateCursor(self):
+      self.blinkcursor = not self.blinkcursor
+      self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight)
+   def setSource(self, src):
+      self.src = src
+      self.adjust()
+   def setCursorPosition(self, c):
+      self.cursorPosition = clipVal(c, 0, len(self.src))
+      print(self.cursorPosition, self.CursorRow, self.CursorCol)
+      self.cursorX = self.CursorCol * self.charWidth + self.xposTXT - self.charWidth
+      self.cursorY = self.CursorRow * self.charHeight - self.charHeight
+   CursorPosition = property(lambda self: self.cursorPosition, setCursorPosition)
+   @property
+   def CursorRow(self):
+      # TODO: make this nice.
+      txt = self.src[0:self.cursorPosition]
+      return len(txt.split('\n'))
+   @property
+   def CursorCol(self):
+      txt = self.src[0:self.cursorPosition]
+      curLine = txt.split('\n')[-1]
+      return len(curLine) + 1
+   @property
+   def CurrentLine(self):
+      return self.getRow(self.CursorRow)
+   def getRow(self, r):
+      rows = self.src.split('\n')
+      r = r - 1
+      if r < 0 or r > len(rows) - 1:
+         return ''
+      else:
+         return rows[r]
+   def getChar(self, pos):
+      pass
+   def insertText(self, txt):
+      self.setSource(self.src[0:self.CursorPosition] + txt + self.src[self.CursorPosition:])
+      self.CursorPosition += len(txt)
+   def GotoNextChar(self):
+      if self.src[self.CursorPosition] != '\n':
+         self.CursorPosition += 1
+   def GotoPrevChar(self):
+      if self.src[self.CursorPosition - 1] != '\n':
+         self.CursorPosition -= 1
+   def GotoNextLine(self):
+      curLine = self.CurrentLine
+      c = self.CursorCol
+      self.CursorPosition += len(curLine) - c + c + 1 # line break char!
+   def GotoPrevLine(self):
+      curLine = self.CurrentLine
+      c = self.CursorCol
+      self.CursorPosition -= len(curLine) + c + 1 # line break char!
+   def paintEvent(self, event):
+      # Helper variables:
+      er = event.rect()
+      chw, chh = self.charWidth, self.charHeight
+      painter = QPainter(self)
+      # Background:
+      painter.fillRect(er, self.palette().color(QPalette.Base))
+      painter.fillRect(QRect(self.xposLNA, er.top(), 8 * chw, er.bottom() + 1), Qt.gray)
+      painter.fillRect(self.xposTXT, (self.CursorRow - 1) * chh, er.width(), chh, Qt.yellow)
+      painter.setPen(Qt.gray)
+      # first and last row:
+      row1 = max(int(er.top() / chh) - 1, 0)
+      row2 = max(int(er.bottom() / chh) + 1, 0)
+      # Draw contents:
+      txt = self.src.split('\n')
+      print('update', row1, row2)
+      for row in range(row1, row2 + 1):
+         ypos = row * chh
+         painter.setPen(Qt.black)
+         painter.drawText(self.xposLNA, ypos, 'R ={0}'.format(row))
+         xpos = self.xposTXT
+         if row - 1 < len(txt):
+            painter.drawText(xpos, ypos, txt[row - 1])
+      # cursor
+      if self.blinkcursor:
+         painter.fillRect(self.cursorX, self.cursorY, 2, chh, Qt.black)
+   def keyPressEvent(self, event):
+      if event.matches(QKeySequence.MoveToNextChar):
+         self.GotoNextChar()
+      if event.matches(QKeySequence.MoveToPreviousChar):
+         self.GotoPrevChar()
+      if event.matches(QKeySequence.MoveToNextLine):
+         self.GotoNextLine()
+      if event.matches(QKeySequence.MoveToPreviousLine):
+         self.GotoPrevLine()
+      if event.matches(QKeySequence.MoveToNextPage):
+         for i in range(5):
+            self.GotoNextLine()
+      if event.matches(QKeySequence.MoveToPreviousPage):
+         for i in range(5):
+            self.GotoPrevLine()
+      if event.matches(QKeySequence.MoveToEndOfLine):
+         self.CursorPosition += len(self.CurrentLine) - self.CursorCol + 1
+      if event.matches(QKeySequence.MoveToStartOfLine):
+         self.CursorPosition -= self.CursorCol - 1
+      char = event.text().lower()
+      if char:
+         print('ins', char)
+         self.insertText(char)
+      self.update()
+   def adjust(self):
+      self.charHeight = self.fontMetrics().height()
+      self.charWidth = self.fontMetrics().width('x')
+      self.xposLNA = GAP
+      self.xposTXT = self.xposLNA + 8 * self.charWidth + GAP
+      self.xposEnd = self.xposTXT + self.charWidth * 80
+      self.setMinimumWidth(self.xposEnd)
+      txt = self.src.split('\n')
+      self.setMinimumHeight(self.charHeight * len(txt))
+      self.update()
+
+class CodeEdit(QScrollArea):
+   def __init__(self):
+      super().__init__()
+      self.ic = InnerCode(self)
+      self.setWidget(self.ic)
+      self.setWidgetResizable(True)
+      self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
+      self.setFocusPolicy(Qt.NoFocus)
+   Source = property(lambda s: s.ic.getSource(), lambda s, v: s.ic.setSource(v))
+
+if __name__ == '__main__':
+   app = QApplication(sys.argv)
+   ce = CodeEdit()
+   ce.show()
+   src = ''.join(inspect.getsourcelines(InnerCode)[0])
+   ce.Source = src
+   ce.resize(600, 500)
+   app.exec()
+