[thopi] improve emoticons in textview. fixes #2933
This commit is contained in:
parent
d6aa63cd1c
commit
968ebff481
1 changed files with 136 additions and 1 deletions
|
@ -38,6 +38,107 @@ from common.fuzzyclock import FuzzyClock
|
||||||
from htmltextview import HtmlTextView
|
from htmltextview import HtmlTextView
|
||||||
from common.exceptions import GajimGeneralException
|
from common.exceptions import GajimGeneralException
|
||||||
|
|
||||||
|
|
||||||
|
def is_selection_modified(mark):
|
||||||
|
name = mark.get_name()
|
||||||
|
if name and name in ('selection_bound', 'insert'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def has_focus(widget):
|
||||||
|
return widget.flags() & gtk.HAS_FOCUS == gtk.HAS_FOCUS
|
||||||
|
|
||||||
|
class TextViewImage(gtk.Image):
|
||||||
|
|
||||||
|
def __init__(self, anchor):
|
||||||
|
super(TextViewImage, self).__init__()
|
||||||
|
self.anchor = anchor
|
||||||
|
self._selected = False
|
||||||
|
self._disconnect_funcs = []
|
||||||
|
self.connect("parent-set", self.on_parent_set)
|
||||||
|
self.connect("expose-event", self.on_expose)
|
||||||
|
|
||||||
|
def _get_selected(self):
|
||||||
|
parent = self.get_parent()
|
||||||
|
if not parent or not self.anchor: return False
|
||||||
|
buffer = parent.get_buffer()
|
||||||
|
position = buffer.get_iter_at_child_anchor(self.anchor)
|
||||||
|
bounds = buffer.get_selection_bounds()
|
||||||
|
if bounds and position.in_range(*bounds):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
parent = self.get_parent()
|
||||||
|
if not parent:
|
||||||
|
return gtk.STATE_NORMAL
|
||||||
|
if self._selected:
|
||||||
|
if has_focus(parent):
|
||||||
|
return gtk.STATE_SELECTED
|
||||||
|
else:
|
||||||
|
return gtk.STATE_ACTIVE
|
||||||
|
else:
|
||||||
|
return gtk.STATE_NORMAL
|
||||||
|
|
||||||
|
def _update_selected(self):
|
||||||
|
selected = self._get_selected()
|
||||||
|
if self._selected != selected:
|
||||||
|
self._selected = selected
|
||||||
|
self.queue_draw()
|
||||||
|
|
||||||
|
def _do_connect(self, widget, signal, callback):
|
||||||
|
id = widget.connect(signal, callback)
|
||||||
|
def disconnect():
|
||||||
|
widget.disconnect(id)
|
||||||
|
self._disconnect_funcs.append(disconnect)
|
||||||
|
|
||||||
|
def _disconnect_signals(self):
|
||||||
|
for func in self._disconnect_funcs:
|
||||||
|
func()
|
||||||
|
self._disconnect_funcs = []
|
||||||
|
|
||||||
|
def on_parent_set(self, widget, old_parent):
|
||||||
|
parent = self.get_parent()
|
||||||
|
if not parent:
|
||||||
|
self._disconnect_signals()
|
||||||
|
return
|
||||||
|
|
||||||
|
self._do_connect(parent, "style-set", self.do_queue_draw)
|
||||||
|
self._do_connect(parent, "focus-in-event", self.do_queue_draw)
|
||||||
|
self._do_connect(parent, "focus-out-event", self.do_queue_draw)
|
||||||
|
|
||||||
|
textbuf = parent.get_buffer()
|
||||||
|
self._do_connect(textbuf, "mark-set", self.on_mark_set)
|
||||||
|
self._do_connect(textbuf, "mark-deleted", self.on_mark_deleted)
|
||||||
|
|
||||||
|
def do_queue_draw(self, *args):
|
||||||
|
self.queue_draw()
|
||||||
|
return False
|
||||||
|
|
||||||
|
def on_mark_set(self, buf, iterat, mark):
|
||||||
|
self.on_mark_modified(mark)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def on_mark_deleted(self, buf, mark):
|
||||||
|
self.on_mark_modified(mark)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def on_mark_modified(self, mark):
|
||||||
|
if is_selection_modified(mark):
|
||||||
|
self._update_selected()
|
||||||
|
|
||||||
|
def on_expose(self, widget, event):
|
||||||
|
state = self.get_state()
|
||||||
|
if state != gtk.STATE_NORMAL:
|
||||||
|
gc = widget.get_style().base_gc[state]
|
||||||
|
area = widget.allocation
|
||||||
|
widget.window.draw_rectangle(gc, True, area.x, area.y,
|
||||||
|
area.width, area.height)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class ConversationTextview:
|
class ConversationTextview:
|
||||||
'''Class for the conversation textview (where user reads already said messages)
|
'''Class for the conversation textview (where user reads already said messages)
|
||||||
for chat/groupchat windows'''
|
for chat/groupchat windows'''
|
||||||
|
@ -67,6 +168,8 @@ class ConversationTextview:
|
||||||
self.tv.set_left_margin(2)
|
self.tv.set_left_margin(2)
|
||||||
self.tv.set_right_margin(2)
|
self.tv.set_right_margin(2)
|
||||||
self.handlers = {}
|
self.handlers = {}
|
||||||
|
self.images = []
|
||||||
|
self.image_cache = {}
|
||||||
|
|
||||||
# connect signals
|
# connect signals
|
||||||
id = self.tv.connect('motion_notify_event',
|
id = self.tv.connect('motion_notify_event',
|
||||||
|
@ -78,6 +181,11 @@ class ConversationTextview:
|
||||||
self.on_textview_button_press_event)
|
self.on_textview_button_press_event)
|
||||||
self.handlers[id] = self.tv
|
self.handlers[id] = self.tv
|
||||||
|
|
||||||
|
id = self.tv.connect("expose-event",
|
||||||
|
self.on_textview_expose_event)
|
||||||
|
self.handlers[id] = self.tv
|
||||||
|
|
||||||
|
|
||||||
self.account = account
|
self.account = account
|
||||||
self.change_cursor = None
|
self.change_cursor = None
|
||||||
self.last_time_printout = 0
|
self.last_time_printout = 0
|
||||||
|
@ -337,6 +445,32 @@ class ConversationTextview:
|
||||||
self.line_tooltip.show_tooltip(_('Text below this line is what has '
|
self.line_tooltip.show_tooltip(_('Text below this line is what has '
|
||||||
'been said since the last time you paid attention to this group chat'), 8, position[1] + pointer[1])
|
'been said since the last time you paid attention to this group chat'), 8, position[1] + pointer[1])
|
||||||
|
|
||||||
|
def on_textview_expose_event(self, widget, event):
|
||||||
|
expalloc = event.area
|
||||||
|
exp_x0 = expalloc.x
|
||||||
|
exp_y0 = expalloc.y
|
||||||
|
exp_x1 = exp_x0 + expalloc.width
|
||||||
|
exp_y1 = exp_y0 + expalloc.height
|
||||||
|
|
||||||
|
try:
|
||||||
|
tryfirst = [self.image_cache[(exp_x0, exp_y0)]]
|
||||||
|
except KeyError:
|
||||||
|
tryfirst = []
|
||||||
|
|
||||||
|
for image in tryfirst + self.images:
|
||||||
|
imgalloc = image.allocation
|
||||||
|
img_x0 = imgalloc.x
|
||||||
|
img_y0 = imgalloc.y
|
||||||
|
img_x1 = img_x0 + imgalloc.width
|
||||||
|
img_y1 = img_y0 + imgalloc.height
|
||||||
|
|
||||||
|
if img_x0 <= exp_x0 and img_y0 <= exp_y0 and \
|
||||||
|
exp_x1 <= img_x1 and exp_y1 <= img_y1:
|
||||||
|
self.image_cache[(img_x0, img_y0)] = image
|
||||||
|
widget.propagate_expose(image, event)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def on_textview_motion_notify_event(self, widget, event):
|
def on_textview_motion_notify_event(self, widget, event):
|
||||||
'''change the cursor to a hand when we are over a mail or an url'''
|
'''change the cursor to a hand when we are over a mail or an url'''
|
||||||
pointer_x, pointer_y, spam = self.tv.window.get_pointer()
|
pointer_x, pointer_y, spam = self.tv.window.get_pointer()
|
||||||
|
@ -720,13 +854,14 @@ class ConversationTextview:
|
||||||
emot_ascii = possible_emot_ascii_caps
|
emot_ascii = possible_emot_ascii_caps
|
||||||
end_iter = buffer.get_end_iter()
|
end_iter = buffer.get_end_iter()
|
||||||
anchor = buffer.create_child_anchor(end_iter)
|
anchor = buffer.create_child_anchor(end_iter)
|
||||||
img = gtk.Image()
|
img = TextViewImage(anchor)
|
||||||
animations = gajim.interface.emoticons_animations
|
animations = gajim.interface.emoticons_animations
|
||||||
if not emot_ascii in animations:
|
if not emot_ascii in animations:
|
||||||
animations[emot_ascii] = gtk.gdk.PixbufAnimation(
|
animations[emot_ascii] = gtk.gdk.PixbufAnimation(
|
||||||
gajim.interface.emoticons[emot_ascii])
|
gajim.interface.emoticons[emot_ascii])
|
||||||
img.set_from_animation(animations[emot_ascii])
|
img.set_from_animation(animations[emot_ascii])
|
||||||
img.show()
|
img.show()
|
||||||
|
self.images.append(img)
|
||||||
# add with possible animation
|
# add with possible animation
|
||||||
self.tv.add_child_at_anchor(img, anchor)
|
self.tv.add_child_at_anchor(img, anchor)
|
||||||
#FIXME: one day, somehow sync with regexp in gajim.py
|
#FIXME: one day, somehow sync with regexp in gajim.py
|
||||||
|
|
Loading…
Add table
Reference in a new issue