fenrir/src/fenrirscreenreader/core/attributeManager.py

291 lines
11 KiB
Python
Raw Normal View History

2018-05-24 11:31:21 +02:00
#!/bin/python
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.core import debug
2018-05-27 14:31:00 +02:00
from collections import Counter
2018-05-24 11:31:21 +02:00
class attributeManager():
def __init__(self):
2018-05-28 09:59:18 +02:00
self.currAttributes = None
self.prevAttributes = None
2018-05-28 10:42:08 +02:00
self.currAttributeDelta = ''
self.currAttributeCursor = None
self.prefAttributeCursor = None
2019-11-04 22:31:36 +01:00
self.initDefaultAttributes()
self.prevLastCursorAttribute = None
self.currLastCursorAttribute = None
2018-05-24 11:31:21 +02:00
def initialize(self, environment):
2019-11-04 22:31:36 +01:00
self.env = environment
2018-05-24 11:31:21 +02:00
def shutdown(self):
pass
2018-05-28 23:29:29 +02:00
def setLastCursorAttribute(self, lastCursorAttribute):
self.prevLastCursorAttribute = self.currLastCursorAttribute
2019-11-04 22:31:36 +01:00
self.currLastCursorAttribute = lastCursorAttribute
2019-02-03 23:34:27 +01:00
def resetLastCursorAttribute(self):
2018-05-28 23:29:29 +02:00
self.prevLastCursorAttribute = None
2019-11-04 22:31:36 +01:00
self.currLastCursorAttribute = None
2018-05-28 23:29:29 +02:00
def isLastCursorAttributeChange(self):
if self.prevLastCursorAttribute == None:
2018-06-04 06:09:51 +02:00
return False
2018-05-28 23:29:29 +02:00
return self.prevLastCursorAttribute != self.currLastCursorAttribute
2018-05-28 22:24:27 +02:00
def getCurrAttributeCursor(self):
return self.currAttributeCursor
def isAttributeCursorActive(self):
return self.currAttributeCursor != None
2018-05-28 22:18:51 +02:00
def isAttributeChange(self):
if not self.prevAttributes:
return False
return self.currAttributes != self.prevAttributes
2018-05-28 13:55:13 +02:00
def resetAttributeAll(self):
self.resetAttributeDelta()
self.resetAttributeCursor()
2019-11-04 22:31:36 +01:00
def getAttributeDelta(self):
return self.currAttributeDelta
2018-05-28 10:42:08 +02:00
def resetAttributeDelta(self):
2019-11-04 22:31:36 +01:00
self.currAttributeDelta = ''
def setAttributeDelta(self, currAttributeDelta):
2018-05-28 14:32:04 +02:00
self.currAttributeDelta = currAttributeDelta
2018-05-28 10:42:08 +02:00
def resetAttributeCursor(self):
self.currAttributeCursor = None
self.prefAttributeCursor = None
2018-05-28 22:18:51 +02:00
def setAttributeCursor(self, currAttributeCursor):
2019-11-04 22:31:36 +01:00
self.prefAttributeCursor = self.currAttributeCursor
2018-05-28 22:18:51 +02:00
self.currAttributeCursor = currAttributeCursor.copy()
def resetAttributes(self, currAttributes):
2019-11-04 22:31:36 +01:00
self.prevAttributes = None
self.currAttributes = currAttributes
2018-05-28 22:18:51 +02:00
def setAttributes(self, currAttributes):
2019-11-04 22:31:36 +01:00
self.prevAttributes = self.currAttributes
2018-05-28 10:42:08 +02:00
self.currAttributes = currAttributes.copy()
2019-11-04 22:31:36 +01:00
2018-05-28 10:32:13 +02:00
def getAttributeByXY(self, x, y):
if not self.currAttributes:
return None
if len(self.currAttributes) < y:
return None
2018-05-28 22:18:51 +02:00
if len(self.currAttributes[y]) < x - 1:
2019-11-04 22:31:36 +01:00
return None
try:
2018-05-28 23:29:29 +02:00
return self.currAttributes[y][x]
2018-05-28 22:18:51 +02:00
except KeyError:
try:
return self.defaultAttributes[0]
except:
pass
return None
2018-06-04 06:09:51 +02:00
def appendDefaultAttributes(self, attribute):
if not attribute:
return
if len(attribute) != 10:
return
2019-11-04 22:31:36 +01:00
self.defaultAttributes.append(attribute)
2018-06-04 06:09:51 +02:00
def initDefaultAttributes(self):
2018-05-29 18:52:28 +02:00
self.defaultAttributes = [None]
self.defaultAttributes.append([
2018-05-28 22:18:51 +02:00
'default', # fg
'default', # bg
2018-05-25 12:50:24 +02:00
False, # bold
False, # italics
False, # underscore
False, # strikethrough
False, # reverse
False, # blink
'default', # fontsize
'default' # fontfamily
2019-11-04 22:31:36 +01:00
]) #end attribute
2018-05-28 23:29:29 +02:00
def isDefaultAttribute(self,attribute):
2018-05-29 10:54:22 +02:00
return attribute in self.defaultAttributes
2018-05-28 23:29:29 +02:00
def hasAttributes(self, cursor, update=True):
if not cursor:
return False
cursorPos = cursor.copy()
try:
2018-05-29 10:54:22 +02:00
attribute = self.getAttributeByXY( cursorPos['x'], cursorPos['y'])
2018-06-04 06:09:51 +02:00
2018-05-28 23:29:29 +02:00
if update:
2019-11-04 22:31:36 +01:00
self.setLastCursorAttribute(attribute)
2018-05-28 23:29:29 +02:00
if not self.isLastCursorAttributeChange():
return False
2018-06-04 06:09:51 +02:00
if self.isDefaultAttribute(attribute):
return False
2018-05-28 23:29:29 +02:00
except Exception as e:
return False
return True
2018-06-04 06:09:51 +02:00
2018-05-30 23:44:54 +02:00
def formatAttributes(self, attribute, attributeFormatString = ''):
2018-05-25 12:56:03 +02:00
# "black",
# "red",
# "green",
# "brown",
# "blue",
# "magenta",
# "cyan",
# "white",
# "default" # white.
# _order_
# "fg",
# "bg",
# "bold",
# "italics",
# "underscore",
# "strikethrough",
2019-11-04 22:31:36 +01:00
# "reverse",
# "blink"
2018-05-25 12:56:03 +02:00
# "fontsieze"
2019-11-04 22:31:36 +01:00
# "fontfamily"
2018-05-30 23:44:54 +02:00
if attributeFormatString == '':
2018-05-24 11:31:21 +02:00
attributeFormatString = self.env['runtime']['settingsManager'].getSetting('general', 'attributeFormatString')
if not attributeFormatString:
return ''
if attributeFormatString == '':
return ''
2018-05-25 12:56:03 +02:00
if not attribute:
return ''
if len(attribute) != 10:
return ''
2019-11-04 22:31:36 +01:00
2018-05-25 12:56:03 +02:00
# 0 FG color (name)
try:
attributeFormatString = attributeFormatString.replace('fenrirFGColor', _(attribute[0]))
except Exception as e:
attributeFormatString = attributeFormatString.replace('fenrirFGColor', '')
# 1 BG color (name)
try:
attributeFormatString = attributeFormatString.replace('fenrirBGColor', _(attribute[1]))
except Exception as e:
attributeFormatString = attributeFormatString.replace('fenrirBGColor', '')
# 2 bold (True/ False)
try:
if attribute[2]:
attributeFormatString = attributeFormatString.replace('fenrirBold', _('bold'))
except Exception as e:
pass
attributeFormatString = attributeFormatString.replace('fenrirBold', '')
2019-11-04 22:31:36 +01:00
# 3 italics (True/ False)
2018-05-24 11:31:21 +02:00
try:
2019-11-04 22:31:36 +01:00
if attribute[3]:
2018-05-25 12:56:03 +02:00
attributeFormatString = attributeFormatString.replace('fenrirItalics', _('italic'))
2018-05-24 11:31:21 +02:00
except Exception as e:
2018-05-25 12:56:03 +02:00
pass
attributeFormatString = attributeFormatString.replace('fenrirItalics', '')
# 4 underline (True/ False)
2018-05-24 11:31:21 +02:00
try:
2018-05-25 12:56:03 +02:00
if attribute[4]:
attributeFormatString = attributeFormatString.replace('fenrirUnderline', _('underline'))
2018-05-24 11:31:21 +02:00
except Exception as e:
2018-05-25 12:56:03 +02:00
pass
attributeFormatString = attributeFormatString.replace('fenrirUnderline', '')
# 5 strikethrough (True/ False)
2018-05-24 11:31:21 +02:00
try:
2018-05-25 12:56:03 +02:00
if attribute[5]:
attributeFormatString = attributeFormatString.replace('fenrirStrikethrough', _('strikethrough'))
2018-05-24 11:31:21 +02:00
except Exception as e:
2018-05-25 12:56:03 +02:00
pass
attributeFormatString = attributeFormatString.replace('fenrirStrikethrough', '')
# 6 reverse (True/ False)
2018-05-24 11:31:21 +02:00
try:
2019-11-04 22:31:36 +01:00
if attribute[6]:
2018-05-25 12:56:03 +02:00
attributeFormatString = attributeFormatString.replace('fenrirReverse', _('reverse'))
2018-05-24 11:31:21 +02:00
except Exception as e:
2018-05-25 12:56:03 +02:00
pass
attributeFormatString = attributeFormatString.replace('fenrirReverse', '')
2019-11-04 22:31:36 +01:00
# 7 blink (True/ False)
2018-05-24 11:31:21 +02:00
try:
2019-11-04 22:31:36 +01:00
if attribute[7]:
2018-05-25 12:56:03 +02:00
attributeFormatString = attributeFormatString.replace('fenrirBlink', _('blink'))
2018-05-24 11:31:21 +02:00
except Exception as e:
2018-05-25 12:56:03 +02:00
pass
attributeFormatString = attributeFormatString.replace('fenrirBlink', '')
# 8 font size (int/ string)
2018-05-24 11:31:21 +02:00
try:
2018-05-25 12:56:03 +02:00
try:
attributeFormatString = attributeFormatString.replace('fenrirFontSize', int(attribute[8]))
except:
pass
try:
attributeFormatString = attributeFormatString.replace('fenrirFontSize', str(attribute[8]))
except:
pass
2018-05-24 11:31:21 +02:00
except Exception as e:
2018-05-25 12:56:03 +02:00
pass
attributeFormatString = attributeFormatString.replace('fenrirFontSize', _('default'))
# 9 font family (string)
2018-05-24 11:31:21 +02:00
try:
2018-05-25 12:56:03 +02:00
attributeFormatString = attributeFormatString.replace('fenrirFont', attribute[9])
2018-05-24 11:31:21 +02:00
except Exception as e:
2018-05-25 12:56:03 +02:00
pass
attributeFormatString = attributeFormatString.replace('fenrirFont', _('default'))
2018-05-25 02:56:03 +02:00
return attributeFormatString
2018-05-28 22:18:51 +02:00
def trackHighlights(self):
2018-05-27 14:31:00 +02:00
result = ''
currCursor = None
2018-05-28 09:50:37 +02:00
# screen change
2018-05-28 22:18:51 +02:00
if self.prevAttributes == None:
2019-11-04 22:31:36 +01:00
return result, currCursor
2018-05-28 09:50:37 +02:00
# no change
2018-05-28 22:18:51 +02:00
if self.prevAttributes == self.currAttributes:
2018-05-27 22:44:17 +02:00
return result, currCursor
2018-05-28 09:59:18 +02:00
# error case
2018-05-28 22:18:51 +02:00
if self.currAttributes == None:
2019-11-04 22:31:36 +01:00
return result, currCursor
2018-05-28 09:50:37 +02:00
# special case for pty if not text exists.
2018-05-28 22:18:51 +02:00
if len(self.currAttributes) == 0:
2019-11-04 22:31:36 +01:00
return result, currCursor
2018-05-28 22:18:51 +02:00
text = self.env['runtime']['screenManager'].getScreenText()
2018-05-27 14:31:00 +02:00
textLines = text.split('\n')
2018-05-28 22:18:51 +02:00
if len(textLines) != len(self.currAttributes):
2018-05-27 14:31:00 +02:00
return result, currCursor
2018-05-28 22:18:51 +02:00
for line in range(len(self.prevAttributes)):
if self.prevAttributes[line] != self.currAttributes[line]:
for column in range(len(self.prevAttributes[line])):
2018-06-09 13:59:54 +02:00
if self.prevAttributes[line][column] == self.currAttributes[line][column]:
continue
if self.isUsefulForTracking(line, column, self.currAttributes, self.prevAttributes):
if not currCursor:
currCursor = {'x': column, 'y': line}
result += textLines[line][column]
2018-05-27 14:31:00 +02:00
result += ' '
2018-06-09 13:59:54 +02:00
return result, currCursor
2018-06-12 10:07:17 +02:00
def isUsefulForTracking(self, line, column, currAttributes, prevAttributes, attribute=1 , mode = 'zaxe'):
2018-06-09 13:59:54 +02:00
if len(currAttributes) <= 3:
return False
if line < 0:
return False
if line > len(currAttributes):
2019-11-04 22:31:36 +01:00
return False
2018-06-09 13:59:54 +02:00
useful = False
2018-06-12 10:07:17 +02:00
if mode == 'default':
# non default tracking
useful = not self.isDefaultAttribute(currAttributes[line][column])
elif (mode == 'zaxe') or (mode == ''):
# arround me tracking for bg
if line == 0:
useful = (currAttributes[line][column][attribute] != currAttributes[line + 1][column][attribute]) and (currAttributes[line][column][attribute] != currAttributes[line + 2][column][attribute])
elif line >= len(prevAttributes):
2019-11-04 22:31:36 +01:00
useful = (currAttributes[line][column][attribute] != currAttributes[line - 1][column][attribute]) and (currAttributes[line][column][attribute] != currAttributes[line - 2][column][attribute])
2018-06-12 10:07:17 +02:00
else:
2019-11-04 22:31:36 +01:00
useful = (currAttributes[line][column][attribute] != currAttributes[line + 1][column][attribute]) and (currAttributes[line][column][attribute] != currAttributes[line - 1][column][attribute])
2018-06-12 10:07:17 +02:00
elif mode == 'barrier':
# to be implement
useful = True
2019-11-04 22:31:36 +01:00
2018-06-09 13:59:54 +02:00
return useful