Fix infinite expand of MessageTextView
- The 'configure-event' does not trigger anymore when connected to the MessageTextView. The reason is unknown. - Use our own ScrolledWindow Widget instead so we can better control the dimension of the MessageTextView
This commit is contained in:
parent
c963fc5dcc
commit
b8aaf09c13
|
@ -629,21 +629,7 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="message_scrolledwindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<property name="vscrollbar_policy">never</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
|
|
|
@ -44,6 +44,7 @@ import notify
|
|||
import re
|
||||
|
||||
import emoticons
|
||||
from scrolled_window import ScrolledWindow
|
||||
from common import events
|
||||
from common import gajim
|
||||
from common import helpers
|
||||
|
@ -327,15 +328,21 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
self.last_received_id = {} # one per name
|
||||
|
||||
# add MessageTextView to UI and connect signals
|
||||
self.msg_scrolledwindow = self.xml.get_object('message_scrolledwindow')
|
||||
self.msg_textview = MessageTextView()
|
||||
|
||||
self.msg_scrolledwindow = ScrolledWindow()
|
||||
self.msg_scrolledwindow.set_max_content_height(100)
|
||||
self.msg_scrolledwindow.set_min_content_height(23)
|
||||
|
||||
self.msg_scrolledwindow.set_property('shadow_type', Gtk.ShadowType.IN)
|
||||
self.msg_scrolledwindow.add(self.msg_textview)
|
||||
|
||||
hbox = self.xml.get_object('hbox')
|
||||
hbox.pack_end(self.msg_scrolledwindow, True, True, 0)
|
||||
|
||||
id_ = self.msg_textview.connect('key_press_event',
|
||||
self._on_message_textview_key_press_event)
|
||||
self.handlers[id_] = self.msg_textview
|
||||
id_ = self.msg_textview.connect('configure-event',
|
||||
self.on_configure_event)
|
||||
self.handlers[id_] = self.msg_textview
|
||||
id_ = self.msg_textview.connect('populate_popup',
|
||||
self.on_msg_textview_populate_popup)
|
||||
self.handlers[id_] = self.msg_textview
|
||||
|
@ -369,8 +376,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
# For XEP-0172
|
||||
self.user_nick = None
|
||||
|
||||
self.smooth = True
|
||||
|
||||
self.command_hits = []
|
||||
self.last_key_tabs = False
|
||||
|
||||
|
@ -693,6 +698,10 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
self.send_message(message, xhtml=xhtml)
|
||||
else:
|
||||
message_buffer.insert_at_cursor('\n')
|
||||
mark = message_buffer.get_insert()
|
||||
iter_ = message_buffer.get_iter_at_mark(mark)
|
||||
if message_buffer.get_end_iter().equal(iter_):
|
||||
GLib.idle_add(gtkgui_helpers.scroll_to_end, self.msg_scrolledwindow)
|
||||
|
||||
return True
|
||||
elif event.keyval == Gdk.KEY_z: # CTRL+z
|
||||
|
@ -1157,60 +1166,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
self.conv_textview.scroll_to_end_iter()
|
||||
return False
|
||||
|
||||
def on_configure_event(self, msg_textview, event):
|
||||
"""
|
||||
When message_textview changes its size: if the new height will enlarge
|
||||
the window, enable the scrollbar automatic policy. Also enable scrollbar
|
||||
automatic policy for horizontal scrollbar if message we have in
|
||||
message_textview is too big
|
||||
"""
|
||||
if msg_textview.get_window() is None:
|
||||
return
|
||||
|
||||
min_height = self.conv_scrolledwindow.get_property('height-request')
|
||||
conversation_height = self.conv_textview.tv.get_window().get_size()[1]
|
||||
message_height = msg_textview.get_window().get_size()[1]
|
||||
message_width = msg_textview.get_window().get_size()[0]
|
||||
# new tab is not exposed yet
|
||||
if conversation_height < 2:
|
||||
return
|
||||
|
||||
if conversation_height < min_height:
|
||||
min_height = conversation_height
|
||||
|
||||
# we don't want to always resize in height the message_textview
|
||||
# so we have minimum on conversation_textview's scrolled window
|
||||
# but we also want to avoid window resizing so if we reach that
|
||||
# minimum for conversation_textview and maximum for message_textview
|
||||
# we set to automatic the scrollbar policy
|
||||
diff_y = message_height - event.height
|
||||
if diff_y != 0:
|
||||
if conversation_height + diff_y < min_height:
|
||||
if message_height + conversation_height - min_height > min_height:
|
||||
policy = self.msg_scrolledwindow.get_property(
|
||||
'vscrollbar-policy')
|
||||
if policy != Gtk.PolicyType.AUTOMATIC:
|
||||
self.msg_scrolledwindow.set_property('vscrollbar-policy',
|
||||
Gtk.PolicyType.AUTOMATIC)
|
||||
self.msg_scrolledwindow.set_property('height-request',
|
||||
message_height + conversation_height - min_height)
|
||||
else:
|
||||
self.msg_scrolledwindow.set_property('vscrollbar-policy',
|
||||
Gtk.PolicyType.NEVER)
|
||||
self.msg_scrolledwindow.set_property('height-request', -1)
|
||||
|
||||
self.smooth = True # reinit the flag
|
||||
# enable scrollbar automatic policy for horizontal scrollbar
|
||||
# if message we have in message_textview is too big
|
||||
if event.width > message_width:
|
||||
self.msg_scrolledwindow.set_property('hscrollbar-policy',
|
||||
Gtk.PolicyType.AUTOMATIC)
|
||||
else:
|
||||
self.msg_scrolledwindow.set_property('hscrollbar-policy',
|
||||
Gtk.PolicyType.NEVER)
|
||||
|
||||
return True
|
||||
|
||||
def on_conversation_vadjustment_changed(self, adjustment):
|
||||
# used to stay at the end of the textview when we shrink conversation
|
||||
# textview.
|
||||
|
|
|
@ -29,6 +29,7 @@ from gi.repository import GLib
|
|||
from gi.repository import Pango
|
||||
|
||||
from common import gajim
|
||||
import gtkgui_helpers
|
||||
|
||||
class MessageTextView(Gtk.TextView):
|
||||
"""
|
||||
|
@ -38,7 +39,7 @@ class MessageTextView(Gtk.TextView):
|
|||
UNDO_LIMIT = 20
|
||||
|
||||
def __init__(self):
|
||||
GObject.GObject.__init__(self)
|
||||
Gtk.TextView.__init__(self)
|
||||
|
||||
# set properties
|
||||
self.set_border_width(1)
|
||||
|
@ -79,6 +80,15 @@ class MessageTextView(Gtk.TextView):
|
|||
self.begin_tags['strike'] = '<span style="text-decoration: line-through;">'
|
||||
self.end_tags['strike'] = '</span>'
|
||||
|
||||
self.connect_after('paste-clipboard', self.after_paste_clipboard)
|
||||
|
||||
def after_paste_clipboard(self, textview):
|
||||
buffer_ = textview.get_buffer()
|
||||
mark = buffer_.get_insert()
|
||||
iter_ = buffer_.get_iter_at_mark(mark)
|
||||
if iter_.get_offset() == buffer_.get_end_iter().get_offset():
|
||||
GLib.idle_add(gtkgui_helpers.scroll_to_end, textview.get_parent())
|
||||
|
||||
def make_clickable_urls(self, text):
|
||||
_buffer = self.get_buffer()
|
||||
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
# -*- coding:utf-8 -*-
|
||||
# Copyright (C) 2015 Patrick Griffis <tingping@tingping.se>
|
||||
# Copyright (C) 2014 Christian Hergert <christian@hergert.me>
|
||||
#
|
||||
# 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 warranties of
|
||||
# MERCHANTABILITY, SATISFACTORY QUALITY, 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/>.
|
||||
|
||||
from gi.repository import GObject, Gtk
|
||||
|
||||
class ScrolledWindow(Gtk.ScrolledWindow):
|
||||
"""
|
||||
ScrolledWindow that sets a max size for the child to grow into.
|
||||
Taken from the Gnome Builder project:
|
||||
https://git.gnome.org/browse/gnome-builder/tree/contrib/egg/egg-scrolled-window.c
|
||||
"""
|
||||
__gtype_name__ = "EggScrolledWindow"
|
||||
|
||||
max_content_height = GObject.Property(type=int, default=-1, nick="Max Content Height",
|
||||
blurb="The maximum height request that can be made")
|
||||
max_content_width = GObject.Property(type=int, default=-1, nick="Max Content Width",
|
||||
blurb="The maximum width request that can be made")
|
||||
min_content_height = GObject.Property(type=int, default=-1, nick="Min Content Height",
|
||||
blurb="The minimum height request that can be made")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.connect_after("notify::max-content-height", lambda obj, param: self.queue_resize())
|
||||
self.connect_after("notify::max-content-width", lambda obj, param: self.queue_resize())
|
||||
|
||||
def set_min_content_height(self, value):
|
||||
self.min_content_height = value
|
||||
|
||||
def set_max_content_height(self, value):
|
||||
self.max_content_height = value
|
||||
|
||||
def set_max_content_width(self, value):
|
||||
self.max_content_width = value
|
||||
|
||||
def get_max_content_height(self):
|
||||
return self.max_content_height
|
||||
|
||||
def get_max_content_width(self):
|
||||
return self.max_content_width
|
||||
|
||||
def do_get_preferred_height(self):
|
||||
min_height, natural_height = Gtk.ScrolledWindow.do_get_preferred_height(self)
|
||||
child = self.get_child()
|
||||
|
||||
if natural_height and self.max_content_height > -1 and child:
|
||||
|
||||
style = self.get_style_context()
|
||||
border = style.get_border(style.get_state())
|
||||
additional = border.top + border.bottom
|
||||
|
||||
child_min_height, child_nat_height = child.get_preferred_height()
|
||||
if child_nat_height > natural_height and self.max_content_height > natural_height:
|
||||
natural_height = min(self.max_content_height, child_nat_height) + additional
|
||||
elif natural_height > child_nat_height:
|
||||
if child_nat_height < self.min_content_height:
|
||||
return self.min_content_height, self.min_content_height
|
||||
min_height, natural_height = child_min_height + additional, child_nat_height + additional
|
||||
|
||||
return min_height, natural_height
|
||||
|
||||
def do_get_preferred_width(self):
|
||||
min_width, natural_width = Gtk.ScrolledWindow.do_get_preferred_width(self)
|
||||
child = self.get_child()
|
||||
|
||||
if natural_width and self.max_content_width > -1 and child:
|
||||
|
||||
style = self.get_style_context()
|
||||
border = style.get_border(style.get_state())
|
||||
additional = border.left + border.right + 1
|
||||
|
||||
child_min_width, child_nat_width = child.get_preferred_width()
|
||||
if child_nat_width > natural_width and self.max_content_width > natural_width:
|
||||
natural_width = min(self.max_content_width, child_nat_width) + additional
|
||||
|
||||
return min_width, natural_width
|
Loading…
Reference in New Issue