Tue, 12 Mar 2019 20:00:30 +0100
SubstyledLexer: continued implementing the getter and setter methods.
# -*- coding: utf-8 -*- # Copyright (c) 2003 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the lexer mixin class. """ from __future__ import unicode_literals import copy from PyQt5.QtGui import QColor from .Lexer import Lexer import Preferences class SubstyledLexer(Lexer): """ Class to implement the sub-styled lexer mixin class. """ def __init__(self): """ Constructor """ super(SubstyledLexer, self).__init__() self.baseStyles = [] # list of style numbers, that support sub-styling self.defaultSubStyles = {} # dictionary with sub-styling data # main key: base style number, value : dict with # key: sub-style number, value: dict with # 'Description': string containing a short description # 'Words': string of whitespace separated words to be styled # 'Style': dictionary with styling data (only difference to # the base style is required # 'fore': foreground color (int containing RGB values) # 'paper': background color (int containing RGB values) # 'eolfill': fill to eol (bool) # 'font_family': font family (str) # 'font_size: point size (int) # 'font_bold: bold font (bool) # 'font_italic: italic font (bool) # 'font_underline: underlined font (bool) self.__subStyles = {} self.__subStylesInitialized = False def loadSubstyles(self): """ Public method to load the sub-styles from the settings file """ settings = Preferences.Prefs.settings self.loadDefaultSubStyles() for baseStyle in self.baseStyles: key = "Scintilla/{0}/style{1}/SubStyleLength".format( self.language(), baseStyle) if settings.contains(key): subStyleLength = int(settings.value(key), 0) self.__subStyles[baseStyle] = {} if subStyleLength: self.__subStyles[baseStyle] = [] for subStyle in range(subStyleLength): baseKey = "Scintilla/{0}/style{1}/substyle{2}/".format( self.language(), baseStyle, subStyle) if settings.contains(baseKey): subStyleData = {} subStyleData["Description"] = settings.value( baseKey + "Description", "") subStyleData["Words"] = settings.value( baseKey + "Words", "") style = {} key = baseKey + "fore" if settings.contains(key): style["fore"] = int(settings.value(key)) key = baseKey + "paper" if settings.contains(key): style["paper"] = int(settings.value(key)) key = baseKey + "eolfill" if settings.contains(key): style["eolfill"] = Preferences.toBool( settings.value(key)) key = baseKey + "font_family" if settings.contains(key): style["font_family"] = settings.value(key) key = baseKey + "font_size" if settings.contains(key): style["font_size"] = int(settings.value(key)) key = baseKey + "font_bold" if settings.contains(key): style["font_bold"] = Preferences.toBool( settings.value(key)) key = baseKey + "font_italic" if settings.contains(key): style["font_italic"] = Preferences.toBool( settings.value(key)) key = baseKey + "font_underline" if settings.contains(key): style["font_underline"] = Preferences.toBool( settings.value(key)) subStyleData["Style"] = style self.__subStyles[baseStyle][subStyle] = \ subStyleData self.__subStylesInitialized = True def loadDefaultSubStyles(self): """ Public method to load the default sub-style definitions. """ self.__subStyles = copy.deepcopy(self.defaultSubStyles) def readSubstyles(self, editor): """ Public method to load the sub-styles and configure the editor. @param editor reference to the editor object @type QsciScintilla """ subStyleBasesLength = editor.SendScintilla( editor.SCI_GETSUBSTYLEBASES, 0, None) if not subStyleBasesLength: # lexer does not support sub-styling return self.loadSubstyles() # free existing sub-styles first editor.SendScintilla(editor.SCI_FREESUBSTYLES) subStyleBases = b"\00" * (subStyleBasesLength + 1) editor.SendScintilla(editor.SCI_GETSUBSTYLEBASES, 0, subStyleBases) distanceToSecondary = editor.SendScintilla( editor.SCI_DISTANCETOSECONDARYSTYLES) subStyleBases = [b for b in bytearray(subStyleBases[:-1])] if distanceToSecondary: subStyleBases.extend(b + distanceToSecondary for b in subStyleBases[:]) for baseStyleNo in subStyleBases: if baseStyleNo in self.__subStyles: subStylesData = self.__subStyles[baseStyleNo] subStyleLength = len(subStylesData) subStyleStart = editor.SendScintilla( editor.SCI_ALLOCATESUBSTYLES, baseStyleNo, subStyleLength) if subStyleStart < 0: subStyleLength = 0 for subStyleIndex in range(subStyleLength): styleNo = subStyleStart + subStyleIndex subStyle = subStylesData[subStyleIndex] # set the words editor.SendScintilla( editor.SCI_SETIDENTIFIERS, styleNo, subStyle["Words"].encode()) # set the style style = subStyle["Style"] if "fore" in style: color = QColor( style["fore"] >> 16 & 0xff, style["fore"] >> 8 & 0xff, style["fore"] & 0xff, ) else: color = self.color(baseStyleNo) self.setColor(color, styleNo) if "paper" in style: color = QColor( style["paper"] >> 16 & 0xff, style["paper"] >> 8 & 0xff, style["paper"] & 0xff, ) else: color = self.paper(baseStyleNo) self.setPaper(color, styleNo) if "eolfill" in style: eolFill = style["eolfill"] else: eolFill = self.eolFill(baseStyleNo) self.setEolFill(eolFill, styleNo) font = self.font(baseStyleNo) if "font_family" in style: font.setFamily(style["font_family"]) if "font_size" in style: font.setPointSize(style["font_size"]) if "font_bold" in style: font.setBold(style["font_bold"]) if "font_italic" in style: font.setItalic(style["font_italic"]) if "font_underline" in style: font.setUnderline(style["font_underline"]) self.setFont(font, styleNo) def writeSubstyles(self): """ Public method to save the sub-styles. """ if not self.__subStylesInitialized: # make sure, the sub-styles have been initialized self.loadSubstyles() settings = Preferences.Prefs.settings for baseStyle in self.baseStyles: key = "Scintilla/{0}/style{1}/SubStyleLength".format( self.language(), baseStyle) settings.setValue(key, len(self.__subStyles[baseStyle])) for subStyle in self.__subStyles[baseStyle]: baseKey = "Scintilla/{0}/style{1}/substyle{2}/".format( self.language(), baseStyle, subStyle) subStyleData = self.__subStyles[baseStyle][subStyle] settings.setValue(baseKey + "Description", subStyleData["Description"]) settings.setValue(baseKey + "Words", subStyleData["Words"]) style = subStyleData["Style"] if "fore" in style: color = style["fore"] else: col = self.color(baseStyle) color = col.red() << 16 | col.green() << 8 | col.blue() settings.setValue(baseKey + "fore", color) if "paper" in style: color = style["paper"] else: col = self.paper(baseStyle) color = col.red() << 16 | col.green() << 8 | col.blue() settings.setValue(baseKey + "paper", color) if "eolfill" in style: eolfill = style["eolfill"] else: eolfill = self.eolFill(baseStyle) settings.setValue(baseKey + "eolfill", eolfill) font = self.font(baseStyle) if "font_family" in style: family = style["font_family"] else: family = font.family() settings.setValue(baseKey + "font_family", family) if "font_size" in style: size = style["font_size"] else: size = font.pointSize() settings.setValue(baseKey + "font_size", size) if "font_bold" in style: bold = style["font_bold"] else: bold = font.bold() settings.setValue(baseKey + "font_bold", bold) if "font_italic" in style: italic = style["font_italic"] else: italic = font.italic() settings.setValue(baseKey + "font_italic", italic) if "font_underline" in style: underline = style["font_underline"] else: underline = font.underline() settings.setValue(baseKey + "font_underline", underline) def hasSubStyles(self): """ Public method to indicate the support of sub-styles. @return flag indicating sub-styling support @rtype bool """ return True def getBaseStyles(self): """ Public method to get the list of supported base styles. @return list of base styles @rtype list of int """ return self.baseStyles[:] def substylesCount(self, style): """ Public method to get the number of defined sub-styles. @return number of defined sub-styles @rtype int """ if style in self.__subStyles: count = len(self.__subStyles[style]) else: count = 0 return count def setSubstyleDescription(self, description, style, substyle): """ Public method to set the description for a sub-style. @param description description to be set @type str @param style base style number @type int @param substyle sub-style number @type int """ if style in self.__subStyles and substyle in self.__subStyles[style]: self.__subStyles[style][substyle]["Description"] = description def substyleDescription(self, style, substyle): """ Public method to get the description of a sub-style. @param style base style number @type int @param substyle sub-style number @type int @return sub-style description @rtype str """ if style in self.__subStyles and substyle in self.__subStyles[style]: desc = self.__subStyles[style][substyle]["Description"] else: desc = "" return desc def setSubstyleWords(self, words, style, substyle): """ Public method to set the words for a sub-style. @param words words to be set separated by white-space @type str @param style base style number @type int @param substyle sub-style number @type int """ if style in self.__subStyles and substyle in self.__subStyles[style]: self.__subStyles[style][substyle]["Words"] = words def substyleWords(self, style, substyle): """ Public method to get the words of a sub-style. @param style base style number @type int @param substyle sub-style number @type int @return white-space separated word list @rtype str """ if style in self.__subStyles and substyle in self.__subStyles[style]: words = self.__subStyles[style][substyle]["Words"] else: words = "" return words def setSubstyleColor(self, color, style, substyle): """ Public method to set the foreground color of a sub-style. @param color foreground color to be set @type QColor @param style base style number @type int @param substyle sub-style number @type int """ if style in self.__subStyles and substyle in self.__subStyles[style]: self.__subStyles[style][substyle]["Style"]["fore"] = \ color.red() << 16 | color.green() << 8 | color.blue() def substyleColor(self, style, substyle): """ Public method to get the sub-style foreground color. @param style base style number @type int @param substyle sub-style number @type int @return foreground color @rtype QColor """ color = self.color(style) if style in self.__subStyles and substyle in self.__subStyles[style]: styleData = self.__subStyles[style][substyle]["Style"] if "fore" in styleData: color = QColor( styleData["fore"] >> 16 & 0xff, styleData["fore"] >> 8 & 0xff, styleData["fore"] & 0xff, ) return color def setSubstylePaper(self, color, style, substyle): """ Public method to set the background color of a sub-style. @param color background color to be set @type QColor @param style base style number @type int @param substyle sub-style number @type int """ if style in self.__subStyles and substyle in self.__subStyles[style]: self.__subStyles[style][substyle]["Style"]["paper"] = \ color.red() << 16 | color.green() << 8 | color.blue() def substylePaper(self, style, substyle): """ Public method to get the sub-style background color. @param style base style number @type int @param substyle sub-style number @type int @return background color @rtype QColor """ color = self.paper(style) if style in self.__subStyles and substyle in self.__subStyles[style]: styleData = self.__subStyles[style][substyle]["Style"] if "paper" in styleData: color = QColor( styleData["paper"] >> 16 & 0xff, styleData["paper"] >> 8 & 0xff, styleData["paper"] & 0xff, ) return color def setSubstyleEolFill(self, eolFill, style, substyle): """ Public method to set the eolfill flag of a sub-style. @param eolFill eolfill flag to be set @type bool @param style base style number @type int @param substyle sub-style number @type int """ if style in self.__subStyles and substyle in self.__subStyles[style]: self.__subStyles[style][substyle]["Style"]["eolfill"] = \ eolFill def substyleEolFill(self, style, substyle): """ Public method to get the eolfill flag. @param style base style number @type int @param substyle sub-style number @type int @return eolfill flag @rtype bool """ eolFill = self.eolFill(style) if style in self.__subStyles and substyle in self.__subStyles[style]: styleData = self.__subStyles[style][substyle]["Style"] if "eolfill" in styleData: eolFill = styleData["eolfill"] return eolFill def setSubstyleFont(self, font, style, substyle): """ Public method to set the font of a sub-style. @param font font to be set @type QFont @param style base style number @type int @param substyle sub-style number @type int """ if style in self.__subStyles and substyle in self.__subStyles[style]: self.__subStyles[style][substyle]["Style"]["font_family"] = \ font.family() self.__subStyles[style][substyle]["Style"]["font_size"] = \ font.pointSize() self.__subStyles[style][substyle]["Style"]["font_bold"] = \ font.bold() self.__subStyles[style][substyle]["Style"]["font_italic"] = \ font.italic() self.__subStyles[style][substyle]["Style"]["font_underline"] = \ font.underline() def substyleFont(self, style, substyle): """ Public method to get the sub-style font. @param style base style number @type int @param substyle sub-style number @type int @return font @rtype QFont """ font = self.font(style) if style in self.__subStyles and substyle in self.__subStyles[style]: styleData = self.__subStyles[style][substyle]["Style"] if "font_family" in styleData: font.setFamily(styleData["font_family"]) if "font_size" in styleData: font.setPointSize(styleData["font_size"]) if "font_bold" in styleData: font.setBold(styleData["font_bold"]) if "font_italic" in styleData: font.setItalic(styleData["font_italic"]) if "font_underline" in styleData: font.setUnderline(styleData["font_underline"]) return font def substyleDefaultDescription(self, style, substyle): """ Public method to get the default description of a sub-style. @param style base style number @type int @param substyle sub-style number @type int @return sub-style default description @rtype str """ description = "" if style in self.defaultSubStyles and \ substyle in self.defaultSubStyles[style]: styleData = self.defaultSubStyles[style][substyle]["Style"] description = styleData["Description"] return description def substyleDefaultWords(self, style, substyle): """ Public method to get the default words of a sub-style. @param style base style number @type int @param substyle sub-style number @type int @return white-space separated default word list @rtype str """ words = "" if style in self.defaultSubStyles and \ substyle in self.defaultSubStyles[style]: styleData = self.defaultSubStyles[style][substyle]["Style"] words = styleData["Words"] return words def substyleDefaultColor(self, style, substyle): """ Public method to get the sub-style default foreground color. @param style base style number @type int @param substyle sub-style number @type int @return default foreground color @rtype QColor """ color = self.defaultColor(style) if style in self.defaultSubStyles and \ substyle in self.defaultSubStyles[style]: styleData = self.defaultSubStyles[style][substyle]["Style"] if "fore" in styleData: color = QColor( styleData["fore"] >> 16 & 0xff, styleData["fore"] >> 8 & 0xff, styleData["fore"] & 0xff, ) return color def substyleDefaultPaper(self, style, substyle): """ Public method to get the sub-style default background color. @param style base style number @type int @param substyle sub-style number @type int @return default background color @rtype QColor """ color = self.defaultPaper(style) if style in self.defaultSubStyles and \ substyle in self.defaultSubStyles[style]: styleData = self.defaultSubStyles[style][substyle]["Style"] if "paper" in styleData: color = QColor( styleData["paper"] >> 16 & 0xff, styleData["paper"] >> 8 & 0xff, styleData["paper"] & 0xff, ) return color def substyleDefaultEolFill(self, style, substyle): """ Public method to get the default eolfill flag. @param style base style number @type int @param substyle sub-style number @type int @return default eolfill flag @rtype bool """ eolFill = self.defaultEolFill(style) if style in self.defaultSubStyles and \ substyle in self.defaultSubStyles[style]: styleData = self.defaultSubStyles[style][substyle]["Style"] if "eolfill" in styleData: eolFill = styleData["eolfill"] return eolFill def substyleDefaultFont(self, style, substyle): """ Public method to get the default sub-style font. @param style base style number @type int @param substyle sub-style number @type int @return default font @rtype QFont """ font = self.defaultFont(style) if style in self.defaultSubStyles and \ substyle in self.defaultSubStyles[style]: styleData = self.defaultSubStyles[style][substyle]["Style"] if "font_family" in styleData: font.setFamily(styleData["font_family"]) if "font_size" in styleData: font.setPointSize(styleData["font_size"]) if "font_bold" in styleData: font.setBold(styleData["font_bold"]) if "font_italic" in styleData: font.setItalic(styleData["font_italic"]) if "font_underline" in styleData: font.setUnderline(styleData["font_underline"]) return font def addSubstyle(self, style): """ Public method to add a sub-style to a given base style. @param style base style number @type int @return allocated sub-style number @rtype int """ # TODO: implement this # add empty sub-style definition def delSubstyle(self, style, substyle): """ Public method to delet a given sub-style definition. @param style base style number @type int @param substyle sub-style number @type int @return flag indicating successful deletion @rtype bool """ ok = False if style in self.__subStyles and substyle in self.__subStyles[style]: del self.__subStyles[style][substyle] ok = True return ok