Revision: 4368
          http://vexi.svn.sourceforge.net/vexi/?rev=4368&view=rev
Author:   clrg
Date:     2012-03-12 15:59:39 +0000 (Mon, 12 Mar 2012)
Log Message:
-----------
Improved cursor placement handling

Modified Paths:
--------------
    trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/edit.t

Modified: trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/edit.t
===================================================================
--- trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/edit.t       
2012-03-09 01:18:15 UTC (rev 4367)
+++ trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/edit.t       
2012-03-12 15:59:39 UTC (rev 4368)
@@ -655,77 +655,96 @@
                 // reset need to loop
                 updateCurPos = false;
                 
-                if (aWord and aInWord) {
-                    // place cursor at mouse position if it's over a word
-                    var tx = aX-aBlock.distanceto(aWord).x;
-                    var ci = static.getIndInWord(aWord, tx);
+                if (!aWord or !aInWord) while(true) {
+                    // using a while loop so we can "break" out
+                    // to avoid a more complex suite of if/else
                     
-                    if (ci == aWord.text.length and aBlock.numchildren > 
aBlock.indexof(aWord)+1) {
-                        // place cursor after word
-                        //aBlock = aBlock;
-                        aPos = 0;
-                        aWord = aBlock[aBlock.indexof(aWord)+1];
-                    
-                    } else {
-                        // place cursor in word
-                        //aBlock = aBlock;
-                        aPos = ci;
-                        //aWord = aWord;
-                    }
-                
-                } else while (true) {
                     // place cursor as close to the mouse position as possible
                     var d = thisbox.distanceto(aBlock);
                     var dY = d.y;
                     var dX = d.x;
                     
+                    // STAGE 1: find the correct block
+                    
+                    var aI = thisbox.indexof(aBlock);
+                    if (aI == -1) {
+                        // aBlock no longer part of this edit
+                        // -> probably an error
+                        throw "Invalid edit state";
+                        
+                    } else
+                    if (!multiline) {
+                        aBlock = thisbox[0];
+                    } else
                     if (dY > aY) {
-                        // mouse is above aBlock
-                        var i = thisbox.indexof(aBlock);
-                        for (i--; i >= 0; i--) {
-                            aBlock = thisbox[i];
-                            dY -= aBlock.height;
+                        // mouse is above aBlock;
+                        // this occurs when the user moves the mouse
+                        // outside of the edit but continues to hold
+                        // the button down
+                        // -> update ablock to correct block for the
+                        //    height of the mouse
+                        var i;
+                        for (i = aI; i > 0; i--) {
+                            dY -= thisbox[i].height;
                             if (aY > dY) break;
                         }
-                        if (i == -1) {
-                            aWord = aBlock[0];
-                            aPos = 0;
-                            break;
-                        }
+                        aBlock = thisbox[i];
                     
-                    } else if (aY > dY+aBlock.height) {
+                    } else
+                    if (aY > dY+aBlock.height) {
                         // mouse is below aBlock
-                        var n = thisbox.numchildren;
-                        dY += aBlock.height;
-                        var i = thisbox.indexof(aBlock);
-                        for (i++; n > i; i++) {
-                            aBlock = thisbox[i];
-                            dY += aBlock.height;
+                        // -> update ablock to correct block for the
+                        //    height of the mouse
+                        var i;
+                        for (i = aI; n-1 > i; i++) {
+                            dY += thisbox[i].height;
                             if (dY > aY) break;
                         }
-                        if (i == thisbox.numchildren) {
-                            aWord = aBlock.numchildren ? 
aBlock[aBlock.numchildren-1] : null;
-                            aPos = aWord ? aWord.text.length : 0;
-                            break;
-                        }
+                        aBlock = thisbox[i];
                     }
-                    // else working within the current block
+                    // else working within the vertical confines of
+                    // the current block; mouse to left or right of word
                     
+                    // STAGE 2: find the aligned word
+                    
                     if (aBlock.numchildren == 0) {
                         // empty block
                         aWord = null;
                         aPos = 0;
+                        break;
                     
                     } else {
-                        // block with children
+                        // STAGE 2a: find a word on the correct line
+                        
                         var ind1 = 0;
                         var ind2 = aBlock.numchildren-1;
                         var indm = 0;
+                        var lineY;
+                        var subY = aY - dY;
+                        var w1 = aBlock[ind1];
+                        var w2 = aBlock[ind2];
+                        var wm;
+                        
+                        if (!aBlock.multiline or w1.y+w1.height >= subY) {
+                            // use top line
+                            lineY = 0;
+                            wm = aBlock[0];
+                            
+                        } else
+                        if (aY >= w2.y) {
+                            // use bottom line
+                            lineY = w2.y;
+                            wm = aBlock[aBlock.numchildren-1];
+                            
+                        } else 
                         while (ind2 > ind1) {
+                            // locate the line
+                            
                             // the middle
                             indm = vexi.math.floor(ind1+(ind2-ind1)/2);
+                            wm = aBlock[indm];
                             
-                            if (aY > aBlock[indm].y+aBlock[indm].height) {
+                            if (aY > wm.y+wm.height) {
                                 // indm is on a line below mouse click
                                 if (ind1 == indm) {
                                     indm = ind2;
@@ -733,7 +752,7 @@
                                 ind1 = indm;
                                 continue;
                             }
-                            if (aBlock[indm].y > aY) {
+                            if (wm.y > aY) {
                                 // indm is on a line above mouse click
                                 if (ind2 == indm) {
                                     indm = ind1;
@@ -742,28 +761,50 @@
                                 continue;
                             }
                             // indm is on the same line that was clicked
+                            lineY = wm.y;
                             break;
                         }
-                        if (aX > dX) {
-                            // to the right of current line, find word at the 
end of the line
-                            var n = aBlock.numchildren;
-                            while (n > indm+1 and aBlock[indm].y == 
aBlock[indm+1].y) {
-                                indm++;
-                            }
-                            aWord = aBlock[indm];
-                            aPos = aWord ? aWord.text.length : 0;
                         
-                        } else {
-                            // to the left, find word at the start of the line
-                            while (indm-1 >= 0 and aBlock[indm].y == 
aBlock[indm-1].y) {
-                                indm--;
-                            }
-                            aWord = aBlock[indm];
-                            aPos = 0;
-                        }
+                        // STAGE 2b: we have the line and a starting point
+                        // (word) from which we can find the word that is
+                        // closest to the mouse cursor
+                        
+                        // go left
+                        for (var i = indm; i>=0 and wm.x > aX-dX; i--)
+                            wm = aBlock[i];
+                        
+                        // go right
+                        var n = aBlock.numchildren;
+                        for (var i = indm; n>i and aX-dX >= wm.x; i++)
+                            wm = aBlock[i];
+                
+                        aWord = wm;
                     }
                     break;
                 }
+                
+                if (aWord==null) {
+                    aPos = 0;
+                } else {
+                    // place cursor at mouse x position
+                    // relative to aWord
+                    var tx = aX-aBlock.distanceto(aWord).x;
+                    var ci = static.getIndInWord(aWord, tx);
+                    
+                    if (ci == aWord.text.length and aBlock.numchildren > 
aBlock.indexof(aWord)+1) {
+                        // place cursor after word
+                        //aBlock = aBlock;
+                        aPos = 0;
+                        aWord = aBlock[aBlock.indexof(aWord)+1];
+                    
+                    } else {
+                        // place cursor in word
+                        //aBlock = aBlock;
+                        aPos = ci;
+                        //aWord = aWord;
+                    }
+                }
+                    
                 // FEATURE: syncCursor should probably happen post-highlight ?
                 if (abortTip) {
                     abortTip = false;
@@ -805,6 +846,7 @@
             
             // clean up; thread no longer in progress
             doHighlight = false;
+            frameToThis = null;
             tip = false;
         }
         

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Try before you buy = See our experts in action!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-dev2
_______________________________________________
Vexi-svn mailing list
Vexi-svn@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/vexi-svn

Reply via email to