xed/plugins/textsize/textsize/documenthelper.py

203 lines
6.0 KiB
Python

# -*- coding: utf-8 -*-
#
# documenthelper.py - Document helper
#
# Copyright (C) 2010 - Jesse van den Kieboom
# Copyright (C) 2017 - Linux Mint team
#
# This program 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 2 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
from .signals import Signals
from gi.repository import Gtk, Gdk, Pango
MAX_FONT_SIZE = 30
MIN_FONT_SIZE = 5
class DocumentHelper(Signals):
def __init__(self, view):
Signals.__init__(self)
self._view = view
self.connect_signal(self._view, 'scroll-event', self.on_scroll_event)
self.connect_signal(self._view, 'button-press-event', self.on_button_press_event)
self._view.textsize_document_helper = self
self._default_font = None
self._last_font = None
self._font_tags = {}
def stop(self):
if self._default_font:
self._view.override_font(self._default_font)
self.remove_font_tags()
self.disconnect_signals(self._view)
self._view.textsize_document_helper = None
def remove_font_tags(self):
buf = self._view.get_buffer()
table = buf.get_tag_table()
# Remove all the font tags
for size in self._font_tags:
tag = self._font_tags[size]
table.remove(tag)
self._font_tags = {}
def update_default_font(self):
context = self._view.get_style_context()
description = context.get_font(context.get_state()).copy()
if not self._last_font or description.hash() != self._last_font.hash():
self._default_font = description
def get_font_tags(self, start, end):
tags = set()
# Check all the know font tags
for size in self._font_tags:
tag = self._font_tags[size]
if start.has_tag(tag):
tags.add(tag)
else:
cp = start.copy()
if cp.forward_to_tag_toggle(tag) and cp.compare(end) < 0:
tags.add(tag)
return list(tags)
def set_font_size(self, amount):
self.update_default_font()
context = self._view.get_style_context()
description = context.get_font(context.get_state()).copy()
buf = self._view.get_buffer()
bounds = buf.get_selection_bounds()
size = description.get_size() / Pango.SCALE
if not bounds:
if size >= MAX_FONT_SIZE and amount == 1:
return;
if size <= MIN_FONT_SIZE and amount == -1:
return;
description.set_size(max(1, (size + amount)) * Pango.SCALE)
self._view.override_font(description)
self._last_font = description
else:
start = bounds[0]
end = bounds[1]
tags = self.get_font_tags(start, end)
if not tags:
# Simply use the overall font size as the base
newsize = size + amount
elif len(tags) == 1:
newsize = tags[0].props.font_desc.get_size() / Pango.SCALE + amount
else:
newsize = 0
for tag in tags:
newsize += tag.props.font_desc.get_size() / Pango.SCALE
newsize = round(newsize / len(tags))
if newsize >= MAX_FONT_SIZE and amount == 1:
return;
if newsize <= MIN_FONT_SIZE and amount == -1:
return;
newsize = int(max(1, newsize))
if not newsize in self._font_tags:
newtag = buf.create_tag(None)
desc = description
desc.set_size(newsize * Pango.SCALE)
newtag.props.font_desc = desc
self._font_tags[newsize] = newtag
else:
newtag = self._font_tags[newsize]
# Remove all the previous mix of tags
for tag in tags:
buf.remove_tag(tag, start, end)
buf.apply_tag(newtag, start, end)
def larger_text(self):
self.set_font_size(1)
def smaller_text(self):
self.set_font_size(-1)
def normal_size(self):
self.update_default_font()
buf = self._view.get_buffer()
bounds = buf.get_selection_bounds()
if not bounds:
self.remove_font_tags()
self._view.override_font(self._default_font)
self._last_font = self._default_font
else:
tags = self.get_font_tags(bounds[0], bounds[1])
for tag in tags:
buf.remove_tag(tag, bounds[0], bounds[1])
def on_scroll_event(self, view, event):
state = event.state & Gtk.accelerator_get_default_mod_mask()
if state != Gdk.ModifierType.CONTROL_MASK:
return False
if event.direction == Gdk.ScrollDirection.UP:
self.larger_text()
return True
elif event.direction == Gdk.ScrollDirection.DOWN:
self.smaller_text()
return True
elif event.direction == Gdk.ScrollDirection.SMOOTH:
if event.delta_y > 0:
self.smaller_text()
elif event.delta_y < 0:
self.larger_text()
return False
def on_button_press_event(self, view, event):
state = event.state & Gtk.accelerator_get_default_mod_mask()
if state == Gdk.ModifierType.CONTROL_MASK and event.button == 2:
self.normal_size()
return True
else:
return False