forked from Mirrors/apostrophe
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
parent
bf657891c6
commit
ac7e18b0b3
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue