Rework emoticon menu

This commit is contained in:
Philipp Hörist 2017-06-16 19:36:32 +02:00
parent 0d0671374a
commit 79716f421f
12 changed files with 372 additions and 229 deletions

View File

@ -1,7 +1,7 @@
emoticonsdir = $(pkgdatadir)/data/emoticons
nobase_dist_emoticons_DATA = \
$(srcdir)/*/*.png \
$(srcdir)/*/*.gif \
$(srcdir)/*/emoticons.py
$(srcdir)/*/LICENSE \
$(srcdir)/*/emoticons_theme.py
MAINTAINERCLEANFILES = Makefile.in

View File

@ -664,23 +664,17 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="emoticons_button">
<object class="GtkMenuButton" id="emoticons_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_markup" translatable="yes">Show a list of emoticons (Alt+M)</property>
<property name="tooltip_text" translatable="yes">Show a list of emoticons (Alt+M)</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="emoticons_button_image">
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-missing-image</property>
<property name="icon_size">1</property>
<property name="icon_name">face-smile</property>
</object>
</child>
</object>

View File

@ -224,20 +224,17 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="emoticons_button">
<object class="GtkMenuButton" id="emoticons_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a list of emoticons (Alt+M)</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="emoticons_button_image">
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
<property name="icon_size">1</property>
<property name="icon_name">face-smile</property>
</object>
</child>
</object>

View File

@ -4,4 +4,11 @@
#ChatControl-AuthenticationButton { padding-top: 0px; padding-bottom: 0px}
/* VCardWindow */
.VCard-GtkLinkButton { padding-left: 5px; border-left: none; }
.VCard-GtkLinkButton { padding-left: 5px; border-left: none; }
popover#EmoticonPopover button { background: none; border: none; box-shadow:none; padding: 0px;}
popover#EmoticonPopover button > label { font-size: 24px; }
popover#EmoticonPopover flowboxchild > label { font-size: 24px; }
popover#EmoticonPopover notebook label { font-size: 24px; }
popover#EmoticonPopover flowbox { padding-left: 5px; padding-right: 6px; }
popover#EmoticonPopover flowboxchild { padding-top: 5px; padding-bottom: 5px; }

View File

@ -102,6 +102,8 @@ class ChatControl(ChatControlBase):
self.handlers[id_] = self.actions_button
self._formattings_button = self.xml.get_object('formattings_button')
self.emoticons_button = self.xml.get_object('emoticons_button')
self.toggle_emoticons()
self._add_to_roster_button = self.xml.get_object(
'add_to_roster_button')
@ -325,8 +327,6 @@ class ChatControl(ChatControlBase):
if (gajim.connections[self.account].connected > 1 and not \
self.TYPE_ID == 'pm') or (self.contact.show != 'offline' and \
self.TYPE_ID == 'pm'):
emoticons_button = self.xml.get_object('emoticons_button')
emoticons_button.set_sensitive(True)
send_button = self.xml.get_object('send_button')
send_button.set_sensitive(True)
# Formatting
@ -1663,15 +1663,11 @@ class ChatControl(ChatControlBase):
if contact:
self.contact = contact
self.draw_banner()
emoticons_button = self.xml.get_object('emoticons_button')
emoticons_button.set_sensitive(True)
send_button = self.xml.get_object('send_button')
send_button.set_sensitive(True)
def got_disconnected(self):
# Emoticons button
emoticons_button = self.xml.get_object('emoticons_button')
emoticons_button.set_sensitive(False)
send_button = self.xml.get_object('send_button')
send_button.set_sensitive(False)
# Add to roster

View File

@ -43,6 +43,7 @@ import history_window
import notify
import re
import emoticons
from common import events
from common import gajim
from common import helpers
@ -263,12 +264,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
id_ = widget.connect('clicked', self._on_history_menuitem_activate)
self.handlers[id_] = widget
# when/if we do XHTML we will put formatting buttons back
widget = self.xml.get_object('emoticons_button')
widget.set_sensitive(False)
id_ = widget.connect('clicked', self.on_emoticons_button_clicked)
self.handlers[id_] = widget
# Create banner and connect signals
widget = self.xml.get_object('banner_eventbox')
id_ = widget.connect('button-press-event',
@ -364,13 +359,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self.received_history_pos = 0
self.orig_msg = None
# Emoticons menu
# set image no matter if user wants at this time emoticons or not
# (so toggle works ok)
img = self.xml.get_object('emoticons_button_image')
img.set_from_file(os.path.join(gajim.DATA_DIR, 'emoticons', 'static',
'smile.png'))
self.toggle_emoticons()
self.set_emoticon_popover()
# Attach speller
if gajim.config.get('use_speller') and HAS_GTK_SPELL:
@ -568,6 +557,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
When send button is pressed: send the current message
"""
message_buffer = self.msg_textview.get_buffer()
emoticons.replace_with_codepoint(message_buffer)
start_iter = message_buffer.get_start_iter()
end_iter = message_buffer.get_end_iter()
message = message_buffer.get_text(start_iter, end_iter, False)
@ -588,12 +578,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self.parent_win.notebook.event(event)
return True
def show_emoticons_menu(self):
if not gajim.config.get('emoticons_theme'):
return
gajim.interface.emoticon_menuitem_clicked = self.append_emoticon
gajim.interface.emoticons_menu.popup(None, None, None, None, 1, 0)
def _on_message_textview_key_press_event(self, widget, event):
if event.keyval == Gdk.KEY_space:
self.space_pressed = True
@ -683,6 +667,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
event.keyval == Gdk.KEY_KP_Enter: # ENTER
message_textview = widget
message_buffer = message_textview.get_buffer()
emoticons.replace_with_codepoint(message_buffer)
start_iter, end_iter = message_buffer.get_bounds()
message = message_buffer.get_text(start_iter, end_iter, False)
xhtml = self.msg_textview.get_xhtml()
@ -1012,31 +997,26 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
def toggle_emoticons(self):
"""
Hide show emoticons_button and make sure emoticons_menu is always there
when needed
Hide show emoticons_button
"""
emoticons_button = self.xml.get_object('emoticons_button')
if gajim.config.get('emoticons_theme'):
emoticons_button.show()
emoticons_button.set_no_show_all(False)
self.emoticons_button.set_no_show_all(False)
self.emoticons_button.show()
else:
emoticons_button.hide()
emoticons_button.set_no_show_all(True)
self.emoticons_button.set_no_show_all(True)
self.emoticons_button.hide()
def append_emoticon(self, str_):
buffer_ = self.msg_textview.get_buffer()
if buffer_.get_char_count():
buffer_.insert_at_cursor(' %s ' % str_)
else: # we are the beginning of buffer
buffer_.insert_at_cursor('%s ' % str_)
self.msg_textview.grab_focus()
def set_emoticon_popover(self):
if not gajim.config.get('emoticons_theme'):
return
def on_emoticons_button_clicked(self, widget):
"""
Popup emoticons menu
"""
gajim.interface.emoticon_menuitem_clicked = self.append_emoticon
gajim.interface.popup_emoticons_under_button(widget, self.parent_win)
if not self.parent_win:
return
popover = emoticons.get_popover()
popover.set_callbacks(self.msg_textview)
emoticons_button = self.xml.get_object('emoticons_button')
emoticons_button.set_popover(popover)
def on_color_menuitem_activate(self, widget):
color_dialog = Gtk.ColorChooserDialog(None, self.parent_win.window)
@ -1139,6 +1119,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
def set_control_active(self, state):
if state:
self.set_emoticon_popover()
jid = self.contact.jid
if self.was_at_the_end:
# we are at the end

View File

@ -657,7 +657,7 @@ class PreferencesWindow:
else:
gajim.config.set('emoticons_theme', emot_theme)
gajim.interface.init_emoticons(need_reload = True)
gajim.interface.init_emoticons()
gajim.interface.make_regexps()
self.toggle_emoticons()

View File

@ -48,6 +48,7 @@ from common import helpers
from common import i18n
from calendar import timegm
from common.fuzzyclock import FuzzyClock
import emoticons
from htmltextview import HtmlTextView
from common.exceptions import GajimGeneralException
@ -952,22 +953,17 @@ class ConversationTextview(GObject.GObject):
end_iter = iter_
else:
end_iter = buffer_.get_end_iter()
if gajim.config.get('emoticons_theme') and \
possible_emot_ascii_caps in gajim.interface.emoticons.keys() and graphics:
# it's an emoticon
emot_ascii = possible_emot_ascii_caps
anchor = buffer_.create_child_anchor(end_iter)
img = TextViewImage(anchor,
GLib.markup_escape_text(special_text))
animations = gajim.interface.emoticons_animations
if not emot_ascii in animations:
animations[emot_ascii] = GdkPixbuf.PixbufAnimation.new_from_file(
gajim.interface.emoticons[emot_ascii])
img.set_from_animation(animations[emot_ascii])
img.show()
self.images.append(img)
# add with possible animation
self.tv.add_child_at_anchor(img, anchor)
if gajim.config.get('emoticons_theme') and graphics:
pixbuf = emoticons.get_pixbuf(possible_emot_ascii_caps)
if pixbuf:
# it's an emoticon
anchor = buffer_.create_child_anchor(end_iter)
img = TextViewImage(anchor,
GLib.markup_escape_text(special_text))
img.set_from_pixbuf(pixbuf)
img.show()
self.images.append(img)
self.tv.add_child_at_anchor(img, anchor)
elif special_text.startswith('www.') or \
special_text.startswith('ftp.') or \
text_is_valid_uri and not is_xhtml_link:

309
gajim/emoticons.py Normal file
View File

@ -0,0 +1,309 @@
# -*- coding:utf-8 -*-
#
# Copyright (C) 2017 Philipp Hörist <philipp AT hoerist.com>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
import os
import logging
import importlib.util as imp
from collections import OrderedDict
from gi.repository import GdkPixbuf, Gtk, GLib
MODIFIER_MAX_CHILDREN_PER_LINE = 6
MAX_CHILDREN_PER_LINE = 10
MIN_HEIGHT = 200
pixbufs = dict()
codepoints = dict()
popover_instance = None
log = logging.getLogger('gajim.emoticons')
class SubPixbuf:
height = 24
width = 24
columns = 20
def __init__(self, path):
self.cur_column = 0
self.src_x = 0
self.src_y = 0
self.atlas = GdkPixbuf.Pixbuf.new_from_file(path)
def get_pixbuf(self):
self.src_x = self.cur_column * self.width
subpixbuf = self.atlas.new_subpixbuf(self.src_x, self.src_y, self.width, self.height)
if self.cur_column == self.columns - 1:
self.src_y += self.width
self.cur_column = 0
else:
self.cur_column += 1
return subpixbuf
def load(path):
theme_path = os.path.join(path, 'emoticons_theme.py')
spec = imp.spec_from_file_location("emoticons_theme.py", theme_path)
try:
theme = imp.module_from_spec(spec)
spec.loader.exec_module(theme)
except FileNotFoundError:
log.exception('Emoticons theme not found')
return
if not theme.use_image:
# Use Font to display emoticons
set_popover(theme.emoticons, False)
return True
try:
sub = SubPixbuf(os.path.join(path, 'emoticons.png'))
except GLib.GError:
log.exception('Error while creating subpixbuf')
return False
def add_emoticon(codepoint_, sub, mod_list=None):
pix = sub.get_pixbuf()
for alternate in codepoint_:
codepoints[alternate.upper()] = pix
if pix not in pixbufs:
pixbufs[pix] = alternate.upper()
if mod_list is not None:
mod_list.append(pix)
else:
pixbuf_list.append(pix)
popover_dict = OrderedDict()
try:
for category in theme.emoticons:
if not theme.emoticons[category]:
# Empty category
continue
pixbuf_list = []
for filename, codepoint_ in theme.emoticons[category]:
if codepoint_ is None:
# Category image
pixbuf_list.append(sub.get_pixbuf())
continue
if not filename:
# We have an emoticon with a modifier
mod_list = []
for _, mod_codepoint in codepoint_:
add_emoticon(mod_codepoint, sub, mod_list)
pixbuf_list.append(mod_list)
else:
add_emoticon(codepoint_, sub)
popover_dict[category] = pixbuf_list
except Exception:
log.exception('Error while loading emoticon theme')
return
set_popover(popover_dict, True)
return True
def set_popover(popover_dict, use_image):
global popover_instance
popover_instance = EmoticonPopover(popover_dict, use_image)
def get_popover():
return popover_instance
def get_pixbuf(codepoint_):
try:
return codepoints[codepoint_]
except KeyError:
return None
def get_codepoint(pixbuf_):
try:
return pixbufs[pixbuf_]
except KeyError:
return None
def replace_with_codepoint(buffer_):
if not pixbufs:
# We use font emoticons
return
iter_ = buffer_.get_start_iter()
pix = iter_.get_pixbuf()
def replace(pix):
if pix:
emote = get_codepoint(pix)
if not emote:
return
iter_2 = iter_.copy()
iter_2.forward_char()
buffer_.delete(iter_, iter_2)
buffer_.insert(iter_, emote)
replace(pix)
while iter_.forward_char():
pix = iter_.get_pixbuf()
replace(pix)
class EmoticonPopover(Gtk.Popover):
def __init__(self, emoji_dict, use_image):
super().__init__()
self.set_name('EmoticonPopover')
self.text_widget = None
self.use_image = use_image
notebook = Gtk.Notebook()
self.add(notebook)
self.handler_id = self.connect('key_press_event', self.on_key_press)
for category in emoji_dict:
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.set_min_content_height(MIN_HEIGHT)
flowbox = Gtk.FlowBox()
flowbox.set_max_children_per_line(MAX_CHILDREN_PER_LINE)
flowbox.connect('child_activated', self.on_emoticon_press)
scrolled_window.add(flowbox)
# Use first entry as a label for the notebook page
if self.use_image:
cat_image = Gtk.Image()
cat_image.set_from_pixbuf(emoji_dict[category][0])
notebook.append_page(scrolled_window, cat_image)
else:
notebook.append_page(scrolled_window, Gtk.Label(label=emoji_dict[category][0]))
# Populate the category with emojis
for pix in emoji_dict[category][1:]:
if isinstance(pix, list):
widget = self.add_emoticon_modifier(pix)
else:
if self.use_image:
widget = Gtk.Image()
widget.set_from_pixbuf(pix)
else:
widget = Gtk.Label(pix)
flowbox.add(widget)
notebook.show_all()
def add_emoticon_modifier(self, pixbuf_list):
button = Gtk.MenuButton()
button.set_relief(Gtk.ReliefStyle.NONE)
if self.use_image:
# We use the first item of the list as image for the button
button.get_child().set_from_pixbuf(pixbuf_list[0])
else:
button.remove(button.get_child())
label = Gtk.Label(pixbuf_list[0])
button.add(label)
button.connect('button-press-event', self.on_modifier_press)
popover = Gtk.Popover()
popover.set_name('EmoticonPopover')
popover.connect('key_press_event', self.on_key_press)
flowbox = Gtk.FlowBox()
flowbox.set_size_request(200, -1)
flowbox.set_max_children_per_line(MODIFIER_MAX_CHILDREN_PER_LINE)
flowbox.connect('child_activated', self.on_emoticon_press)
popover.add(flowbox)
for pix in pixbuf_list[1:]:
if self.use_image:
widget = Gtk.Image()
widget.set_from_pixbuf(pix)
else:
widget = Gtk.Label(pix)
flowbox.add(widget)
flowbox.show_all()
button.set_popover(popover)
return button
def set_callbacks(self, widget):
self.text_widget = widget
# Because the handlers getting disconnected when on_destroy() is called
# we connect them again
if self.handler_id:
self.disconnect(self.handler_id)
self.handler_id = self.connect('key_press_event', self.on_key_press)
def on_key_press(self, widget, event):
self.text_widget.grab_focus()
def on_modifier_press(self, button, event):
if event.button == 3:
button.get_popover().show()
button.get_popover().get_child().unselect_all()
if event.button == 1:
button.get_parent().emit('activate')
if self.use_image:
self.append_emoticon(button.get_child().get_pixbuf())
else:
self.append_emoticon(button.get_child().get_text())
return True
def on_emoticon_press(self, flowbox, child):
GLib.timeout_add(100, flowbox.unselect_all)
if isinstance(child.get_child(), Gtk.MenuButton):
return
if self.use_image:
self.append_emoticon(child.get_child().get_pixbuf())
else:
self.append_emoticon(child.get_child().get_text())
def append_emoticon(self, pix):
buffer_ = self.text_widget.get_buffer()
if buffer_.get_char_count():
buffer_.insert_at_cursor(' ')
insert_mark = buffer_.get_insert()
insert_iter = buffer_.get_iter_at_mark(insert_mark)
if self.use_image:
buffer_.insert_pixbuf(insert_iter, pix)
else:
buffer_.insert(insert_iter, pix)
buffer_.insert_at_cursor(' ')
else: # we are the beginning of buffer
insert_mark = buffer_.get_insert()
insert_iter = buffer_.get_iter_at_mark(insert_mark)
if self.use_image:
buffer_.insert_pixbuf(insert_iter, pix)
else:
buffer_.insert(insert_iter, pix)
buffer_.insert_at_cursor(' ')
def do_destroy(self):
# Remove the references we hold to other objects
self.text_widget = None
# Even though we dont destroy the Popover, handlers are getting
# still disconnected, which makes the handler_id invalid
# FIXME: find out how we can prevent handlers getting disconnected
self.handler_id = None
# Never destroy, creating a new EmoticonPopover is expensive
return True

View File

@ -304,6 +304,9 @@ class GroupchatControl(ChatControlBase):
self.on_actions_button_clicked)
self.handlers[id_] = self.actions_button
self.emoticons_button = self.xml.get_object('emoticons_button')
self.toggle_emoticons()
widget = self.xml.get_object('change_nick_button')
widget.set_sensitive(False)
id_ = widget.connect('clicked', self._on_change_nick_menuitem_activate)
@ -1429,8 +1432,6 @@ class GroupchatControl(ChatControlBase):
send_button = self.xml.get_object('send_button')
send_button.set_sensitive(True)
emoticons_button = self.xml.get_object('emoticons_button')
emoticons_button.set_sensitive(True)
formattings_button = self.xml.get_object('formattings_button')
formattings_button.set_sensitive(True)
change_nick_button = self.xml.get_object('change_nick_button')
@ -1441,8 +1442,6 @@ class GroupchatControl(ChatControlBase):
def got_disconnected(self):
send_button = self.xml.get_object('send_button')
send_button.set_sensitive(False)
emoticons_button = self.xml.get_object('emoticons_button')
emoticons_button.set_sensitive(False)
formattings_button = self.xml.get_object('formattings_button')
formattings_button.set_sensitive(False)
change_nick_button = self.xml.get_object('change_nick_button')

View File

@ -87,6 +87,7 @@ from common.connection_handlers_events import OurShowEvent, \
from common.connection import Connection
from common.file_props import FilesProp
from common import pep
import emoticons
import roster_window
import profile_window
@ -1839,20 +1840,6 @@ class Interface:
### Methods dealing with emoticons
################################################################################
@staticmethod
def image_is_ok(image):
if not os.path.exists(image):
return False
img = Gtk.Image()
try:
img.set_from_file(image)
except Exception:
return False
t = img.get_storage_type()
if t != Gtk.ImageType.PIXBUF and t != Gtk.ImageType.ANIMATION:
return False
return True
@property
def basic_pattern_re(self):
if not self._basic_pattern_re:
@ -1942,7 +1929,7 @@ class Interface:
# NOT expanded. e.g., foo:) NO, foo :) YES, (brb) NO, (:)) YES, etc
# We still allow multiple emoticons side-by-side like :P:P:P
# sort keys by length so :qwe emot is checked before :q
keys = sorted(self.emoticons, key=len, reverse=True)
keys = sorted(emoticons.codepoints.keys(), key=len, reverse=True)
emoticons_pattern_prematch = ''
emoticons_pattern_postmatch = ''
emoticon_length = 0
@ -1981,97 +1968,7 @@ class Interface:
self.invalid_XML_chars = '[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x1f]|'\
'[\ud800-\udfff]|[\ufffe-\uffff]'
def popup_emoticons_under_button(self, button, parent_win):
"""
Popup the emoticons menu under button, located in parent_win
"""
gtkgui_helpers.popup_emoticons_under_button(self.emoticons_menu,
button, parent_win)
def prepare_emoticons_menu(self):
menu = Gtk.Menu()
def emoticon_clicked(w, str_):
if self.emoticon_menuitem_clicked:
self.emoticon_menuitem_clicked(str_)
# don't keep reference to CB of object
# this will prevent making it uncollectable
self.emoticon_menuitem_clicked = None
def selection_done(widget):
# remove reference to CB of object, which will
# make it uncollectable
self.emoticon_menuitem_clicked = None
counter = 0
# Calculate the side lenght of the popup to make it a square
size = int(round(math.sqrt(len(self.emoticons_images))))
for image in self.emoticons_images:
# In Gtk 3.6, Gtk.MenuItem() doesn't contain a label child
item = Gtk.MenuItem.new_with_label('q')
img = Gtk.Image()
if isinstance(image[1], GdkPixbuf.PixbufAnimation):
img.set_from_animation(image[1])
else:
img.set_from_pixbuf(image[1])
c = item.get_child()
item.remove(c)
item.add(img)
item.connect('activate', emoticon_clicked, image[0])
# add tooltip with ascii
item.set_tooltip_text(image[0])
menu.attach(item, counter % size, counter % size + 1,
counter / size, counter / size + 1)
counter += 1
menu.connect('selection-done', selection_done)
menu.show_all()
return menu
def _init_emoticons(self, path, need_reload = False):
#initialize emoticons dictionary and unique images list
self.emoticons_images = list()
self.emoticons = dict()
self.emoticons_animations = dict()
sys.path.insert(0, path)
import emoticons
try:
if need_reload:
# we need to reload else that doesn't work when changing
# emoticons set
import imp
imp.reload(emoticons)
emots = emoticons.emoticons
self.emoticons_sorting = None
try:
self.emoticons_sorting = emoticons.sorting
except:
pass
except Exception as e:
return True
for emot_filename in emots:
emot_file = os.path.join(path, emot_filename)
if not self.image_is_ok(emot_file):
continue
for emot in emots[emot_filename]:
emot = emot
# This avoids duplicated emoticons with the same image eg. :)
# and :-)
if not emot_file in self.emoticons.values():
if emot_file.endswith('.gif'):
pix = GdkPixbuf.PixbufAnimation.new_from_file(emot_file)
else:
pix = GdkPixbuf.Pixbuf.new_from_file_at_size(emot_file,
16, 16)
self.emoticons_images.append((emot, pix))
self.emoticons[emot.upper()] = emot_file
def emoticons_sorter(item):
try:
return self.emoticons_sorting.index(item[0])
except:
return 0
self.emoticons_images = sorted(self.emoticons_images, key=emoticons_sorter)
del emoticons
sys.path.remove(path)
def init_emoticons(self, need_reload = False):
def init_emoticons(self):
emot_theme = gajim.config.get('emoticons_theme')
if not emot_theme:
return
@ -2092,40 +1989,14 @@ class Interface:
transient_for=transient_for)
gajim.config.set('emoticons_theme', '')
return
if self._init_emoticons(path, need_reload):
dialogs.WarningDialog(_('Emoticons disabled'),
_('Your configured emoticons theme cannot been loaded. You '
'maybe need to update the format of emoticons.py file. See '
'http://trac.gajim.org/wiki/Emoticons for more details.'),
if not emoticons.load(path):
dialogs.WarningDialog(
_('Emoticons disabled'),
_('Your configured emoticons theme could not be loaded.'
' See the log for more details.'),
transient_for=transient_for)
gajim.config.set('emoticons_theme', '')
return
if len(self.emoticons) == 0:
# maybe old format of emoticons file, try to convert it
try:
import pprint
import emoticons
emots = emoticons.emoticons
fd = open(os.path.join(path, 'emoticons.py'), 'w')
fd.write('emoticons = ')
pprint.pprint( dict([
(file_, [i for i in emots.keys() if emots[i] == file_])
for file_ in set(emots.values())]), fd)
fd.close()
del emoticons
self._init_emoticons(path, need_reload=True)
except Exception:
pass
if len(self.emoticons) == 0:
dialogs.WarningDialog(_('Emoticons disabled'),
_('Your configured emoticons theme cannot been loaded. You '
'maybe need to update the format of emoticons.py file. See '
'http://trac.gajim.org/wiki/Emoticons for more details.'),
transient_for=transient_for)
gajim.config.set('emoticons_theme', '')
if self.emoticons_menu:
self.emoticons_menu.destroy()
self.emoticons_menu = self.prepare_emoticons_menu()
################################################################################
### Methods for opening new messages controls
@ -2791,9 +2662,6 @@ class Interface:
self.msg_win_mgr = None
self.jabber_state_images = {'16': {}, '24': {}, '32': {}, 'opened': {},
'closed': {}}
self.emoticons_menu = None
# handler when an emoticon is clicked in emoticons_menu
self.emoticon_menuitem_clicked = None
self.minimized_controls = {}
self.status_sent_to_users = {}
self.status_sent_to_groups = {}
@ -2822,10 +2690,6 @@ class Interface:
self.emot_and_basic = None
self.sth_at_sth_dot_sth = None
self.emot_only = None
self.emoticons = []
self.emoticons_animations = {}
self.emoticons_images = {}
self.emoticons_sorting = None
cfg_was_read = parser.read()

View File

@ -438,7 +438,7 @@ class MessageWindow(object):
control.chat_buttons_set_visible(not control.hide_chat_buttons)
return True
elif keyval == Gdk.KEY_m: # ALT + M show emoticons menu
control.show_emoticons_menu()
control.emoticons_button.get_popover().show()
return True
elif keyval == Gdk.KEY_d: # ALT + D show actions menu
if Gtk.Settings.get_default().get_property(