# -*- coding: utf-8 -*-
#
# viewactivatable.py - Gedit View Activatable Implementation
#
# Copyright (C) 2010 - Jesse van den Kieboom
#
# 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 GObject, Gtk, Gdk, Pango, Gedit
class TextSizeViewActivatable(GObject.Object, Gedit.ViewActivatable, Signals):
view = GObject.Property(type=Gedit.View)
def __init__(self):
GObject.Object.__init__(self)
Signals.__init__(self)
def do_activate(self):
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_view_activatable = self
self._default_font = None
self._last_font = None
self._font_tags = {}
def do_deactivate(self):
if self._default_font:
self.view.override_font(self._default_font)
self.remove_font_tags()
self.disconnect_signals(self.view)
delattr(self.view, "textsize_view_activatable")
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:
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))
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
# Scroll to the keep the line in the centre of the screen anchored
visible_rect = self.view.get_visible_rect()
central_line_y = visible_rect.height / 2 + visible_rect.y
central_line_iter, _ = self.view.get_line_at_y(central_line_y)
self.view.scroll_to_iter(central_line_iter, 0, True, 0.5, 0.5)
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
# ex:ts=4:et: