Display only emojis the font supports

Fixes #9299
This commit is contained in:
Philipp Hörist 2018-08-20 19:18:07 +02:00
parent e8526bb063
commit 2e47f93214
2 changed files with 62 additions and 28 deletions

View File

@ -1478,11 +1478,7 @@ def version_condition(current_version, required_version):
return True return True
def get_available_emoticon_themes(): def get_available_emoticon_themes():
emoticons_themes = [] emoticons_themes = ['font']
if sys.platform not in ('win32', 'darwin'):
# Colored emoji fonts only supported on Linux
emoticons_themes.append('font')
files = [] files = []
dir_iterator = os.scandir(configpaths.get('EMOTICONS')) dir_iterator = os.scandir(configpaths.get('EMOTICONS'))
for folder in dir_iterator: for folder in dir_iterator:

View File

@ -21,6 +21,7 @@ from collections import OrderedDict
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import GLib from gi.repository import GLib
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
from gi.repository import Pango
from gajim.common import app from gajim.common import app
from gajim.common import helpers from gajim.common import helpers
@ -38,8 +39,9 @@ log = logging.getLogger('gajim.emoji')
class Section(Gtk.Box): class Section(Gtk.Box):
def __init__(self, name, search_entry, press_cb): def __init__(self, name, search_entry, press_cb, chooser):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
self._chooser = chooser
self._press_cb = press_cb self._press_cb = press_cb
self.pixbuf_generator = None self.pixbuf_generator = None
self.heading = Gtk.Label(label=name) self.heading = Gtk.Label(label=name)
@ -83,22 +85,44 @@ class Section(Gtk.Box):
emoji_pixbufs[codepoint] = pixbuf emoji_pixbufs[codepoint] = pixbuf
else: else:
if pixbuf is not None: if pixbuf is not None:
chooser = self._get_emoji_modifier( chooser = ModifierChooser()
codepoint, pixbuf, attrs)
chooser.flowbox.connect( # Iterate over the variations and add the codepoints
'child-activated', self._press_cb) for codepoint_ in variations.keys():
pixbuf_ = self._get_next_pixbuf()
if pixbuf_ is None:
continue
if pixbuf_ == 'font':
if not self._chooser._font_supports_codepoint(
codepoint_):
continue
else:
emoji_pixbufs[codepoint_] = pixbuf_
# Only codepoints are added which the
# font or theme supports
chooser.add_emoji(codepoint_, pixbuf_)
# Check if we successfully added codepoints with modifiers
if chooser.has_child:
# If we have children then add a button
# and set the popover
child = EmojiModifierChild(
codepoint, pixbuf, attrs['desc'])
child.button.set_popover(chooser)
chooser.flowbox.connect(
'child-activated', self._press_cb)
else:
# If no children were added, destroy the chooser
# and add a EmojiChild instead of a EmojiModifierChild
chooser.destroy()
child = EmojiChild(codepoint, pixbuf, attrs['desc'])
if pixbuf != 'font': if pixbuf != 'font':
emoji_pixbufs[codepoint] = pixbuf emoji_pixbufs[codepoint] = pixbuf
for codepoint, attrs in variations.items(): self.flowbox.add(child)
pixbuf = self._get_next_pixbuf()
if pixbuf is None:
continue
chooser.add_emoji(codepoint, pixbuf)
if pixbuf != 'font':
emoji_pixbufs[codepoint] = pixbuf
else: else:
# We dont have a image for the base codepoint # We dont have a image for the base codepoint
# so skip all modifiers of it # so skip all modifiers of it
@ -112,13 +136,6 @@ class Section(Gtk.Box):
emoji.destroy() emoji.destroy()
self.flowbox.foreach(_remove_emoji) self.flowbox.foreach(_remove_emoji)
def _get_emoji_modifier(self, codepoint, pixbuf, attrs):
chooser = ModifierChooser()
modifier_button = EmojiModifierChild(codepoint, pixbuf, attrs['desc'])
modifier_button.button.set_popover(chooser)
self.flowbox.add(modifier_button)
return chooser
def _get_next_pixbuf(self): def _get_next_pixbuf(self):
if self.pixbuf_generator is None: if self.pixbuf_generator is None:
return 'font' return 'font'
@ -193,6 +210,7 @@ class ModifierChooser(Gtk.Popover):
def __init__(self): def __init__(self):
Gtk.Popover.__init__(self) Gtk.Popover.__init__(self)
self.set_name('EmoticonPopover') self.set_name('EmoticonPopover')
self._has_child = False
self.flowbox = Gtk.FlowBox() self.flowbox = Gtk.FlowBox()
self.flowbox.get_style_context().add_class( self.flowbox.get_style_context().add_class(
@ -202,8 +220,13 @@ class ModifierChooser(Gtk.Popover):
self.flowbox.show() self.flowbox.show()
self.add(self.flowbox) self.add(self.flowbox)
@property
def has_child(self):
return self._has_child
def add_emoji(self, codepoint, pixbuf): def add_emoji(self, codepoint, pixbuf):
self.flowbox.add(EmojiChild(codepoint, pixbuf, None)) self.flowbox.add(EmojiChild(codepoint, pixbuf, None))
self._has_child = True
class EmojiChooser(Gtk.Popover): class EmojiChooser(Gtk.Popover):
@ -224,6 +247,7 @@ class EmojiChooser(Gtk.Popover):
self.set_name('EmoticonPopover') self.set_name('EmoticonPopover')
self._text_widget = None self._text_widget = None
self._load_source_id = None self._load_source_id = None
self._pango_layout = Pango.Layout(self.get_pango_context())
self._builder = get_builder('emoji_chooser.ui') self._builder = get_builder('emoji_chooser.ui')
self._search = self._builder.get_object('search') self._search = self._builder.get_object('search')
@ -232,7 +256,7 @@ class EmojiChooser(Gtk.Popover):
self._sections = OrderedDict() self._sections = OrderedDict()
for name in self._section_names: for name in self._section_names:
self._sections[name] = Section( self._sections[name] = Section(
name, self._search, self._on_emoticon_press) name, self._search, self._on_emoticon_press, self)
section_box = self._builder.get_object('section_box') section_box = self._builder.get_object('section_box')
for section in self._sections.values(): for section in self._sections.values():
@ -326,21 +350,35 @@ class EmojiChooser(Gtk.Popover):
self._clear_sections() self._clear_sections()
emoji_pixbufs.clear() emoji_pixbufs.clear()
factory = self._emoji_factory() factory = self._emoji_factory(theme == 'font')
self._load_source_id = GLib.idle_add(lambda: next(factory, False), self._load_source_id = GLib.idle_add(lambda: next(factory, False),
priority=GLib.PRIORITY_LOW) priority=GLib.PRIORITY_LOW)
def _emoji_factory(self): def _emoji_factory(self, font):
for codepoint, attrs in emoji_data.items(): for codepoint, attrs in emoji_data.items():
if not attrs['fully-qualified']: if not attrs['fully-qualified']:
# We dont add these to the UI # We dont add these to the UI
continue continue
if font and not self._font_supports_codepoint(codepoint):
continue
section = self._sections[attrs['group']] section = self._sections[attrs['group']]
yield section.add_emoji(codepoint, attrs) yield section.add_emoji(codepoint, attrs)
self._load_source_id = None self._load_source_id = None
emoji_pixbufs.complete = True emoji_pixbufs.complete = True
def _font_supports_codepoint(self, codepoint):
self._pango_layout.set_text(codepoint, -1)
if self._pango_layout.get_unknown_glyphs_count():
return False
if len(codepoint) > 1:
# The font supports each of the codepoints
# Check if the rendered glyph is more than one char
if self._pango_layout.get_size()[0] > 19000:
return False
return True
def _get_next_pixbuf(self, path): def _get_next_pixbuf(self, path):
src_x = src_y = cur_column = 0 src_x = src_y = cur_column = 0
atlas = GdkPixbuf.Pixbuf.new_from_file(path) atlas = GdkPixbuf.Pixbuf.new_from_file(path)