Improve auto-scrolling after pasting very large documents

There were 2 problems.

When pasting very large documents, the height calculations will be
temporarily incorrect while the content is rendered over several frames.
This is addressed by waiting for the UI to be idle to scroll.

Additionally, the scroll time (typically 200ms) needs an adjustment as
well. Starting at 200ms, it now scales linearly with distance, amounting
to roughly 4 seconds with Pandoc's user guide.
ft.font-size^2
Gonçalo Silva 2019-04-11 03:33:31 +01:00
parent bf657891c6
commit ac7e18b0b3
2 changed files with 20 additions and 20 deletions

View File

@ -1,47 +1,47 @@
class Scroller:
def __init__(self, scrolled_window, target_pos, source_pos, duration=2000):
def __init__(self, scrolled_window, source_pos, target_pos):
super().__init__()
self.scrolled_window = scrolled_window
self.target_pos = target_pos
self.source_pos = source_pos
self.duration = duration
self.target_pos = target_pos
self.duration = max(200, (target_pos - source_pos) / 50) * 1000
self.is_started = False
self.is_setup = False
self.start_time = 0
self.end_time = 0
self.tick_callback_id = 0
def start(self):
self.tick_callback_id = self.scrolled_window.add_tick_callback(self.on_tick, self)
self.is_started = True
self.tick_callback_id = self.scrolled_window.add_tick_callback(self.on_tick)
def end(self):
self.is_started = False
self.scrolled_window.remove_tick_callback(self.tick_callback_id)
self.is_started = False
def do_start(self, time):
self.is_started = True
def setup(self, time):
self.start_time = time
self.end_time = time + self.duration * 100
self.end_time = time + self.duration
self.is_setup = True
@staticmethod
def on_tick(widget, frame_clock, scroller):
def on_tick(self, widget, frame_clock):
def ease_out_cubic(value):
return pow(value - 1, 3) + 1
now = frame_clock.get_frame_time()
if not scroller.is_started:
scroller.do_start(now)
if not self.is_setup:
self.setup(now)
if now < scroller.end_time:
time = float(now - scroller.start_time) / float(scroller.end_time - scroller.start_time)
if now < self.end_time:
time = float(now - self.start_time) / float(self.end_time - self.start_time)
else:
time = 1
scroller.end()
self.end()
time = ease_out_cubic(time)
pos = scroller.source_pos + (time * (scroller.target_pos - scroller.source_pos))
pos = self.source_pos + (time * (self.target_pos - self.source_pos))
widget.get_vadjustment().props.value = pos
return True

View File

@ -8,7 +8,7 @@ from uberwriter.text_view_drag_drop_handler import DragDropHandler, TARGET_URI,
from uberwriter.scroller import Scroller
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GObject
from gi.repository import Gtk, Gdk, GObject, GLib
import logging
LOGGER = logging.getLogger('uberwriter')
@ -104,7 +104,7 @@ class TextView(Gtk.TextView):
def on_text_changed(self, *_):
self.markup.apply()
self.scroll_to()
GLib.idle_add(self.scroll_to)
def on_size_allocate(self, *_):
self.update_vertical_margin()
@ -186,7 +186,7 @@ class TextView(Gtk.TextView):
if self.scroller and self.scroller.is_started:
self.scroller.end()
if target_pos:
self.scroller = Scroller(scrolled_window, target_pos, va.props.value)
self.scroller = Scroller(scrolled_window, va.props.value, target_pos)
self.scroller.start()
def on_mark_set(self, _text_buffer, _location, mark, _data=None):