Update of /project/mcclim/cvsroot/mcclim/Drei In directory clnet:/tmp/cvs-serv16834/Drei
Modified Files: drei-redisplay.lisp views.lisp Log Message: Fixed redisplay issue where changes to the contents of strokes were sometimes not picked up correctly.
--- /project/mcclim/cvsroot/mcclim/Drei/drei-redisplay.lisp 2008/01/21 20:23:40 1.47 +++ /project/mcclim/cvsroot/mcclim/Drei/drei-redisplay.lisp 2008/01/22 15:21:07 1.48 @@ -330,6 +330,31 @@ (end-offset (stroke-end-offset stroke)))) (return stroke))))))
+(defun find-index-of-line-containing-offset (view offset) + "Return the index of the line containing `offset'. If `offset' +is before the displayed lines, return 0. If `offset' is after the +displayed lines, return the index of the last line." + (with-accessors ((lines displayed-lines)) view + (cond ((< offset (line-start-offset (aref lines 0))) + 0) + ((> offset (line-end-offset (last-displayed-line view))) + (1- (displayed-lines-count view))) + (t + ;; Binary search for the line. + (loop with low-index = 0 + with high-index = (displayed-lines-count view) + for middle = (floor (+ low-index high-index) 2) + for this-line = (aref lines middle) + for line-start = (line-start-offset this-line) + for line-end = (line-end-offset this-line) + do (cond ((<= line-start offset line-end) + (loop-finish)) + ((mark> offset line-start) + (setf low-index (1+ middle))) + ((mark< offset line-start) + (setf high-index middle))) + finally (return middle)))))) + (defun ensure-line-information-size (view min-size) "Ensure that the array of lines for `view' contains at least `min-size' elements." @@ -379,14 +404,24 @@ (let* ((stroke (line-stroke-information line (line-stroke-count line))) (old-start-offset (stroke-start-offset stroke)) (old-end-offset (stroke-end-offset stroke)) - (old-drawing-options (stroke-drawing-options stroke))) + (old-drawing-options (stroke-drawing-options stroke)) + (changed-region (first (changed-regions view)))) (prog1 (stroke-pump view stroke pump-state) (unless (and old-start-offset (= (+ old-start-offset line-change) (stroke-start-offset stroke)) (= (+ old-end-offset line-change) (stroke-end-offset stroke)) (drawing-options-equal old-drawing-options - (stroke-drawing-options stroke))) + (stroke-drawing-options stroke)) + (or (null changed-region) + (not (overlaps (stroke-start-offset stroke) (stroke-end-offset stroke) + (car changed-region) (cdr changed-region))))) (invalidate-stroke stroke :modified t)) + ;; Move to the next changed region, if it is not possible for + ;; more stroks to overlap with the current one. + (when (and changed-region + (>= (stroke-end-offset stroke) + (cdr changed-region))) + (pop (changed-regions view))) (incf (line-stroke-count line)) (setf (line-end-offset line) (stroke-end-offset stroke)))))
--- /project/mcclim/cvsroot/mcclim/Drei/views.lisp 2008/01/21 17:08:28 1.25 +++ /project/mcclim/cvsroot/mcclim/Drei/views.lisp 2008/01/22 15:21:07 1.26 @@ -552,7 +552,13 @@ :initform 0 :type number :documentation "The width of the longest -displayed line in device units.")) +displayed line in device units.") + (%changed-regions :accessor changed-regions + :initform nil + :documentation "A list of (start . end) conses +of buffer offsets, delimiting the regions of the buffer that have +changed since the last redisplay. The regions are not +overlapping, and are sorted in ascending order.")) (:metaclass modual-class) (:documentation "A view that contains a `drei-buffer' object. The buffer is displayed on a simple line-by-line basis, @@ -586,6 +592,47 @@ "Return true if `view' is a `drei-buffer-view'." (typep view 'drei-buffer-view))
+(defun overlaps (x1 x2 y1 y2) + "Return true if the x1/x2 region overlaps with y1/y2." + (or (<= x1 y1 x2) + (<= y1 x1 y2) + (<= y1 x1 x2 y2) + (<= x1 y1 y1 x2))) + +(defun remember-changed-region (view start end) + "Note that the buffer region delimited by the offset `start' +and `end' has been modified." + (labels ((worker (list) + ;; Return a new changed-regions list. Try to extend old + ;; regions instead of adding new ones. + (cond ((null list) + (list (cons start end))) + ;; If start/end overlaps with (first list), extend + ;; (first list) + ((overlaps start end (car (first list)) (cdr (first list))) + (setf (car (first list)) (min start (car (first list))) + (cdr (first list)) (max end (cdr (first list)))) + list) + ;; If start/end is wholly before (first list), push + ;; on a new region. + ((< start (car (first list))) + (setf (first list) + (cons (cons start end) (first list))) + list) + ;; If start/end is wholly before (first list), go + ;; further down list. If at end of list, add new + ;; element. + ((< (cdr (first list)) end) + (setf (rest list) (worker (rest list))) + list)))) + (setf (changed-regions view) (worker (changed-regions view))))) + +(defmethod observer-notified ((view drei-buffer-view) (buffer drei-buffer) + changed-region) + ;; If something has been redisplayed, and there have been changes to + ;; some of those lines, mark them as dirty. + (remember-changed-region view (car changed-region) (cdr changed-region))) + (defclass drei-syntax-view (drei-buffer-view) ((%syntax :accessor syntax :documentation "An instance of the syntax class used @@ -675,48 +722,49 @@ (modified-p view) t)) (call-next-method))
-(defmethod synchronize-view :around ((view drei-syntax-view) &key - force-p (begin 0) (end (size (buffer view)))) - (assert (>= end begin)) - ;; If nothing changed, then don't call the other methods. - (when (or (not (= (prefix-size view) (suffix-size view) - (buffer-size view) (size (buffer view)))) - force-p) - (call-next-method))) +(defun needs-resynchronization (view) + "Return true if the the view of the buffer of `view' is +potentially out of date. Return false otherwise." + (not (= (prefix-size view) (suffix-size view) + (buffer-size view) (size (buffer view)))))
(defmethod synchronize-view ((view drei-syntax-view) - &key (begin 0) (end (size (buffer view)))) + &key (begin 0) (end (size (buffer view))) + force-p) "Synchronize the syntax view with the underlying buffer. `Begin' and `end' are offsets specifying the region of the buffer that must be synchronised, defaulting to 0 and the size of the buffer respectively." - (let ((prefix-size (prefix-size view)) - (suffix-size (suffix-size view))) - ;; Set some minimum values here so if `update-syntax' calls - ;; `update-parse' itself, we won't end with infinite recursion. - (setf (prefix-size view) (max (if (> begin prefix-size) - prefix-size - end) - prefix-size) - (suffix-size view) (max (if (>= end (- (size (buffer view)) suffix-size)) - (max (- (size (buffer view)) begin) suffix-size) - suffix-size) - suffix-size) - (buffer-size view) (size (buffer view))) - (multiple-value-bind (parsed-start parsed-end) - (update-syntax (syntax view) prefix-size suffix-size begin end) - (assert (>= parsed-end parsed-start)) - ;; Now set the proper new values for prefix-size and - ;; suffix-size. - (setf (prefix-size view) (max (if (>= prefix-size parsed-start) - parsed-end - prefix-size) + (assert (>= end begin)) + ;; If nothing changed, then don't call the other methods. + (when (or (needs-resynchronization view) force-p) + (let ((prefix-size (prefix-size view)) + (suffix-size (suffix-size view))) + ;; Set some minimum values here so if `update-syntax' calls + ;; `update-parse' itself, we won't end with infinite recursion. + (setf (prefix-size view) (max (if (> begin prefix-size) + prefix-size + end) prefix-size) - (suffix-size view) (max (if (>= parsed-end (- (size (buffer view)) suffix-size)) - (- (size (buffer view)) parsed-start) + (suffix-size view) (max (if (>= end (- (size (buffer view)) suffix-size)) + (max (- (size (buffer view)) begin) suffix-size) suffix-size) - suffix-size))) - (call-next-method))) + suffix-size) + (buffer-size view) (size (buffer view))) + (multiple-value-bind (parsed-start parsed-end) + (update-syntax (syntax view) prefix-size suffix-size begin end) + (assert (>= parsed-end parsed-start)) + ;; Now set the proper new values for prefix-size and + ;; suffix-size. + (setf (prefix-size view) (max (if (>= prefix-size parsed-start) + parsed-end + prefix-size) + prefix-size) + (suffix-size view) (max (if (>= parsed-end (- (size (buffer view)) suffix-size)) + (- (size (buffer view)) parsed-start) + suffix-size) + suffix-size))))) + (call-next-method))
(defun make-syntax-for-view (view syntax-symbol &rest args) (apply #'make-instance syntax-symbol