Refactoring:
- better functionality devision between buffer and editor; - better integration with StyledTextTagType; - font family and font size tags are separated; - new font family and font size toolbar widgets; svn: r10626
This commit is contained in:
parent
c4024f91db
commit
d003d5e61b
@ -38,6 +38,7 @@ _LOG = logging.getLogger(".Editors.StyledTextBuffer")
|
|||||||
# GTK modules
|
# GTK modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
import gobject
|
||||||
import gtk
|
import gtk
|
||||||
from pango import WEIGHT_BOLD, STYLE_ITALIC, UNDERLINE_SINGLE
|
from pango import WEIGHT_BOLD, STYLE_ITALIC, UNDERLINE_SINGLE
|
||||||
|
|
||||||
@ -53,6 +54,43 @@ from gen.lib import (StyledText, StyledTextTag, StyledTextTagType)
|
|||||||
# Constants
|
# Constants
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
# FIXME
|
||||||
|
ALLOWED_STYLES = [i for (i, s, e) in StyledTextTagType._DATAMAP]
|
||||||
|
|
||||||
|
STYLE_TYPE = {
|
||||||
|
StyledTextTagType.BOLD: bool,
|
||||||
|
StyledTextTagType.ITALIC: bool,
|
||||||
|
StyledTextTagType.UNDERLINE: bool,
|
||||||
|
StyledTextTagType.FONTCOLOR: str,
|
||||||
|
StyledTextTagType.HIGHLIGHT: str,
|
||||||
|
StyledTextTagType.FONTFACE: str,
|
||||||
|
StyledTextTagType.FONTSIZE: int,
|
||||||
|
StyledTextTagType.SUPERSCRIPT: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
STYLE_DEFAULT = {
|
||||||
|
StyledTextTagType.BOLD: False,
|
||||||
|
StyledTextTagType.ITALIC: False,
|
||||||
|
StyledTextTagType.UNDERLINE: False,
|
||||||
|
StyledTextTagType.FONTCOLOR: '#000000',
|
||||||
|
StyledTextTagType.HIGHLIGHT: '#FFFFFF',
|
||||||
|
StyledTextTagType.FONTFACE: 'Sans',
|
||||||
|
StyledTextTagType.FONTSIZE: 10,
|
||||||
|
StyledTextTagType.SUPERSCRIPT: False,
|
||||||
|
}
|
||||||
|
|
||||||
|
STYLE_TO_PROPERTY = {
|
||||||
|
StyledTextTagType.BOLD: 'weight', # permanent tag is used instead
|
||||||
|
StyledTextTagType.ITALIC: 'style', # permanent tag is used instead
|
||||||
|
StyledTextTagType.UNDERLINE: 'underline', # permanent tag is used instead
|
||||||
|
StyledTextTagType.FONTCOLOR: 'foreground',
|
||||||
|
StyledTextTagType.HIGHLIGHT: 'background',
|
||||||
|
StyledTextTagType.FONTFACE: 'family',
|
||||||
|
StyledTextTagType.FONTSIZE: 'size-points',
|
||||||
|
StyledTextTagType.SUPERSCRIPT: 'rise',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
(MATCH_START,
|
(MATCH_START,
|
||||||
MATCH_END,
|
MATCH_END,
|
||||||
MATCH_FLAVOR,
|
MATCH_FLAVOR,
|
||||||
@ -189,8 +227,14 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
and gtk.TextBuffer. To set and get the text use the L{set_text} and
|
and gtk.TextBuffer. To set and get the text use the L{set_text} and
|
||||||
L{get_text} methods.
|
L{get_text} methods.
|
||||||
|
|
||||||
StyledTextBuffer provides an action group (L{format_action_group})
|
To set a style to (a portion of) the text (e.g. from GUI) use the
|
||||||
for GUIs.
|
L{apply_style} and L{remove_style} methods.
|
||||||
|
|
||||||
|
To receive information about the style of the text at the cursor position
|
||||||
|
StyledTextBuffer provides two mechanism: message driven and polling.
|
||||||
|
To receive notification of style change as cursor moves connect to the
|
||||||
|
C{style-changed} signal. To get the value of a certain style at the cursor
|
||||||
|
use the L{get_style_at_cursor) method.
|
||||||
|
|
||||||
StyledTextBuffer has a regexp pattern matching mechanism too. To add a
|
StyledTextBuffer has a regexp pattern matching mechanism too. To add a
|
||||||
regexp pattern to match in the text use the L{match_add} method. To check
|
regexp pattern to match in the text use the L{match_add} method. To check
|
||||||
@ -200,66 +244,30 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
"""
|
"""
|
||||||
__gtype_name__ = 'StyledTextBuffer'
|
__gtype_name__ = 'StyledTextBuffer'
|
||||||
|
|
||||||
formats = ('italic', 'bold', 'underline',
|
__gsignals__ = {
|
||||||
'font', 'foreground', 'background',)
|
'style-changed': (gobject.SIGNAL_RUN_FIRST,
|
||||||
|
gobject.TYPE_NONE, #return value
|
||||||
|
(gobject.TYPE_PYOBJECT,)), # arguments
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
gtk.TextBuffer.__init__(self)
|
gtk.TextBuffer.__init__(self)
|
||||||
|
|
||||||
# Create fix tags.
|
# Create fix tags.
|
||||||
# Other tags (e.g. color) have to be created on the fly
|
# Other tags (e.g. color) have to be created on the fly
|
||||||
self.create_tag('bold', weight=WEIGHT_BOLD)
|
# see self._find_tag_by_name
|
||||||
self.create_tag('italic', style=STYLE_ITALIC)
|
self.create_tag(str(StyledTextTagType.BOLD), weight=WEIGHT_BOLD)
|
||||||
self.create_tag('underline', underline=UNDERLINE_SINGLE)
|
self.create_tag(str(StyledTextTagType.ITALIC), style=STYLE_ITALIC)
|
||||||
|
self.create_tag(str(StyledTextTagType.UNDERLINE),
|
||||||
# Setup action group used from user interface
|
underline=UNDERLINE_SINGLE)
|
||||||
format_toggle_actions = [
|
|
||||||
('italic', gtk.STOCK_ITALIC, None, None,
|
|
||||||
_('Italic'), self._on_toggle_action_activate),
|
|
||||||
('bold', gtk.STOCK_BOLD, None, None,
|
|
||||||
_('Bold'), self._on_toggle_action_activate),
|
|
||||||
('underline', gtk.STOCK_UNDERLINE, None, None,
|
|
||||||
_('Underline'), self._on_toggle_action_activate),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.toggle_actions = [action[0] for action in format_toggle_actions]
|
|
||||||
|
|
||||||
format_actions = [
|
|
||||||
('font', 'gramps-font', None, None,
|
|
||||||
_('Font'), self._on_action_activate),
|
|
||||||
('foreground', 'gramps-font-color', None, None,
|
|
||||||
_('Font Color'), self._on_action_activate),
|
|
||||||
('background', 'gramps-font-bgcolor', None, None,
|
|
||||||
_('Background Color'), self._on_action_activate),
|
|
||||||
('clear', gtk.STOCK_CLEAR, None, None,
|
|
||||||
_('Clear Markup'), self._format_clear_cb),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.action_accels = {
|
|
||||||
'<Control>i': 'italic',
|
|
||||||
'<Control>b': 'bold',
|
|
||||||
'<Control>u': 'underline',
|
|
||||||
}
|
|
||||||
|
|
||||||
self.format_action_group = gtk.ActionGroup('Format')
|
|
||||||
self.format_action_group.add_toggle_actions(format_toggle_actions)
|
|
||||||
self.format_action_group.add_actions(format_actions)
|
|
||||||
|
|
||||||
# internal format state attributes
|
# internal format state attributes
|
||||||
## 1. are used to format inserted characters (self.after_insert_text)
|
## 1. are used to format inserted characters (self.after_insert_text)
|
||||||
## 2. are set each time the Insert marker is set (self.do_mark_set)
|
## 2. are set each time the Insert marker is set (self.do_mark_set)
|
||||||
## 3. are set when format actions are activated (self.*_action_activate)
|
## 3. are set when a style is set (self._apply_style_to_selection)
|
||||||
self.italic = False
|
self.style_state = STYLE_DEFAULT.copy()
|
||||||
self.bold = False
|
|
||||||
self.underline = False
|
|
||||||
self.font = None
|
|
||||||
# TODO could we separate font name and size?
|
|
||||||
##self.size = None
|
|
||||||
self.foreground = None
|
|
||||||
self.background = None
|
|
||||||
|
|
||||||
# internally used attribute
|
# internally used attribute
|
||||||
self._internal_toggle = False
|
|
||||||
self._insert = self.get_insert()
|
self._insert = self.get_insert()
|
||||||
|
|
||||||
# create a mark used for text formatting
|
# create a mark used for text formatting
|
||||||
@ -298,13 +306,10 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
insert_start = self.get_iter_at_mark(self.mark_insert)
|
insert_start = self.get_iter_at_mark(self.mark_insert)
|
||||||
|
|
||||||
# apply active formats for the inserted text
|
# apply active formats for the inserted text
|
||||||
for format in self.__class__.formats:
|
for style in ALLOWED_STYLES:
|
||||||
value = getattr(self, format)
|
value = self.style_state[style]
|
||||||
if value:
|
if value and (value != STYLE_DEFAULT[style]):
|
||||||
if format in self.toggle_actions:
|
self.apply_tag(self._find_tag_by_name(style, value),
|
||||||
value = None
|
|
||||||
|
|
||||||
self.apply_tag(self._find_tag_by_name(format, value),
|
|
||||||
insert_start, iter)
|
insert_start, iter)
|
||||||
|
|
||||||
def after_delete_range(self, textbuffer, start, end):
|
def after_delete_range(self, textbuffer, start, end):
|
||||||
@ -334,7 +339,7 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
break
|
break
|
||||||
|
|
||||||
def do_mark_set(self, iter, mark):
|
def do_mark_set(self, iter, mark):
|
||||||
"""Update format attributes each time the cursor moves."""
|
"""Update style state each time the cursor moves."""
|
||||||
_LOG.debug("Setting mark %s at %d" %
|
_LOG.debug("Setting mark %s at %d" %
|
||||||
(mark.get_name(), iter.get_offset()))
|
(mark.get_name(), iter.get_offset()))
|
||||||
|
|
||||||
@ -345,50 +350,28 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
iter.backward_char()
|
iter.backward_char()
|
||||||
|
|
||||||
tag_names = [tag.get_property('name') for tag in iter.get_tags()]
|
tag_names = [tag.get_property('name') for tag in iter.get_tags()]
|
||||||
for format in self.__class__.formats:
|
changed_styles = {}
|
||||||
if format in self.toggle_actions:
|
|
||||||
value = format in tag_names
|
|
||||||
# set state of toggle action
|
|
||||||
action = self.format_action_group.get_action(format)
|
|
||||||
self._internal_toggle = True
|
|
||||||
action.set_active(value)
|
|
||||||
self._internal_toggle = False
|
|
||||||
else:
|
|
||||||
value = None
|
|
||||||
for tname in tag_names:
|
|
||||||
if tname.startswith(format):
|
|
||||||
value = tname.split(' ', 1)[1]
|
|
||||||
|
|
||||||
setattr(self, format, value)
|
for style in ALLOWED_STYLES:
|
||||||
|
if STYLE_TYPE[style] == bool:
|
||||||
|
value = str(style) in tag_names
|
||||||
|
else:
|
||||||
|
value = STYLE_DEFAULT[style]
|
||||||
|
for tname in tag_names:
|
||||||
|
if tname.startswith(str(style)):
|
||||||
|
value = tname.split(' ', 1)[1]
|
||||||
|
value = STYLE_TYPE[style](value)
|
||||||
|
|
||||||
|
if self.style_state[style] != value:
|
||||||
|
changed_styles[style] = value
|
||||||
|
|
||||||
|
self.style_state[style] = value
|
||||||
|
|
||||||
|
if changed_styles:
|
||||||
|
self.emit('style-changed', changed_styles)
|
||||||
|
|
||||||
# Private
|
# Private
|
||||||
|
|
||||||
def _tagname_to_tagtype(self, name):
|
|
||||||
"""Convert gtk.TextTag names to StyledTextTagType values."""
|
|
||||||
tag2type = {
|
|
||||||
'bold': StyledTextTagType.BOLD,
|
|
||||||
'italic': StyledTextTagType.ITALIC,
|
|
||||||
'underline': StyledTextTagType.UNDERLINE,
|
|
||||||
'foreground': StyledTextTagType.FONTCOLOR,
|
|
||||||
'background': StyledTextTagType.HIGHLIGHT,
|
|
||||||
'font': StyledTextTagType.FONTFACE,
|
|
||||||
}
|
|
||||||
|
|
||||||
return StyledTextTagType(tag2type[name])
|
|
||||||
|
|
||||||
def _tagtype_to_tagname(self, tagtype):
|
|
||||||
"""Convert StyledTextTagType values to gtk.TextTag names."""
|
|
||||||
type2tag = {
|
|
||||||
StyledTextTagType.BOLD: 'bold',
|
|
||||||
StyledTextTagType.ITALIC: 'italic',
|
|
||||||
StyledTextTagType.UNDERLINE: 'underline',
|
|
||||||
StyledTextTagType.FONTCOLOR: 'foreground',
|
|
||||||
StyledTextTagType.HIGHLIGHT: 'background',
|
|
||||||
StyledTextTagType.FONTFACE: 'font',
|
|
||||||
}
|
|
||||||
|
|
||||||
return type2tag[tagtype]
|
|
||||||
|
|
||||||
##def get_tag_value_at_insert(self, name):
|
##def get_tag_value_at_insert(self, name):
|
||||||
##"""Get the value of the given tag at the insertion point."""
|
##"""Get the value of the given tag at the insertion point."""
|
||||||
##tags = self.get_iter_at_mark(self._insert).get_tags()
|
##tags = self.get_iter_at_mark(self._insert).get_tags()
|
||||||
@ -404,21 +387,6 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
##return tag.get_name().split()[1]
|
##return tag.get_name().split()[1]
|
||||||
##return None
|
##return None
|
||||||
|
|
||||||
def _color_to_hex(self, color):
|
|
||||||
"""Convert gtk.gdk.Color to hex string."""
|
|
||||||
hexstring = ""
|
|
||||||
for col in 'red', 'green', 'blue':
|
|
||||||
hexfrag = hex(getattr(color, col) / (16 * 16)).split("x")[1]
|
|
||||||
if len(hexfrag) < 2:
|
|
||||||
hexfrag = "0" + hexfrag
|
|
||||||
hexstring += hexfrag
|
|
||||||
return '#' + hexstring
|
|
||||||
|
|
||||||
def _hex_to_color(self, hex):
|
|
||||||
"""Convert hex string to gtk.gdk.Color."""
|
|
||||||
color = gtk.gdk.color_parse(hex)
|
|
||||||
return color
|
|
||||||
|
|
||||||
def _get_selection(self):
|
def _get_selection(self):
|
||||||
bounds = self.get_selection_bounds()
|
bounds = self.get_selection_bounds()
|
||||||
if not bounds:
|
if not bounds:
|
||||||
@ -446,11 +414,34 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
if selection:
|
if selection:
|
||||||
self.remove_tag(tag, *selection)
|
self.remove_tag(tag, *selection)
|
||||||
|
|
||||||
def _remove_format_from_selection(self, format):
|
def _apply_style_to_selection(self, style, value):
|
||||||
|
# FIXME can this be unified?
|
||||||
|
if STYLE_TYPE[style] == bool:
|
||||||
|
start, end = self._get_selection()
|
||||||
|
|
||||||
|
if value:
|
||||||
|
self.apply_tag_by_name(str(style), start, end)
|
||||||
|
else:
|
||||||
|
self.remove_tag_by_name(str(style), start, end)
|
||||||
|
elif STYLE_TYPE[style] == str:
|
||||||
|
tag = self._find_tag_by_name(style, value)
|
||||||
|
self._remove_style_from_selection(style)
|
||||||
|
self._apply_tag_to_selection(tag)
|
||||||
|
elif STYLE_TYPE[style] == int:
|
||||||
|
tag = self._find_tag_by_name(style, value)
|
||||||
|
self._remove_style_from_selection(style)
|
||||||
|
self._apply_tag_to_selection(tag)
|
||||||
|
else:
|
||||||
|
# we should never get until here
|
||||||
|
return
|
||||||
|
|
||||||
|
self.style_state[style] = value
|
||||||
|
|
||||||
|
def _remove_style_from_selection(self, style):
|
||||||
start, end = self._get_selection()
|
start, end = self._get_selection()
|
||||||
tags = self._get_tag_from_range(start.get_offset(), end.get_offset())
|
tags = self._get_tag_from_range(start.get_offset(), end.get_offset())
|
||||||
for tag_name in tags.keys():
|
for tag_name in tags.keys():
|
||||||
if tag_name.startswith(format):
|
if tag_name.startswith(str(style)):
|
||||||
for start, end in tags[tag_name]:
|
for start, end in tags[tag_name]:
|
||||||
self.remove_tag_by_name(tag_name,
|
self.remove_tag_by_name(tag_name,
|
||||||
self.get_iter_at_offset(start),
|
self.get_iter_at_offset(start),
|
||||||
@ -462,6 +453,8 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
Return only the name of the TextTag from the specified range.
|
Return only the name of the TextTag from the specified range.
|
||||||
If range is not given, tags extracted from the whole buffer.
|
If range is not given, tags extracted from the whole buffer.
|
||||||
|
|
||||||
|
@note: TextTag names are always composed like: (%s %s) % (style, value)
|
||||||
|
|
||||||
@param start: an offset pointing to the start of the range of text
|
@param start: an offset pointing to the start of the range of text
|
||||||
@param type: int
|
@param type: int
|
||||||
@param end: an offset pointing to the end of the range of text
|
@param end: an offset pointing to the end of the range of text
|
||||||
@ -489,130 +482,61 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
tagdict[name]=[(pos, pos)]
|
tagdict[name]=[(pos, pos)]
|
||||||
return tagdict
|
return tagdict
|
||||||
|
|
||||||
def _find_tag_by_name(self, name, value):
|
def _find_tag_by_name(self, style, value):
|
||||||
"""Fetch TextTag from buffer's tag table by it's name.
|
"""Fetch TextTag from buffer's tag table by it's name.
|
||||||
|
|
||||||
If TextTag does not exist yet, it is created.
|
If TextTag does not exist yet, it is created.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if value is None:
|
if STYLE_TYPE[style] == bool:
|
||||||
tag_name = name
|
tag_name = str(style)
|
||||||
|
elif STYLE_TYPE[style] == str:
|
||||||
|
tag_name = "%d %s" % (style, value)
|
||||||
|
elif STYLE_TYPE[style] == int:
|
||||||
|
tag_name = "%d %d" % (style, value)
|
||||||
else:
|
else:
|
||||||
tag_name = "%s %s" % (name, value)
|
raise ValueError("Unknown style (%s) value type: %s" %
|
||||||
|
(style, value.__class__))
|
||||||
|
|
||||||
tag = self.get_tag_table().lookup(tag_name)
|
tag = self.get_tag_table().lookup(tag_name)
|
||||||
|
|
||||||
if not tag:
|
if not tag:
|
||||||
if value is not None:
|
if STYLE_TYPE[style] != bool:
|
||||||
|
# bool style tags are not created here, but in constuctor
|
||||||
tag = self.create_tag(tag_name)
|
tag = self.create_tag(tag_name)
|
||||||
tag.set_property(name, value)
|
tag.set_property(STYLE_TO_PROPERTY[style], value)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
return tag
|
return tag
|
||||||
|
|
||||||
# Callbacks
|
|
||||||
|
|
||||||
def _on_toggle_action_activate(self, action):
|
|
||||||
"""Toggle a format.
|
|
||||||
|
|
||||||
Toggle formats are e.g. 'bold', 'italic', 'underline'.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if self._internal_toggle:
|
|
||||||
return
|
|
||||||
|
|
||||||
start, end = self._get_selection()
|
|
||||||
|
|
||||||
if action.get_active():
|
|
||||||
self.apply_tag_by_name(action.get_name(), start, end)
|
|
||||||
else:
|
|
||||||
self.remove_tag_by_name(action.get_name(), start, end)
|
|
||||||
|
|
||||||
setattr(self, action.get_name(), action.get_active())
|
|
||||||
|
|
||||||
def _on_action_activate(self, action):
|
|
||||||
"""Apply a format."""
|
|
||||||
format = action.get_name()
|
|
||||||
|
|
||||||
if format == 'foreground':
|
|
||||||
color_selection = gtk.ColorSelectionDialog(_("Select font color"))
|
|
||||||
if self.foreground:
|
|
||||||
color_selection.colorsel.set_current_color(
|
|
||||||
self._hex_to_color(self.foreground))
|
|
||||||
response = color_selection.run()
|
|
||||||
color = color_selection.colorsel.get_current_color()
|
|
||||||
value = self._color_to_hex(color)
|
|
||||||
color_selection.destroy()
|
|
||||||
elif format == 'background':
|
|
||||||
color_selection = gtk.ColorSelectionDialog(_("Select "
|
|
||||||
"background color"))
|
|
||||||
if self.background:
|
|
||||||
color_selection.colorsel.set_current_color(
|
|
||||||
self._hex_to_color(self.background))
|
|
||||||
response = color_selection.run()
|
|
||||||
color = color_selection.colorsel.get_current_color()
|
|
||||||
value = self._color_to_hex(color)
|
|
||||||
color_selection.destroy()
|
|
||||||
elif format == 'font':
|
|
||||||
font_selection = CustomFontSelectionDialog(_("Select font"))
|
|
||||||
if self.font:
|
|
||||||
font_selection.fontsel.set_font_name(self.font)
|
|
||||||
response = font_selection.run()
|
|
||||||
value = font_selection.fontsel.get_font_name()
|
|
||||||
font_selection.destroy()
|
|
||||||
else:
|
|
||||||
_LOG.debug("unknown format: '%s'" % format)
|
|
||||||
return
|
|
||||||
|
|
||||||
if response == gtk.RESPONSE_OK:
|
|
||||||
_LOG.debug("applying format '%s' with value '%s'" % (format, value))
|
|
||||||
|
|
||||||
tag = self._find_tag_by_name(format, value)
|
|
||||||
self._remove_format_from_selection(format)
|
|
||||||
self._apply_tag_to_selection(tag)
|
|
||||||
|
|
||||||
setattr(self, format, value)
|
|
||||||
|
|
||||||
def _format_clear_cb(self, action):
|
|
||||||
"""Remove all formats from the selection.
|
|
||||||
|
|
||||||
Remove only our own tags without touching other ones (e.g. gtk.Spell),
|
|
||||||
thus remove_all_tags() can not be used.
|
|
||||||
|
|
||||||
"""
|
|
||||||
for format in self.formats:
|
|
||||||
self._remove_format_from_selection(format)
|
|
||||||
|
|
||||||
def on_key_press_event(self, widget, event):
|
|
||||||
"""Handle formatting shortcuts."""
|
|
||||||
for accel in self.action_accels.keys():
|
|
||||||
key, mod = gtk.accelerator_parse(accel)
|
|
||||||
if (event.keyval, event.state) == (key, mod):
|
|
||||||
action_name = self.action_accels[accel]
|
|
||||||
action = self.format_action_group.get_action(action_name)
|
|
||||||
action.activate()
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Public API
|
# Public API
|
||||||
|
|
||||||
def set_text(self, r_text):
|
def set_text(self, s_text):
|
||||||
"""Set the content of the buffer with markup tags."""
|
"""Set the content of the buffer with markup tags.
|
||||||
gtk.TextBuffer.set_text(self, str(r_text))
|
|
||||||
|
|
||||||
r_tags = r_text.get_tags()
|
@note: 's_' prefix means StyledText*, while 'g_' prefix means gtk.*.
|
||||||
for r_tag in r_tags:
|
|
||||||
tagname = self._tagtype_to_tagname(int(r_tag.name))
|
"""
|
||||||
g_tag = self._find_tag_by_name(tagname, r_tag.value)
|
gtk.TextBuffer.set_text(self, str(s_text))
|
||||||
|
|
||||||
|
s_tags = s_text.get_tags()
|
||||||
|
for s_tag in s_tags:
|
||||||
|
g_tag = self._find_tag_by_name(int(s_tag.name), s_tag.value)
|
||||||
if g_tag is not None:
|
if g_tag is not None:
|
||||||
for (start, end) in r_tag.ranges:
|
for (start, end) in s_tag.ranges:
|
||||||
start_iter = self.get_iter_at_offset(start)
|
start_iter = self.get_iter_at_offset(start)
|
||||||
end_iter = self.get_iter_at_offset(end)
|
end_iter = self.get_iter_at_offset(end)
|
||||||
self.apply_tag(g_tag, start_iter, end_iter)
|
self.apply_tag(g_tag, start_iter, end_iter)
|
||||||
|
|
||||||
def get_text(self, start=None, end=None, include_hidden_chars=True):
|
def get_text(self, start=None, end=None, include_hidden_chars=True):
|
||||||
"""Return the buffer text."""
|
"""Return the buffer text.
|
||||||
if not start:
|
|
||||||
|
@note: 's_' prefix means StyledText*, while 'g_' prefix means gtk.*.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if start is None:
|
||||||
start = self.get_start_iter()
|
start = self.get_start_iter()
|
||||||
if not end:
|
if end is None:
|
||||||
end = self.get_end_iter()
|
end = self.get_end_iter()
|
||||||
|
|
||||||
txt = gtk.TextBuffer.get_text(self, start, end, include_hidden_chars)
|
txt = gtk.TextBuffer.get_text(self, start, end, include_hidden_chars)
|
||||||
@ -620,25 +544,59 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
|
|
||||||
# extract tags out of the buffer
|
# extract tags out of the buffer
|
||||||
g_tags = self._get_tag_from_range()
|
g_tags = self._get_tag_from_range()
|
||||||
r_tags = []
|
s_tags = []
|
||||||
|
|
||||||
for g_tagname, g_ranges in g_tags.items():
|
for g_tagname, g_ranges in g_tags.items():
|
||||||
name_value = g_tagname.split(' ', 1)
|
style_and_value = g_tagname.split(' ', 1)
|
||||||
|
|
||||||
if len(name_value) == 1:
|
style = int(style_and_value[0])
|
||||||
name = name_value[0]
|
if len(style_and_value) == 1:
|
||||||
r_value = None
|
s_value = None
|
||||||
else:
|
else:
|
||||||
(name, r_value) = name_value
|
s_value = STYLE_TYPE[style](style_and_value[1])
|
||||||
|
|
||||||
if name in self.formats:
|
if style in ALLOWED_STYLES:
|
||||||
r_tagtype = self._tagname_to_tagtype(name)
|
s_ranges = [(start, end+1) for (start, end) in g_ranges]
|
||||||
r_ranges = [(start, end+1) for (start, end) in g_ranges]
|
s_tag = StyledTextTag(style, s_value, s_ranges)
|
||||||
r_tag = StyledTextTag(r_tagtype, r_value, r_ranges)
|
|
||||||
|
|
||||||
r_tags.append(r_tag)
|
s_tags.append(s_tag)
|
||||||
|
|
||||||
return StyledText(txt, r_tags)
|
return StyledText(txt, s_tags)
|
||||||
|
|
||||||
|
def apply_style(self, style, value):
|
||||||
|
"""Apply a style with the given value to the selection.
|
||||||
|
|
||||||
|
@param style: style type to apply
|
||||||
|
@type style: L{StyledTextTagStyle} int value
|
||||||
|
@param value: value of the style type
|
||||||
|
@type value: depends on the I{style} type
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not isinstance(value, STYLE_TYPE[style]):
|
||||||
|
raise TypeError("Style (%d) value must be %s and not %s" %
|
||||||
|
(style, STYLE_TYPE[style], value.__class__))
|
||||||
|
|
||||||
|
self._apply_style_to_selection(style, value)
|
||||||
|
|
||||||
|
def remove_style(self, style):
|
||||||
|
"""Delete all occurences with any value of the given style.
|
||||||
|
|
||||||
|
@param style: style type to apply
|
||||||
|
@type style: L{StyledTextTagStyle} int value
|
||||||
|
|
||||||
|
"""
|
||||||
|
self._remove_style_from_selection(style)
|
||||||
|
|
||||||
|
def get_style_at_cursor(self, style):
|
||||||
|
"""Get the actual value of the given style at the cursor position.
|
||||||
|
|
||||||
|
@param style: style type to apply
|
||||||
|
@type style: L{StyledTextTagStyle} int value
|
||||||
|
@returns: value of the style type
|
||||||
|
@returntype: depends on the C{style} type
|
||||||
|
|
||||||
|
"""
|
||||||
|
return self.style_state[style]
|
||||||
|
|
||||||
def match_add(self, pattern, flavor):
|
def match_add(self, pattern, flavor):
|
||||||
"""Add a pattern to look for in the text."""
|
"""Add a pattern to look for in the text."""
|
||||||
@ -652,27 +610,3 @@ class StyledTextBuffer(gtk.TextBuffer):
|
|||||||
return match
|
return match
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# CustomFontSelectionDialog class
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
class CustomFontSelectionDialog(gtk.FontSelectionDialog):
|
|
||||||
"""A FontSelectionDialog without the Style treeview.
|
|
||||||
|
|
||||||
This should be only a workaround until a real custom font selector
|
|
||||||
is created, because this solution is gtk implementation dependent.
|
|
||||||
|
|
||||||
"""
|
|
||||||
def __init__(self, title):
|
|
||||||
gtk.FontSelectionDialog.__init__(self, title)
|
|
||||||
|
|
||||||
# hide the Style label and treeview
|
|
||||||
for widget in self.fontsel.get_children():
|
|
||||||
if isinstance(widget, gtk.Table):
|
|
||||||
table = widget
|
|
||||||
|
|
||||||
for child in table.get_children():
|
|
||||||
if table.child_get_property(child, 'left-attach') == 1:
|
|
||||||
child.hide()
|
|
@ -46,8 +46,11 @@ from pango import UNDERLINE_SINGLE
|
|||||||
# GRAMPS modules
|
# GRAMPS modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from Editors._StyledTextBuffer import (StyledTextBuffer, MATCH_START,
|
from gen.lib import StyledTextTagType
|
||||||
MATCH_END, MATCH_FLAVOR, MATCH_STRING)
|
from Editors._StyledTextBuffer import (StyledTextBuffer, ALLOWED_STYLES,
|
||||||
|
STYLE_TYPE, STYLE_DEFAULT,
|
||||||
|
MATCH_START, MATCH_END,
|
||||||
|
MATCH_FLAVOR, MATCH_STRING)
|
||||||
from Spell import Spell
|
from Spell import Spell
|
||||||
from GrampsDisplay import url as display_url
|
from GrampsDisplay import url as display_url
|
||||||
|
|
||||||
@ -62,18 +65,28 @@ REGULAR_CURSOR = gtk.gdk.Cursor(gtk.gdk.XTERM)
|
|||||||
FORMAT_TOOLBAR = '''
|
FORMAT_TOOLBAR = '''
|
||||||
<ui>
|
<ui>
|
||||||
<toolbar name="ToolBar">
|
<toolbar name="ToolBar">
|
||||||
<toolitem action="italic"/>
|
<toolitem action="%d"/>
|
||||||
<toolitem action="bold"/>
|
<toolitem action="%d"/>
|
||||||
<toolitem action="underline"/>
|
<toolitem action="%d"/>
|
||||||
<separator/>
|
<toolitem action="%d"/>
|
||||||
<toolitem action="font"/>
|
<toolitem action="%d"/>
|
||||||
<toolitem action="foreground"/>
|
<toolitem action="%d"/>
|
||||||
<toolitem action="background"/>
|
<toolitem action="%d"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<toolitem action="clear"/>
|
<toolitem action="clear"/>
|
||||||
</toolbar>
|
</toolbar>
|
||||||
</ui>
|
</ui>
|
||||||
'''
|
''' % (StyledTextTagType.ITALIC,
|
||||||
|
StyledTextTagType.BOLD,
|
||||||
|
StyledTextTagType.UNDERLINE,
|
||||||
|
StyledTextTagType.FONTFACE,
|
||||||
|
StyledTextTagType.FONTSIZE,
|
||||||
|
StyledTextTagType.FONTCOLOR,
|
||||||
|
StyledTextTagType.HIGHLIGHT,
|
||||||
|
)
|
||||||
|
|
||||||
|
FONT_SIZES = [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22,
|
||||||
|
24, 26, 28, 32, 36, 40, 48, 56, 64, 72]
|
||||||
|
|
||||||
USERCHARS = "-A-Za-z0-9"
|
USERCHARS = "-A-Za-z0-9"
|
||||||
PASSCHARS = "-A-Za-z0-9,?;.:/!%$^*&~\"#'"
|
PASSCHARS = "-A-Za-z0-9,?;.:/!%$^*&~\"#'"
|
||||||
@ -137,6 +150,7 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Setup initial instance variable values."""
|
"""Setup initial instance variable values."""
|
||||||
self.textbuffer = StyledTextBuffer()
|
self.textbuffer = StyledTextBuffer()
|
||||||
|
self.textbuffer.connect('style-changed', self._on_buffer_style_changed)
|
||||||
gtk.TextView.__init__(self, self.textbuffer)
|
gtk.TextView.__init__(self, self.textbuffer)
|
||||||
|
|
||||||
self.match = None
|
self.match = None
|
||||||
@ -146,6 +160,7 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
|
|
||||||
self.toolbar = self._create_toolbar()
|
self.toolbar = self._create_toolbar()
|
||||||
self.spellcheck = Spell(self)
|
self.spellcheck = Spell(self)
|
||||||
|
self._internal_style_change = False
|
||||||
|
|
||||||
self._connect_signals()
|
self._connect_signals()
|
||||||
|
|
||||||
@ -196,10 +211,17 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
def on_key_press_event(self, widget, event):
|
def on_key_press_event(self, widget, event):
|
||||||
"""Signal handler.
|
"""Signal handler.
|
||||||
|
|
||||||
Handle shortcuts in the TextView.
|
Handle formatting shortcuts.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.get_buffer().on_key_press_event(self, event)
|
for accel in self.action_accels.keys():
|
||||||
|
key, mod = gtk.accelerator_parse(accel)
|
||||||
|
if (event.keyval, event.state) == (key, mod):
|
||||||
|
action_name = self.action_accels[accel]
|
||||||
|
action = self.action_group.get_action(action_name)
|
||||||
|
action.activate()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def on_insert_at_cursor(self, widget, string):
|
def on_insert_at_cursor(self, widget, string):
|
||||||
"""Signal handler. for debugging only."""
|
"""Signal handler. for debugging only."""
|
||||||
@ -301,16 +323,73 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
def _create_toolbar(self):
|
def _create_toolbar(self):
|
||||||
"""Create a formatting toolbar.
|
"""Create a formatting toolbar.
|
||||||
|
|
||||||
@returns: toolbar according to L{StyedTextBuffer} formatting
|
@returns: toolbar containing text formatting toolitems.
|
||||||
capabilities.
|
|
||||||
@returntype: gtk.Toolbar
|
@returntype: gtk.Toolbar
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# define the actions...
|
||||||
|
# ...first the toggle actions, which have a ToggleToolButton as proxy
|
||||||
|
format_toggle_actions = [
|
||||||
|
(str(StyledTextTagType.ITALIC), gtk.STOCK_ITALIC, None, None,
|
||||||
|
_('Italic'), self._on_toggle_action_activate),
|
||||||
|
(str(StyledTextTagType.BOLD), gtk.STOCK_BOLD, None, None,
|
||||||
|
_('Bold'), self._on_toggle_action_activate),
|
||||||
|
(str(StyledTextTagType.UNDERLINE), gtk.STOCK_UNDERLINE, None, None,
|
||||||
|
_('Underline'), self._on_toggle_action_activate),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.toggle_actions = [action[0] for action in format_toggle_actions]
|
||||||
|
|
||||||
|
# ...then the normal actions, which have a ToolButton as proxy
|
||||||
|
format_actions = [
|
||||||
|
(str(StyledTextTagType.FONTCOLOR), 'gramps-font-color', None, None,
|
||||||
|
_('Font Color'), self._on_action_activate),
|
||||||
|
(str(StyledTextTagType.HIGHLIGHT), 'gramps-font-bgcolor', None, None,
|
||||||
|
_('Background Color'), self._on_action_activate),
|
||||||
|
('clear', gtk.STOCK_CLEAR, None, None,
|
||||||
|
_('Clear Markup'), self._format_clear_cb),
|
||||||
|
]
|
||||||
|
|
||||||
|
# ...last the custom actions, which have custom proxies
|
||||||
|
fontface_action = ComboToolAction(str(StyledTextTagType.FONTFACE),
|
||||||
|
_("Font family"),
|
||||||
|
_("Font family"), None)
|
||||||
|
fontsize_action = ComboToolAction(str(StyledTextTagType.FONTSIZE),
|
||||||
|
_("Font size"),
|
||||||
|
_("Font size"), None)
|
||||||
|
self.action_accels = {
|
||||||
|
'<Control>i': 'italic',
|
||||||
|
'<Control>b': 'bold',
|
||||||
|
'<Control>u': 'underline',
|
||||||
|
}
|
||||||
|
|
||||||
|
# create the action group and insert all the actions
|
||||||
|
self.action_group = gtk.ActionGroup('Format')
|
||||||
|
self.action_group.add_toggle_actions(format_toggle_actions)
|
||||||
|
self.action_group.add_actions(format_actions)
|
||||||
|
self.action_group.add_action(fontface_action)
|
||||||
|
self.action_group.add_action(fontsize_action)
|
||||||
|
|
||||||
|
# define the toolbar and create the proxies via ensure_update()
|
||||||
uimanager = gtk.UIManager()
|
uimanager = gtk.UIManager()
|
||||||
uimanager.insert_action_group(self.textbuffer.format_action_group, 0)
|
uimanager.insert_action_group(self.action_group, 0)
|
||||||
uimanager.add_ui_from_string(FORMAT_TOOLBAR)
|
uimanager.add_ui_from_string(FORMAT_TOOLBAR)
|
||||||
uimanager.ensure_update()
|
uimanager.ensure_update()
|
||||||
|
|
||||||
|
# now that widget is created for the custom actions set them up
|
||||||
|
fontface = uimanager.get_widget('/ToolBar/%d' %
|
||||||
|
StyledTextTagType.FONTFACE)
|
||||||
|
set_fontface_toolitem(fontface, self._on_combotoolitem_changed)
|
||||||
|
|
||||||
|
fontsize = uimanager.get_widget('/ToolBar/%d' %
|
||||||
|
StyledTextTagType.FONTSIZE)
|
||||||
|
set_fontsize_toolitem(fontsize, self._on_combotoolitem_changed)
|
||||||
|
|
||||||
|
##separator = uimanager.get_widget('/ToolBar/abcdef')
|
||||||
|
##separator = gtk.SeparatorToolItem()
|
||||||
|
##separator.set_expand(True)
|
||||||
|
##separator.set_draw(False)
|
||||||
|
|
||||||
toolbar = uimanager.get_widget('/ToolBar')
|
toolbar = uimanager.get_widget('/ToolBar')
|
||||||
toolbar.set_style(gtk.TOOLBAR_ICONS)
|
toolbar.set_style(gtk.TOOLBAR_ICONS)
|
||||||
|
|
||||||
@ -357,6 +436,98 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
|
|
||||||
# Callback functions
|
# Callback functions
|
||||||
|
|
||||||
|
def _on_toggle_action_activate(self, action):
|
||||||
|
"""Toggle a style.
|
||||||
|
|
||||||
|
Toggle styles are e.g. 'bold', 'italic', 'underline'.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if self._internal_style_change:
|
||||||
|
return
|
||||||
|
|
||||||
|
style = int(action.get_name())
|
||||||
|
value = action.get_active()
|
||||||
|
_LOG.debug("applying style '%d' with value '%s'" % (style, str(value)))
|
||||||
|
self.textbuffer.apply_style(style, value)
|
||||||
|
|
||||||
|
def _on_action_activate(self, action):
|
||||||
|
"""Apply a format."""
|
||||||
|
style = int(action.get_name())
|
||||||
|
current_value = self.textbuffer.get_style_at_cursor(style)
|
||||||
|
|
||||||
|
if style == StyledTextTagType.FONTCOLOR:
|
||||||
|
color_selection = gtk.ColorSelectionDialog(_("Select font color"))
|
||||||
|
elif style == StyledTextTagType.HIGHLIGHT:
|
||||||
|
color_selection = gtk.ColorSelectionDialog(_("Select "
|
||||||
|
"background color"))
|
||||||
|
else:
|
||||||
|
_LOG.debug("unknown style: '%d'" % style)
|
||||||
|
return
|
||||||
|
|
||||||
|
if current_value:
|
||||||
|
color_selection.colorsel.set_current_color(
|
||||||
|
hex_to_color(current_value))
|
||||||
|
|
||||||
|
response = color_selection.run()
|
||||||
|
color = color_selection.colorsel.get_current_color()
|
||||||
|
value = color_to_hex(color)
|
||||||
|
color_selection.destroy()
|
||||||
|
|
||||||
|
if response == gtk.RESPONSE_OK:
|
||||||
|
_LOG.debug("applying style '%d' with value '%s'" %
|
||||||
|
(style, str(value)))
|
||||||
|
self.textbuffer.apply_style(style, value)
|
||||||
|
|
||||||
|
def _on_combotoolitem_changed(self, combobox, style):
|
||||||
|
if self._internal_style_change:
|
||||||
|
return
|
||||||
|
|
||||||
|
value = STYLE_TYPE[style](combobox.get_active_text())
|
||||||
|
_LOG.debug("applying style '%d' with value '%s'" % (style, str(value)))
|
||||||
|
self.textbuffer.apply_style(style, value)
|
||||||
|
|
||||||
|
def _format_clear_cb(self, action):
|
||||||
|
"""Remove all formats from the selection.
|
||||||
|
|
||||||
|
Remove only our own tags without touching other ones (e.g. gtk.Spell),
|
||||||
|
thus remove_all_tags() can not be used.
|
||||||
|
|
||||||
|
"""
|
||||||
|
for style in ALLOWED_STYLES:
|
||||||
|
self.textbuffer.remove_style(style)
|
||||||
|
|
||||||
|
def _on_buffer_style_changed(self, buffer, changed_styles):
|
||||||
|
# set state of toggle action
|
||||||
|
for style in changed_styles.keys():
|
||||||
|
if str(style) in self.toggle_actions:
|
||||||
|
action = self.action_group.get_action(str(style))
|
||||||
|
self._internal_style_change = True
|
||||||
|
action.set_active(changed_styles[style])
|
||||||
|
self._internal_style_change = False
|
||||||
|
|
||||||
|
if ((style == StyledTextTagType.FONTFACE) or
|
||||||
|
(style == StyledTextTagType.FONTSIZE)):
|
||||||
|
|
||||||
|
action = self.action_group.get_action(str(style))
|
||||||
|
combo = action.get_proxies()[0].child
|
||||||
|
model = combo.get_model()
|
||||||
|
iter = model.get_iter_first()
|
||||||
|
while iter:
|
||||||
|
if (STYLE_TYPE[style](model.get_value(iter, 0)) ==
|
||||||
|
changed_styles[style]):
|
||||||
|
break
|
||||||
|
iter = model.iter_next(iter)
|
||||||
|
|
||||||
|
self._internal_style_change = True
|
||||||
|
if iter is None:
|
||||||
|
combo.child.set_text(str(changed_styles[style]))
|
||||||
|
if style == StyledTextTagType.FONTFACE:
|
||||||
|
_LOG.debug('font family "%s" is not installed' %
|
||||||
|
changed_styles[style])
|
||||||
|
else:
|
||||||
|
combo.set_active_iter(iter)
|
||||||
|
self._internal_style_change = False
|
||||||
|
|
||||||
def _spell_change_cb(self, menuitem, language):
|
def _spell_change_cb(self, menuitem, language):
|
||||||
"""Set spell checker language according to user selection."""
|
"""Set spell checker language according to user selection."""
|
||||||
self.spellcheck.set_active_language(language)
|
self.spellcheck.set_active_language(language)
|
||||||
@ -396,6 +567,7 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
self.textbuffer.set_text(text)
|
self.textbuffer.set_text(text)
|
||||||
|
self.textbuffer.place_cursor(self.textbuffer.get_start_iter())
|
||||||
|
|
||||||
def get_text(self):
|
def get_text(self):
|
||||||
"""Get the text of the text buffer of the editor.
|
"""Get the text of the text buffer of the editor.
|
||||||
@ -414,3 +586,111 @@ class StyledTextEditor(gtk.TextView):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
return self.toolbar
|
return self.toolbar
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# ComboToolItem class
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
class ComboToolItem(gtk.ToolItem):
|
||||||
|
|
||||||
|
__gtype_name__ = "ComboToolItem"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
gtk.ToolItem.__init__(self)
|
||||||
|
|
||||||
|
self.set_border_width(2)
|
||||||
|
self.set_homogeneous(False)
|
||||||
|
self.set_expand(False)
|
||||||
|
|
||||||
|
self.combobox = gtk.combo_box_entry_new_text()
|
||||||
|
self.combobox.show()
|
||||||
|
self.add(self.combobox)
|
||||||
|
|
||||||
|
def set_entry_editable(self, editable):
|
||||||
|
self.combobox.child.set_editable(editable)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# ComboToolAction class
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
class ComboToolAction(gtk.Action):
|
||||||
|
|
||||||
|
__gtype_name__ = "ComboToolAction"
|
||||||
|
|
||||||
|
def __init__(self, name, label, tooltip, stock_id):
|
||||||
|
gtk.Action.__init__(self, name, label, tooltip, stock_id)
|
||||||
|
##self.set_tool_item_type(ComboToolItem)
|
||||||
|
|
||||||
|
##def create_tool_item(self):
|
||||||
|
##combobox = ComboToolButton()
|
||||||
|
###self.connect_proxy(combobox)
|
||||||
|
##return combobox
|
||||||
|
|
||||||
|
##def connect_proxy(self, proxy):
|
||||||
|
##gtk.Action.connect_proxy(self, proxy)
|
||||||
|
|
||||||
|
##if isinstance(proxy, ComboToolButton):
|
||||||
|
##proxy.combobox.connect('changed', self.changed)
|
||||||
|
|
||||||
|
##def changed(self, combobox):
|
||||||
|
##self.activate()
|
||||||
|
ComboToolAction.set_tool_item_type(ComboToolItem)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Module functions
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
def set_fontface_toolitem(combotoolitem, callback):
|
||||||
|
"""Setup font family comboboxentry."""
|
||||||
|
combotoolitem.set_entry_editable(False)
|
||||||
|
|
||||||
|
fontface = combotoolitem.child
|
||||||
|
|
||||||
|
families = [family.get_name()
|
||||||
|
for family in fontface.get_pango_context().list_families()]
|
||||||
|
families.sort()
|
||||||
|
for family in families:
|
||||||
|
fontface.append_text(family)
|
||||||
|
|
||||||
|
try:
|
||||||
|
default = families.index(STYLE_DEFAULT[StyledTextTagType.FONTFACE])
|
||||||
|
except ValueError:
|
||||||
|
default = 0
|
||||||
|
fontface.set_active(default)
|
||||||
|
|
||||||
|
fontface.connect('changed', callback, StyledTextTagType.FONTFACE)
|
||||||
|
|
||||||
|
def set_fontsize_toolitem(combotoolitem, callback):
|
||||||
|
"""Setup font size comboboxentry."""
|
||||||
|
combotoolitem.set_size_request(60, -1)
|
||||||
|
|
||||||
|
fontsize = combotoolitem.child
|
||||||
|
|
||||||
|
for size in FONT_SIZES:
|
||||||
|
fontsize.append_text(str(size))
|
||||||
|
|
||||||
|
try:
|
||||||
|
default = FONT_SIZES.index(STYLE_DEFAULT[StyledTextTagType.FONTSIZE])
|
||||||
|
except ValueError:
|
||||||
|
default = 0
|
||||||
|
fontsize.set_active(default)
|
||||||
|
|
||||||
|
fontsize.connect('changed', callback, StyledTextTagType.FONTSIZE)
|
||||||
|
|
||||||
|
def color_to_hex(color):
|
||||||
|
"""Convert gtk.gdk.Color to hex string."""
|
||||||
|
hexstring = ""
|
||||||
|
for col in 'red', 'green', 'blue':
|
||||||
|
hexfrag = hex(getattr(color, col) / (16 * 16)).split("x")[1]
|
||||||
|
if len(hexfrag) < 2:
|
||||||
|
hexfrag = "0" + hexfrag
|
||||||
|
hexstring += hexfrag
|
||||||
|
return '#' + hexstring
|
||||||
|
|
||||||
|
def hex_to_color(hex):
|
||||||
|
"""Convert hex string to gtk.gdk.Color."""
|
||||||
|
color = gtk.gdk.color_parse(hex)
|
||||||
|
return color
|
||||||
|
@ -47,23 +47,25 @@ class StyledTextTagType(GrampsType):
|
|||||||
Here we only define new class variables. For details see L{GrampsType}.
|
Here we only define new class variables. For details see L{GrampsType}.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
NONE_ = -1
|
NONE_TYPE = -1
|
||||||
BOLD = 0
|
BOLD = 0
|
||||||
ITALIC = 1
|
ITALIC = 1
|
||||||
UNDERLINE = 2
|
UNDERLINE = 2
|
||||||
FONTFACE = 3
|
FONTFACE = 3
|
||||||
FONTCOLOR = 4
|
FONTSIZE = 4
|
||||||
HIGHLIGHT = 5
|
FONTCOLOR = 5
|
||||||
SUPERSCRIPT = 6
|
HIGHLIGHT = 6
|
||||||
|
SUPERSCRIPT = 7
|
||||||
|
|
||||||
_CUSTOM = NONE_
|
_CUSTOM = NONE_TYPE
|
||||||
_DEFAULT = NONE_
|
_DEFAULT = NONE_TYPE
|
||||||
|
|
||||||
_DATAMAP = [
|
_DATAMAP = [
|
||||||
(BOLD, _("Bold"), "bold"),
|
(BOLD, _("Bold"), "bold"),
|
||||||
(ITALIC, _("Italic"), "italic"),
|
(ITALIC, _("Italic"), "italic"),
|
||||||
(UNDERLINE, _("Underline"), "underline"),
|
(UNDERLINE, _("Underline"), "underline"),
|
||||||
(FONTFACE, _("Fontface"), "fontface"),
|
(FONTFACE, _("Fontface"), "fontface"),
|
||||||
|
(FONTSIZE, _("Fontsize"), "fontsize"),
|
||||||
(FONTCOLOR, _("Fontcolor"), "fontcolor"),
|
(FONTCOLOR, _("Fontcolor"), "fontcolor"),
|
||||||
(HIGHLIGHT, _("Highlight"), "highlight"),
|
(HIGHLIGHT, _("Highlight"), "highlight"),
|
||||||
(SUPERSCRIPT, _("Superscript"), "superscript"),
|
(SUPERSCRIPT, _("Superscript"), "superscript"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user