[meld] filediff, misc: Align syncpoints at top/bottom better (bgo#780608)



commit 6b71cde5cf0455c1d7cbd6750ab4f39d1b730a46
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Tue Apr 25 11:29:58 2017 +1000

    filediff, misc: Align syncpoints at top/bottom better (bgo#780608)
    
    The issue here addressed by this change is that when we get scroll near
    the top or bottom of a pane, and the corresponding pane that gets its
    scroll set has more lines in the top-/bottom-most chunk, we won't ever
    scroll the whole dependent chunk in to view.
    
    For example, in a situation where we're scrolling to the bottom of a
    comparison in the left pane, with the right pane being set by this
    sync, and we have an end-of-file that looks like:
    
    viewport  left   right
        |     x      x
        |     x      x
        |     x      x
        |     a      b
        _     EOF    b
                     b
                     EOF
    
    the last two lines of b will often not be scrolled into view. The reason
    here is that the way we decide how to align the right pane is to find
    the middle of the left pane, figure out what chunk is there, find the
    corresponding chunk in the right pane and then try to align those lines.
    This means that the start and end of a file are aligned according to
    whatever chunk is half way up the page. This is fine and good, except
    that if e.g., the first `x` above is in the middle of the screen,
    there's no way that you can scroll the left pane down far enough to be
    able to see the bottom of the right pane.
    
    The fix here is that we adjust the syncpoint that we use according to
    where we are in the document. If we're showing the first half page, we
    scale our syncpoint to be toward the top of the page; if we're showing
    the last half page we scale the syncpoint towards the bottom. For most
    normal documents, the majority of the document will have a syncpoint
    of 0.5 (the middle of the screen) which is what we've always used.

 meld/filediff.py |    6 +++---
 meld/misc.py     |   29 +++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+), 3 deletions(-)
---
diff --git a/meld/filediff.py b/meld/filediff.py
index 10d3e19..8e4b6e5 100644
--- a/meld/filediff.py
+++ b/meld/filediff.py
@@ -1670,11 +1670,11 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
 
     @with_scroll_lock('_sync_vscroll_lock')
     def _sync_vscroll(self, adjustment, master):
-        SYNCPOINT = 0.5
+        syncpoint = misc.calc_syncpoint(adjustment)
 
         # Middle of the screen, in buffer coords
         middle_y = (
-            adjustment.get_value() + adjustment.get_page_size() * SYNCPOINT)
+            adjustment.get_value() + adjustment.get_page_size() * syncpoint)
 
         # Find the target line. This is a float because, especially for
         # wrapped lines, the sync point may be half way through a line.
@@ -1725,8 +1725,8 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             other_line = obegin + fraction * (oend - obegin)
             it = self.textbuffer[i].get_iter_at_line(int(other_line))
             val, height = self.textview[i].get_line_yrange(it)
-            val -= adj.get_page_size() * SYNCPOINT
             val += (other_line - int(other_line)) * height
+            val -= adj.get_page_size() * syncpoint
             val = min(max(val, adj.get_lower()),
                       adj.get_upper() - adj.get_page_size())
             val = math.floor(val)
diff --git a/meld/misc.py b/meld/misc.py
index ef329cb..b8b102f 100644
--- a/meld/misc.py
+++ b/meld/misc.py
@@ -514,3 +514,32 @@ def apply_text_filters(txt, regexes, apply_fn=None):
         offset = end
     result_txts.append(txt[offset:])
     return empty_string.join(result_txts)
+
+
+def calc_syncpoint(adj):
+    """Calculate a cross-pane adjustment synchronisation point
+
+    Our normal syncpoint is the middle of the screen. If the
+    current position is within the first half screen of a
+    document, we scale the sync point linearly back to 0.0 (top
+    of the screen); if it's the the last half screen, we again
+    scale linearly to 1.0.
+
+    The overall effect of this is to make sure that the top and
+    bottom parts of documents with different lengths and chunk
+    offsets correctly scroll into view.
+    """
+
+    current = adj.get_value()
+    half_a_screen = adj.get_page_size() / 2
+
+    syncpoint = 0.0
+    # How far through the first half-screen our adjustment is
+    top_val = adj.get_lower()
+    first_scale = (current - top_val) / half_a_screen
+    syncpoint += 0.5 * min(1, first_scale)
+    # How far through the last half-screen our adjustment is
+    bottom_val = adj.get_upper() - 1.5 * adj.get_page_size()
+    last_scale = (current - bottom_val) / half_a_screen
+    syncpoint += 0.5 * max(0, last_scale)
+    return syncpoint


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]