Skip to content
Snippets Groups Projects
Commit 10844fc7 authored by Philipp Hörist's avatar Philipp Hörist
Browse files

Add ScrolledView

parent e75092f8
No related branches found
No related tags found
No related merge requests found
......@@ -180,8 +180,8 @@ def __init__(self, parent_win, jid, acct, session, resource=None):
content_area.add(self.info_bar_label)
self.info_bar.set_no_show_all(True)
self.xml.vbox2.pack_start(self.info_bar, False, True, 5)
self.xml.vbox2.reorder_child(self.info_bar, 1)
self.xml.textview_box.pack_start(self.info_bar, False, True, 5)
self.xml.textview_box.reorder_child(self.info_bar, 1)
# List of waiting infobar messages
self.info_bar_queue = []
......
......@@ -49,6 +49,7 @@
from gajim import gtkgui_helpers
from gajim.gui.conversation.view import ConversationView
from gajim.gui.conversation.scrolled import ScrolledView
from gajim.gui.dialogs import DialogButton
from gajim.gui.dialogs import ConfirmationDialog
from gajim.gui.dialogs import PastePreviewDialog
......@@ -166,38 +167,18 @@ def __init__(self, parent_win, widget_name, jid, acct,
# Create ConversationView and connect signals
self.conversation_view = ConversationView(self.account, self.contact)
id_ = self.conversation_view.connect('quote', self.on_quote)
self.handlers[id_] = self.conversation_view
id_ = self.conversation_view.connect(
'load-history', self._on_load_history)
self.handlers[id_] = self.conversation_view
self.conversation_view.connect('quote', self.on_quote)
id_ = self.conversation_view.connect(
'key-press-event', self._on_conversation_view_key_press)
self.handlers[id_] = self.conversation_view
# This is a workaround: as soon as a line break occurs in Gtk.TextView
# with word-char wrapping enabled, a hyphen character is automatically
# inserted before the line break. This triggers the hscrollbar to show,
# see: https://gitlab.gnome.org/GNOME/gtk/-/issues/2384
# Using set_hscroll_policy(Gtk.Scrollable.Policy.NEVER) would cause bad
# performance during resize, and prevent the window from being shrunk
# horizontally under certain conditions (applies to GroupchatControl)
hscrollbar = self.xml.conversation_scrolledwindow.get_hscrollbar()
hscrollbar.hide()
self.xml.conversation_scrolledwindow.add(self.conversation_view)
self._scrolled_old_upper = None
self._scrolled_old_value = None
self._fetch_start_upper = None
self._current_upper = 0
self._autoscroll = True
self._no_more_messages = False
vadjustment = self.xml.conversation_scrolledwindow.get_vadjustment()
vadjustment.connect('notify::upper', self._on_adj_upper_changed)
vadjustment.connect('notify::value', self._on_adj_value_changed)
self._scrolled_view = ScrolledView()
self._scrolled_view.add(self.conversation_view)
self.xml.textview_box.add(self._scrolled_view)
self.xml.textview_box.reorder_child(self._scrolled_view, 2)
self._scrolled_view.connect('request-history',
self.fetch_n_lines_history, 30)
self.msg_textview = MessageInputTextView()
self.msg_textview.connect('paste-clipboard',
......@@ -710,7 +691,11 @@ def shutdown(self):
self.handlers[i].disconnect(i)
self.handlers.clear()
self.conversation_view.destroy()
self._scrolled_view.destroy()
del self.conversation_view
del self._scrolled_view
del self.msg_textview
del self.msg_scrolledwindow
......@@ -1406,10 +1391,7 @@ def set_control_active(self, state):
def scroll_to_end(self, force=False):
self.conversation_view.scroll_to_end(force)
def _on_load_history(self, _button, lines):
self.fetch_n_lines_history(lines)
def fetch_n_lines_history(self, n_lines):
def fetch_n_lines_history(self, _scrolled, n_lines):
row = self.conversation_view.get_first_message_row()
if row is None:
timestamp = time.time()
......@@ -1430,8 +1412,7 @@ def fetch_n_lines_history(self, n_lines):
n_lines)
if not messages:
self._no_more_messages = True
print('SET NO MORE')
self._scrolled_view.set_history_complete()
return
for msg in messages:
......@@ -1470,46 +1451,6 @@ def has_focus(self):
return True
return False
def _on_adj_upper_changed(self, adj, *args):
upper = adj.get_upper()
diff = upper - self._current_upper
if diff != 0:
self._current_upper = upper
if self._autoscroll:
adj.set_value(adj.get_upper() - adj.get_page_size())
else:
# Workaround: https://gitlab.gnome.org/GNOME/gtk/merge_requests/395
self.xml.conversation_scrolledwindow.set_kinetic_scrolling(True)
adj.set_value(adj.get_value() + diff)
if upper == adj.get_page_size():
# There is no scrollbar, load history until there is
self.fetch_n_lines_history(30)
def _on_adj_value_changed(self, adj, *args):
bottom = adj.get_upper() - adj.get_page_size()
if (bottom - adj.get_value()) < 1:
self._autoscroll = True
else:
self._autoscroll = False
if self._no_more_messages:
self._fetch_start_upper = None
return
if self._fetch_start_upper == adj.get_upper():
return
self._fetch_start_upper = None
# Load messages when we are near the top
if adj.get_value() < adj.get_page_size() * 2:
self._fetch_start_upper = adj.get_upper()
# Workaround: https://gitlab.gnome.org/GNOME/gtk/merge_requests/395
self.xml.conversation_scrolledwindow.set_kinetic_scrolling(False)
self.fetch_n_lines_history(30)
def scroll_messages(self, direction, msg_buf, msg_type):
if msg_type == 'sent':
history = self.sent_history
......
......@@ -403,7 +403,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkBox" id="vbox2">
<object class="GtkBox" id="textview_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
......@@ -618,25 +618,7 @@
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
<property name="height_request">60</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="overlay_scrolling">False</property>
<child>
<placeholder/>
</child>
<style>
<class name="scrolled-no-border"/>
<class name="no-scroll-indicator"/>
<class name="scrollbar-style"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
<placeholder/>
</child>
<child>
<object class="GtkSeparator">
......
......@@ -228,7 +228,7 @@
<property name="margin_bottom">7</property>
<property name="spacing">3</property>
<child>
<object class="GtkBox" id="gc_textviews_vbox">
<object class="GtkBox" id="textview_box">
<property name="width_request">0</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
......@@ -341,27 +341,7 @@
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
<property name="width_request">200</property>
<property name="height_request">60</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="overlay_scrolling">False</property>
<child>
<placeholder/>
</child>
<style>
<class name="scrolled-no-border"/>
<class name="no-scroll-indicator"/>
<class name="scrollbar-style"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
<placeholder/>
</child>
<child>
<object class="GtkSeparator">
......
......@@ -21,6 +21,10 @@
class DateRow(BaseRow):
def __init__(self, account, date_string, timestamp):
BaseRow.__init__(self, account)
self.set_selectable(False)
self.set_activatable(False)
self.type = 'date'
self.timestamp = timestamp
self.get_style_context().add_class('conversation-date-row')
......
......@@ -24,6 +24,9 @@
class ScrollHintRow(BaseRow):
def __init__(self, account, history_mode=False):
BaseRow.__init__(self, account)
self.set_selectable(False)
self.set_activatable(False)
self.type = 'system'
self.timestamp = datetime.fromtimestamp(0)
......@@ -42,11 +45,5 @@ def __init__(self, account, history_mode=False):
self.label.set_text(_('Scroll up to load more chat history…'))
self.grid.attach(self.label, 0, 1, 1, 1)
self._button = Gtk.Button.new_from_icon_name(
'go-up-symbolic', Gtk.IconSize.BUTTON)
self._button.set_tooltip_text(_('Load more messages'))
self._button.connect('clicked', self._on_load_history)
self.grid.attach(self._button, 0, 0, 1, 1)
def _on_load_history(self, _button):
self.get_parent().emit('load-history', 30)
def set_history_complete(self):
self.label.set_text(_('There is no more history'))
# This file is part of Gajim.
#
# Gajim 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; version 3 only.
#
# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
from gi.repository import Gtk
from gi.repository import GObject
class ScrolledView(Gtk.ScrolledWindow):
__gsignals__ = {
'request-history': (
GObject.SignalFlags.RUN_LAST | GObject.SignalFlags.ACTION,
None,
()
)
}
def __init__(self, *args, **kwargs):
Gtk.ScrolledWindow.__init__(self, *args, **kwargs)
self.set_overlay_scrolling(False)
self.get_style_context().add_class('scrolled-no-border')
self.get_style_context().add_class('no-scroll-indicator')
self.get_style_context().add_class('scrollbar-style')
self.set_shadow_type(Gtk.ShadowType.IN)
self.set_vexpand(True)
self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
# This is a workaround: as soon as a line break occurs in Gtk.TextView
# with word-char wrapping enabled, a hyphen character is automatically
# inserted before the line break. This triggers the hscrollbar to show,
# see: https://gitlab.gnome.org/GNOME/gtk/-/issues/2384
# Using set_hscroll_policy(Gtk.Scrollable.Policy.NEVER) would cause bad
# performance during resize, and prevent the window from being shrunk
# horizontally under certain conditions (applies to GroupchatControl)
self.get_hscrollbar().hide()
self._current_upper = 0
self._autoscroll = True
self._request_history_at_upper = None
self._complete = False
vadjustment = self.get_vadjustment()
vadjustment.connect('notify::upper', self._on_adj_upper_changed)
vadjustment.connect('notify::value', self._on_adj_value_changed)
@property
def autoscroll(self):
return self._autoscroll
def set_history_complete(self):
self._complete = True
self.get_child().get_child().set_history_complete()
def _on_adj_upper_changed(self, adj, *args):
upper = adj.get_upper()
diff = upper - self._current_upper
if diff != 0:
self._current_upper = upper
if self._autoscroll:
adj.set_value(adj.get_upper() - adj.get_page_size())
else:
# Workaround
# https://gitlab.gnome.org/GNOME/gtk/merge_requests/395
self.set_kinetic_scrolling(True)
adj.set_value(adj.get_value() + diff)
if upper == adj.get_page_size():
# There is no scrollbar, request history until there is
self.emit('request-history')
def _on_adj_value_changed(self, adj, *args):
bottom = adj.get_upper() - adj.get_page_size()
if (bottom - adj.get_value()) < 1:
self._autoscroll = True
else:
self._autoscroll = False
if self._complete:
self._request_history_at_upper = None
return
if self._request_history_at_upper == adj.get_upper():
# Abort here if we already did a history request and the upper
# did not change. This can happen if we scroll very fast and the
# value changes while the request has not been fullfilled.
return
self._request_history_at_upper = None
# Load messages when we are near the top
if adj.get_value() < adj.get_page_size() * 2:
self._request_history_at_upper = adj.get_upper()
# Workaround: https://gitlab.gnome.org/GNOME/gtk/merge_requests/395
self.set_kinetic_scrolling(False)
self.emit('request-history')
......@@ -48,11 +48,6 @@ class ConversationView(Gtk.ListBox):
None,
(str, )
),
'load-history': (
GObject.SignalFlags.RUN_LAST | GObject.SignalFlags.ACTION,
None,
(str, )
)
}
def __init__(self, account, contact, history_mode=False):
......@@ -95,7 +90,8 @@ def __init__(self, account, contact, history_mode=False):
self._last_incoming_timestamp = datetime.fromtimestamp(0)
# Insert the very first row, containing the scroll hint and load button
self.add(ScrollHintRow(self._account, history_mode=self._history_mode))
self._scroll_hint_row = ScrollHintRow(self._account)
self.add(self._scroll_hint_row)
self._timestamps_inserted.append(datetime.fromtimestamp(0))
def clear(self):
......@@ -111,6 +107,9 @@ def get_first_message_row(self):
return row
return None
def set_history_complete(self):
self._scroll_hint_row.set_history_complete()
def _reset_conversation_view(self):
self._first_date = None
self._last_date = None
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment