Browse Source

Added multicursor kayboard movements

pull/48/head
Eugenio Parodi 4 years ago
parent
commit
2d84c389ce
  1. 3
      TermTk/TTkCore/color.py
  2. 98
      TermTk/TTkGui/textcursor.py
  3. 4
      TermTk/TTkGui/textwrap.py
  4. 29
      TermTk/TTkWidgets/texedit.py
  5. 24
      demo/demo.py

3
TermTk/TTkCore/color.py

@ -252,6 +252,9 @@ class TTkColor(_TTkColor):
STRIKETROUGH = _TTkColor(mod='\033[9m')
''':strike:`Striketrough` modifier'''
BLINKING = _TTkColor(mod='\033[5m')
'''"Blinking" modifier'''
@staticmethod
def fg(*args, **kwargs):
''' Helper to generate a Foreground color

98
TermTk/TTkGui/textcursor.py

@ -22,6 +22,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.string import TTkString
from TermTk.TTkGui.textdocument import TTkTextDocument
@ -179,25 +180,67 @@ class TTkTextCursor():
def position(self):
return self._properties[0].position
def setPosition(self, line, pos, moveMode=MoveMode.MoveAnchor ):
def addCursor(self, line, pos):
self._properties.insert(0,
TTkTextCursor._prop(
TTkTextCursor._CP(line, pos),
TTkTextCursor._CP(line, pos)))
def cleanCursors(self):
self._properties = self._properties[:1]
def setPosition(self, line, pos, moveMode=MoveMode.MoveAnchor, cID=0):
# TTkLog.debug(f"{line=}, {pos=}, {moveMode=}")
self._properties[0].position.set(line,pos)
self._properties[cID].position.set(line,pos)
if moveMode==TTkTextCursor.MoveAnchor:
self._properties[0].anchor.set(line,pos)
self._properties[cID].anchor.set(line,pos)
def movePosition(self, operation, moveMode=MoveMode.MoveAnchor, n=1 ):
if operation == TTkTextCursor.Right:
p = self.position()
def movePosition(self, operation, moveMode=MoveMode.MoveAnchor, n=1, textWrap=None):
def moveRight(cID,p,_):
if p.pos < len(self._document._dataLines[p.line]):
self.setPosition(p.line, p.pos+1, moveMode)
self.setPosition(p.line, p.pos+1, moveMode, cID=cID)
elif p.line < len(self._document._dataLines)-1:
self.setPosition(p.line+1, 0, moveMode)
elif operation == TTkTextCursor.Left:
p = self.position()
self.setPosition(p.line+1, 0, moveMode, cID=cID)
def moveLeft(cID,p,_):
if p.pos > 0:
self.setPosition(p.line, p.pos-1, moveMode)
self.setPosition(p.line, p.pos-1, moveMode, cID=cID)
elif p.line > 0:
self.setPosition(p.line-1, len(self._document._dataLines[p.line-1]) , moveMode)
self.setPosition(p.line-1, len(self._document._dataLines[p.line-1]) , moveMode, cID=cID)
def moveUpDown(offset):
def _moveUpDown(cID,p,n):
cx, cy = textWrap.dataToScreenPosition(p.line, p.pos)
x, y = textWrap.normalizeScreenPosition(cx,cy+offset*n)
line, pos = textWrap.screenToDataPosition(x,y)
self.setPosition(line, pos, moveMode, cID=cID)
return _moveUpDown
def moveEnd(cID,p,_):
l = self._document._dataLines[p.line]
self.setPosition(p.line, len(l), moveMode, cID=cID)
def moveHome(cID,p,_):
self.setPosition(p.line, 0, moveMode, cID=cID)
operations = {
TTkTextCursor.Right : moveRight,
TTkTextCursor.Left : moveLeft,
TTkTextCursor.Up : moveUpDown(-1),
TTkTextCursor.Down : moveUpDown(+1),
TTkTextCursor.EndOfLine : moveEnd,
TTkTextCursor.StartOfLine: moveHome
}
for cID, prop in enumerate(self._properties):
p = prop.position
operations.get(operation,lambda _:_)(cID,p,n)
#if operation == TTkTextCursor.Right:
# if p.pos < len(self._document._dataLines[p.line]):
# self.setPosition(p.line, p.pos+1, moveMode, cID=cID)
# elif p.line < len(self._document._dataLines)-1:
# self.setPosition(p.line+1, 0, moveMode, cID=cID)
#elif operation == TTkTextCursor.Left:
# if p.pos > 0:
# self.setPosition(p.line, p.pos-1, moveMode, cID=cID)
# elif p.line > 0:
# self.setPosition(p.line-1, len(self._document._dataLines[p.line-1]) , moveMode, cID=cID)
def document(self):
return self._document
@ -272,13 +315,30 @@ class TTkTextCursor():
self._document.contentsChange.emit(a,b,c)
def getHighlightedLines(self, fr, to, color):
selSt = self.selectionStart()
selEn = self.selectionEnd()
ret = []
for i,l in enumerate(self._document._dataLines[fr:to+1],fr):
if selSt.line <= i <= selEn.line:
# Create a list of cursors (filtering out the ones which
# position/selection is outside the screen boundaries)
sel = []
for p in self._properties:
selSt = p.selectionStart()
selEn = p.selectionEnd()
if selEn.line >= fr and selSt.line<=to:
sel.append((selSt,selEn,p))
# Retrieve the sublist of lines to be required (displayed)
ret = self._document._dataLines[fr:to+1]
# Apply the selection color for each of them
for s in sel:
selSt, selEn, _ = s
for i in range(max(selSt.line,fr),min(selEn.line+1,to+1)):
l = ret[i-fr]
pf = 0 if i > selSt.line else selSt.pos
pt = len(l) if i < selEn.line else selEn.pos
l = l.setColor(color=color, posFrom=pf, posTo=pt)
ret.append(l)
ret[i-fr] = l.setColor(color=color, posFrom=pf, posTo=pt)
# Add Blinking cursor
if len(sel)>1:
for s in sel:
_, _, prop = s
p = prop.position
ret[p.line-fr] = (ret[p.line-fr]+" ").setColor(color=color+TTkColor.BLINKING, posFrom=p.pos, posTo=p.pos+1)
return ret

4
TermTk/TTkGui/textwrap.py

@ -78,7 +78,7 @@ class TTkTextWrap():
self._lines = []
if not self._enable:
def _process(i,l):
self._lines.append((i,(0,len(l))))
self._lines.append((i,(0,len(l)+1)))
else:
if not (w := self._wrapWidth):
return
@ -92,7 +92,7 @@ class TTkTextWrap():
while len(l):
fl = l.tab2spaces(self._tabSpaces)
if len(fl) <= w:
self._lines.append((i,(fr,fr+len(l))))
self._lines.append((i,(fr,fr+len(l)+1)))
l=[]
else:
to = max(1,l.tabCharPos(w,self._tabSpaces))

29
TermTk/TTkWidgets/texedit.py

@ -167,12 +167,16 @@ class _TTkTextEditView(TTkAbstractScrollView):
TTkHelper.showCursor(TTkK.Cursor_Blinking_Bar)
self.update()
def _setCursorPos(self, x, y, moveAnchor=True, newCursor=False):
def _setCursorPos(self, x, y, moveAnchor=True, addCursor=False):
x,y = self._textWrap.normalizeScreenPosition(x,y)
line, pos = self._textWrap.screenToDataPosition(x,y)
TTkLog.debug(f"{newCursor=}")
self._textCursor.setPosition(line, pos,
moveMode=TTkTextCursor.MoveAnchor if moveAnchor else TTkTextCursor.KeepAnchor)
TTkLog.debug(f"{addCursor=}")
if addCursor:
self._textCursor.addCursor(line, pos)
else:
self._textCursor.cleanCursors()
self._textCursor.setPosition(line, pos,
moveMode=TTkTextCursor.MoveAnchor if moveAnchor else TTkTextCursor.KeepAnchor )
self._scrolToInclude(x,y)
return x, y
@ -188,7 +192,7 @@ class _TTkTextEditView(TTkAbstractScrollView):
if self._readOnly:
return super().mousePressEvent(evt)
ox, oy = self.getViewOffsets()
self._setCursorPos(evt.x + ox, evt.y + oy, newCursor=evt.mod&TTkK.ControlModifier==TTkK.ControlModifier)
self._setCursorPos(evt.x + ox, evt.y + oy, addCursor=evt.mod&TTkK.ControlModifier==TTkK.ControlModifier)
self.update()
return True
@ -227,14 +231,14 @@ class _TTkTextEditView(TTkAbstractScrollView):
# Don't Handle the special tab key, for now
if evt.key == TTkK.Key_Tab:
return False
if evt.key == TTkK.Key_Up: self._setCursorPos(cx , cy-1)
elif evt.key == TTkK.Key_Down: self._setCursorPos(cx , cy+1)
if evt.key == TTkK.Key_Up: self._textCursor.movePosition(TTkTextCursor.Up, textWrap=self._textWrap)
elif evt.key == TTkK.Key_Down: self._textCursor.movePosition(TTkTextCursor.Down, textWrap=self._textWrap)
elif evt.key == TTkK.Key_Left: self._textCursor.movePosition(TTkTextCursor.Left)
elif evt.key == TTkK.Key_Right: self._textCursor.movePosition(TTkTextCursor.Right)
elif evt.key == TTkK.Key_End: self._setCursorPos(w , cy )
elif evt.key == TTkK.Key_Home: self._setCursorPos(0 , cy )
elif evt.key == TTkK.Key_PageUp: self._setCursorPos(cx , cy - h)
elif evt.key == TTkK.Key_PageDown: self._setCursorPos(cx , cy + h)
elif evt.key == TTkK.Key_End: self._textCursor.movePosition(TTkTextCursor.EndOfLine)
elif evt.key == TTkK.Key_Home: self._textCursor.movePosition(TTkTextCursor.StartOfLine)
elif evt.key == TTkK.Key_PageUp: self._textCursor.movePosition(TTkTextCursor.Up, textWrap=self._textWrap, n=h) #self._setCursorPos(cx , cy - h)
elif evt.key == TTkK.Key_PageDown: self._textCursor.movePosition(TTkTextCursor.Down, textWrap=self._textWrap, n=h) #self._setCursorPos(cx , cy + h)
elif evt.key == TTkK.Key_Insert:
self._replace = not self._replace
self._setCursorPos(cx , cy)
@ -249,6 +253,9 @@ class _TTkTextEditView(TTkAbstractScrollView):
elif evt.key == TTkK.Key_Enter:
self._textCursor.insertText('\n')
self._textCursor.movePosition(TTkTextCursor.Right)
p = self._textCursor.position()
cx, cy = self._textWrap.dataToScreenPosition(p.line, p.pos)
self._scrolToInclude(cx,cy)
self.update()
return True
else: # Input char

24
demo/demo.py

@ -66,29 +66,29 @@ def stupidPythonHighlighter(txt):
return ret
# Operators
txt = _colorize(re.compile('[\+\*\/\=\-\<\>\!]'), txt, ttk.TTkColor.fg('#00AAAA'))
txt = _colorize(re.compile(r'[\+\*\/\=\-\<\>\!]'), txt, ttk.TTkColor.fg('#00AAAA'))
# Bool
txt = _colorize(re.compile('True|False'), txt, ttk.TTkColor.fg('#0000FF'))
txt = _colorize(re.compile(r'True|False'), txt, ttk.TTkColor.fg('#0000FF'))
# Numbers
txt = _colorize(re.compile('[0-9]'), txt, ttk.TTkColor.fg('#00FFFF'))
txt = _colorize(re.compile(r'[0-9]'), txt, ttk.TTkColor.fg('#00FFFF'))
# Functions
txt = _colorize(re.compile('[ \t]*def[ \t]*'), txt, ttk.TTkColor.fg('#00FFFF'))
txt = _colorize(re.compile('[^= \t\.\()]*[\t ]*\('), txt, ttk.TTkColor.fg('#AAAA00'))
txt = _colorize(re.compile(r'[ \t]*def[ \t]*'), txt, ttk.TTkColor.fg('#00FFFF'))
txt = _colorize(re.compile(r'[^= \t\.\()]*[\t ]*\('), txt, ttk.TTkColor.fg('#AAAA00'))
# Objects
txt = _colorize(re.compile('[^= \t\.\()]*\.'), txt, ttk.TTkColor.fg('#44AA00'))
txt = _colorize(re.compile(r'[^= \t\.\()]*\.'), txt, ttk.TTkColor.fg('#44AA00'))
# Fix Extra colors
txt = _colorize(re.compile('[\(\)]'), txt, ttk.TTkColor.RST)
txt = _colorize(re.compile("'[^']*'"), txt, ttk.TTkColor.fg('#FF8800'))
txt = _colorize(re.compile(r'[\(\)]'), txt, ttk.TTkColor.RST)
txt = _colorize(re.compile(r"'[^']*'"), txt, ttk.TTkColor.fg('#FF8800'))
# Strings
txt = _colorize(re.compile('"[^"]*"'), txt, ttk.TTkColor.fg('#FF8800'))
txt = _colorize(re.compile("'[^']*'"), txt, ttk.TTkColor.fg('#FF8800'))
txt = _colorize(re.compile(r'"[^"]*"'), txt, ttk.TTkColor.fg('#FF8800'))
txt = _colorize(re.compile(r"'[^']*'"), txt, ttk.TTkColor.fg('#FF8800'))
# Comments
txt = _colorize(re.compile('#.*\n'), txt, ttk.TTkColor.fg('#00FF00'))
txt = _colorize(re.compile(r'#.*\n'), txt, ttk.TTkColor.fg('#00FF00'))
return txt
def showSource(file):
@ -260,6 +260,6 @@ if __name__ == "__main__":
main()
def test_demo():
root = ttk.TTk()
root = ttk.TTk(layout=ttk.TTkGridLayout())
assert demoShowcase(root) != None
root.quit()
Loading…
Cancel
Save