parent
2a4e59654f
commit
fef8cff254
|
@ -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:
|
||||||
|
|
|
@ -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)
|
|
||||||
|
# Iterate over the variations and add the codepoints
|
||||||
|
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(
|
chooser.flowbox.connect(
|
||||||
'child-activated', self._press_cb)
|
'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)
|
||||||
|
|
Loading…
Reference in New Issue