[Geobert] Smooth scrolling of conversation textview. see #3358
This commit is contained in:
parent
b60036af8f
commit
7bd952d691
|
@ -253,6 +253,8 @@ class ChatControlBase(MessageControl):
|
|||
# For JEP-0172
|
||||
self.user_nick = None
|
||||
|
||||
self.smooth = True
|
||||
|
||||
def on_msg_textview_populate_popup(self, textview, menu):
|
||||
'''we override the default context menu and we prepend an option to switch languages'''
|
||||
def _on_select_dictionary(widget, lang):
|
||||
|
@ -812,9 +814,10 @@ class ChatControlBase(MessageControl):
|
|||
self.msg_scrolledwindow.set_property('vscrollbar-policy',
|
||||
gtk.POLICY_NEVER)
|
||||
self.msg_scrolledwindow.set_property('height-request', -1)
|
||||
|
||||
self.conv_textview.bring_scroll_to_end(diff_y - 18)
|
||||
|
||||
self.conv_textview.bring_scroll_to_end(diff_y - 18, False)
|
||||
else:
|
||||
self.conv_textview.bring_scroll_to_end(diff_y - 18, self.smooth)
|
||||
self.smooth = True # reinit the flag
|
||||
# enable scrollbar automatic policy for horizontal scrollbar
|
||||
# if message we have in message_textview is too big
|
||||
if requisition.width > message_width:
|
||||
|
@ -895,6 +898,7 @@ class ChatControlBase(MessageControl):
|
|||
if self.sent_history_pos == 0:
|
||||
return
|
||||
self.sent_history_pos = self.sent_history_pos - 1
|
||||
self.smooth = False
|
||||
conv_buf.set_text(self.sent_history[self.sent_history_pos])
|
||||
elif direction == 'down':
|
||||
if self.sent_history_pos >= size - 1:
|
||||
|
@ -904,6 +908,7 @@ class ChatControlBase(MessageControl):
|
|||
return
|
||||
|
||||
self.sent_history_pos = self.sent_history_pos + 1
|
||||
self.smooth = False
|
||||
conv_buf.set_text(self.sent_history[self.sent_history_pos])
|
||||
|
||||
def lighten_color(self, color):
|
||||
|
|
|
@ -218,6 +218,7 @@ class Config:
|
|||
'hide_groupchat_occupants_list': [opt_bool, False, _('Hides the group chat occupants list in group chat window.')],
|
||||
'chat_merge_consecutive_nickname': [opt_bool, False, _('In a chat, show the nickname at the beginning of a line only when it\'s not the same person talking than in previous message.')],
|
||||
'chat_merge_consecutive_nickname_indent': [opt_str, ' ', _('Indentation when using merge consecutive nickname.')],
|
||||
'use_smooth_scrolling': [opt_bool, True, _('Smooth scroll message in conversation window')],
|
||||
'gc_nicknames_colors': [ opt_str, '#a34526:#c000ff:#0012ff:#388a99:#045723:#7c7c7c:#ff8a00:#94452d:#244b5a:#32645a', _('List of colors that will be used to color nicknames in group chats.'), True ],
|
||||
'ctrl_tab_go_to_next_composing': [opt_bool, True, _('Ctrl-Tab go to next composing tab when none is unread.')],
|
||||
'confirm_metacontacts': [ opt_str, '', _('Should we show the confirm metacontacts creation dialog or not? Empty string means we never show the dialog.')],
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
import random
|
||||
from tempfile import gettempdir
|
||||
from subprocess import Popen
|
||||
from threading import Timer # for smooth scrolling
|
||||
|
||||
import gtk
|
||||
import pango
|
||||
|
@ -44,6 +45,10 @@ class ConversationTextview:
|
|||
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'muc_separator.png')
|
||||
FOCUS_OUT_LINE_PIXBUF = gtk.gdk.pixbuf_new_from_file(path_to_file)
|
||||
|
||||
# smooth scroll constants
|
||||
MAX_SCROLL_TIME = 0.4 # seconds
|
||||
SCROLL_DELAY = 33 # milliseconds
|
||||
|
||||
def __init__(self, account, used_in_history_window = False):
|
||||
'''if used_in_history_window is True, then we do not show
|
||||
Clear menuitem in context menu'''
|
||||
|
@ -154,6 +159,7 @@ class ConversationTextview:
|
|||
self.line_tooltip = tooltips.BaseTooltip()
|
||||
# use it for hr too
|
||||
self.tv.focus_out_line_pixbuf = ConversationTextview.FOCUS_OUT_LINE_PIXBUF
|
||||
self.smooth_id = None
|
||||
|
||||
def del_handlers(self):
|
||||
for i in self.handlers.keys():
|
||||
|
@ -181,6 +187,41 @@ class ConversationTextview:
|
|||
return True
|
||||
return False
|
||||
|
||||
# Smooth scrolling inspired by Pidgin code
|
||||
def smooth_scroll(self):
|
||||
parent = self.tv.get_parent()
|
||||
if not parent:
|
||||
return False
|
||||
vadj = parent.get_vadjustment()
|
||||
max_val = vadj.upper - vadj.page_size + 1
|
||||
cur_val = vadj.get_value()
|
||||
# scroll by 1/3rd of remaining distance
|
||||
onethird = cur_val + ((max_val - cur_val) / 3.0)
|
||||
vadj.set_value(onethird)
|
||||
if max_val - onethird < 0.01:
|
||||
self.smooth_id = None
|
||||
self.smooth_scroll_timer.cancel()
|
||||
return False
|
||||
return True
|
||||
|
||||
def smooth_scroll_timeout(self):
|
||||
gobject.source_remove(self.smooth_id)
|
||||
self.smooth_id = None
|
||||
parent = self.tv.get_parent()
|
||||
if parent:
|
||||
vadj = parent.get_vadjustment()
|
||||
vadj.set_value(vadj.upper - vadj.page_size + 1)
|
||||
|
||||
def smooth_scroll_to_end(self):
|
||||
if None != self.smooth_id: # already scrolling
|
||||
return False
|
||||
self.smooth_id = gobject.timeout_add(self.SCROLL_DELAY,
|
||||
self.smooth_scroll)
|
||||
self.smooth_scroll_timer = Timer(self.MAX_SCROLL_TIME,
|
||||
self.smooth_scroll_timeout)
|
||||
self.smooth_scroll_timer.start()
|
||||
return False
|
||||
|
||||
def scroll_to_end(self):
|
||||
parent = self.tv.get_parent()
|
||||
buffer = self.tv.get_buffer()
|
||||
|
@ -192,7 +233,9 @@ class ConversationTextview:
|
|||
adjustment.set_value(0)
|
||||
return False # when called in an idle_add, just do it once
|
||||
|
||||
def bring_scroll_to_end(self, diff_y = 0):
|
||||
def bring_scroll_to_end(self, diff_y = 0,\
|
||||
use_smooth =\
|
||||
gajim.config.get('use_smooth_scrolling')):
|
||||
''' scrolls to the end of textview if end is not visible '''
|
||||
buffer = self.tv.get_buffer()
|
||||
end_iter = buffer.get_end_iter()
|
||||
|
@ -200,6 +243,9 @@ class ConversationTextview:
|
|||
visible_rect = self.tv.get_visible_rect()
|
||||
# scroll only if expected end is not visible
|
||||
if end_rect.y >= (visible_rect.y + visible_rect.height + diff_y):
|
||||
if use_smooth:
|
||||
gobject.idle_add(self.smooth_scroll_to_end)
|
||||
else:
|
||||
gobject.idle_add(self.scroll_to_end_iter)
|
||||
|
||||
def scroll_to_end_iter(self):
|
||||
|
@ -857,6 +903,9 @@ class ConversationTextview:
|
|||
if at_the_end or kind == 'outgoing':
|
||||
# we are at the end or we are sending something
|
||||
# scroll to the end (via idle in case the scrollbar has appeared)
|
||||
if gajim.config.get('use_smooth_scrolling'):
|
||||
gobject.idle_add(self.smooth_scroll_to_end)
|
||||
else:
|
||||
gobject.idle_add(self.scroll_to_end)
|
||||
|
||||
buffer.end_user_action()
|
||||
|
|
Loading…
Reference in New Issue