diff --git a/gui/markup.py b/gui/markup.py new file mode 100644 index 0000000..42d5dd5 --- /dev/null +++ b/gui/markup.py @@ -0,0 +1,109 @@ +# Originally from https://github.com/wrhansen/MarkupToTextTag +# Then modified a bit to suit. +# This will be obsolete at some point in the future -- see +# https://bugzilla.gnome.org/show_bug.cgi?id=59390. + +# This package is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from gi.repository import Gtk, Pango + +import gui.pangohack + +__author__ = "Wesley Hansen" +__date__ = "07/06/2012 11:29:17 PM" +''' +The markuptotexttag package contains the function `convertMarkup` that +will parse a string that is formatted with pango markup and convert +it into GtkTextTags that can be retrieved via the MarkupProps iterator. +''' + +def convertMarkup(string): + ''' + Parses the string and returns a MarkupProps instance + ''' + attr_values = ('value', 'ink_rect', 'logical_rect', 'desc', 'color') + # This seems like a rather lame API. + ok, attr_list, text, accel = Pango.parse_markup( string, len(string), '\0' ) + + props = MarkupProps() + props.text = text + + val = True + for attr in attr_list.get_iterator(): + name = attr.type + start = attr.start_index + end = attr.end_index + name = Pango.AttrType(name).value_nick + + value = None + for attr_value in attr_values: + if hasattr( attr, attr_value ): + value = getattr( attr, attr_value ) + break + if name == 'font_desc': + name = 'font' + props.add( name, value, start, end ) + + return props + +class MarkupProps(object): + ''' + Stores properties that contain indices and appropriate values for that property. + Includes an iterator that generates GtkTextTags with the start and end indices to + apply them to + ''' + def __init__(self): + ''' + properties = ( { + 'properties': {'foreground': 'green', 'background': 'red'} + 'start': 0, + 'end': 3 + }, + { + 'properties': {'font': 'Lucida Sans 10'}, + 'start': 1, + 'end':2, + + }, + ) + ''' + self.properties = []#Sequence containing all the properties, and values, organized by like start and end indices + self.text = ""#The raw text without any markup + + def add( self, label, value, start, end ): + ''' + Add a property to MarkupProps. If the start and end indices are already in + a property dictionary, then add the property:value entry into + that property, otherwise create a new one + ''' + for prop in self.properties: + if prop['start'] == start and prop['end'] == end: + prop['properties'].update({label:value}) + else: + new_prop = { + 'properties': {label:value}, + 'start': start, + 'end':end, + } + self.properties.append( new_prop ) + + + def __iter__(self): + ''' + Yields (TextTag, start, end) + ''' + for prop in self.properties: + tag = Gtk.TextTag() + tag.set_properties( **prop['properties'] ) + yield (tag, prop['start'], prop['end']) diff --git a/gui/pangohack.py b/gui/pangohack.py new file mode 100644 index 0000000..5e6974f --- /dev/null +++ b/gui/pangohack.py @@ -0,0 +1,131 @@ +# From +# https://bug646788.bugzilla-attachments.gnome.org/attachment.cgi?id=221735 + +from gi.repository import Pango + +#Pango.AttrList +class AttrIterator(): + def __init__ (self, attributes=[]): + self.attributes = attributes + self.attribute_stack = [] + self.start_index = 0 + self.end_index = 0 + if not self.next(): + self.end_index = 2**32 -1 + + def __next__(self): + return self.next() + + def __iter__(self): + return self + + def next(self): + if len(self.attributes) == 0 and len(self.attribute_stack) == 0: + return False + self.start_index = self.end_index + self.end_index = 2**32 - 1 + + to_remove = [] + for attr in self.attribute_stack: + if attr.end_index == self.start_index: + to_remove.append(attr) + else: + self.end_index = min(self.end_index, attr.end_index) + + while len(to_remove) > 0: + attr = to_remove[0] + self.attribute_stack.remove(to_remove[0]) + try: + to_remove.remove(attr) + except: + pass + + while len(self.attributes) != 0 and \ + self.attributes[0].start_index == self.start_index: + if self.attributes[0].end_index > self.start_index: + self.attribute_stack.append(self.attributes[0]) + self.end_index = min(self.end_index, self.attributes[0].end_index) + self.attributes = self.attributes[1:] + if len(self.attributes) > 0: + self.end_index = min(self.end_index, self.attributes[0].start_index) + return True + + def range(self): + return (self.start_index, self.end_index) + + #Dont create pango.fontdesc as it should. But half working. + def get_font(self): + tmp_list1 = self.attribute_stack + fontdesc = Pango.FontDescription() + for attr in self.attribute_stack: + if attr.klass.type == Pango.ATTR_FONT_DESC: + tmp_list1.remove(attr) + attr.__class__ = gi.repository.Pango.AttrFontDesc + fontdesc = attr.desc + return (fontdesc, None, self.attribute_stack) + + + +def get_iterator(self): + tmplist = [] + def fil(val, data): + tmplist.append(val) + return False + self.filter(fil, None) + return AttrIterator(tmplist) + + +setattr(Pango.AttrList, 'get_iterator', get_iterator) +class AttrFamily(Pango.Attribute): + pass +Pango.AttrFamily = AttrFamily + +class AttrStyle(Pango.Attribute): + pass +Pango.AttrStyle = AttrStyle + +class AttrVariant(Pango.Attribute): + pass +Pango.AttrVariant = AttrVariant + +class AttrWeight(Pango.Attribute): + pass +Pango.AttrWeight = AttrWeight + +class AttrVariant(Pango.Attribute): + pass +Pango.AttrVariant = AttrVariant + +class AttrStretch(Pango.Attribute): + pass +Pango.AttrStretch = AttrStretch + + +# And to access values +# pango_type_table = { +# pango.ATTR_SIZE: gi.repository.Pango.AttrInt, +# pango.ATTR_WEIGHT: gi.repository.Pango.AttrInt, +# pango.ATTR_UNDERLINE: gi.repository.Pango.AttrInt, +# pango.ATTR_STRETCH: gi.repository.Pango.AttrInt, +# pango.ATTR_VARIANT: gi.repository.Pango.AttrInt, +# pango.ATTR_STYLE: gi.repository.Pango.AttrInt, +# pango.ATTR_SCALE: gi.repository.Pango.AttrFloat, +# pango.ATTR_FAMILY: gi.repository.Pango.AttrString, +# pango.ATTR_FONT_DESC: gi.repository.Pango.AttrFontDesc, +# pango.ATTR_STRIKETHROUGH: gi.repository.Pango.AttrInt, +# pango.ATTR_BACKGROUND: gi.repository.Pango.AttrColor, +# pango.ATTR_FOREGROUND: gi.repository.Pango.AttrColor, +# pango.ATTR_RISE: gi.repository.Pango.AttrInt} + +# def make_with_value(a): +# type_ = a.klass.type +# klass = a.klass +# start_index = a.start_index +# end_index = a.end_index +# #Nasty workaround, but then python object gets value field. +# a.__class__ = self.pango_type_table[type_] +# a.type = type_ +# a.start_index = start_index +# a.end_index = end_index +# a.klass = klass +# return a