#BUGFIX by exept
authorClaus Gittinger <cg@exept.de>
Sun, 15 Sep 2019 18:29:12 +0200
changeset 6704 0b9dff1f67d0
parent 6703 ebc60a121fea
child 6705 efea30a3e8e0
#BUGFIX by exept class: EditTextViewCompletionSupport code completion view position fixes; do not eat tab key added: #adjustSizeOfCompletionView: changed: #closeCompletionView #computeAndShowCompletions #handleKeyPress:x:y: #openCompletionView: #postKeyPress: #startCompletionProcess
EditTextViewCompletionSupport.st
--- a/EditTextViewCompletionSupport.st	Sun Sep 15 15:09:07 2019 +0200
+++ b/EditTextViewCompletionSupport.st	Sun Sep 15 18:29:12 2019 +0200
@@ -80,17 +80,19 @@
 handleKeyPress:key x:x y:y
     "return true, if I have eaten this keypress"
 
-    |ch eatCursorLeftOrRight eatCursorUpDown|
+    |ch eatCursorLeftOrRight eatCursorUpDown sensor|
 
     "/ completeImmediate := UserPreferences current immediateCodeCompletion.
 
+    sensor := editView sensor.
+    
     "/ open on CTRL- or TAB-key?
     (completionView notNil and:[completionView realized]) ifFalse:[
         editView hasSelection ifFalse:[
             ch := editView characterBeforeCursor.
 
             (ch notNil "/ i.e. not at begin of line
-              and:[ ch isLetterOrDigitOrUnderline ]
+              and:[ ch isLetterOrDigitOrUnderline or:[ch == Character space]]
             ) ifTrue:[
                 (key == #Control_L or:[ key == #Ctrl or:[ key == #Control_R or:[ key == #Control]]]) ifTrue:[
                     UserPreferences current codeCompletionOnControlKey ifTrue:[
@@ -98,14 +100,14 @@
                         self updateCompletionList
                     ]
                 ].
-                ((key == #Tab) and:[editView sensor shiftDown not]) ifTrue:[
+                ((key == #Tab) and:[sensor shiftDown not]) ifTrue:[
                     UserPreferences current codeCompletionOnTabKey ifTrue:[
                         "/ only if the character after the cursor is a separator!!
                         "/ otherwise, we cannot insert tabs 
                         ((ch := editView characterAfterCursor) isNil or:[ch isSeparator]) ifTrue:[
                             autoSelect := true.
                             self updateCompletionList.
-                            ^ true
+                            "/ ^ true
                         ].
                     ].
                 ]
@@ -114,6 +116,9 @@
         ^ false.
     ].
 
+    "/ the completion view is already open
+    "/ determine, if the key should be forwarded to it (cursor keys)
+
     editView cursorCol <= 1 ifTrue:[^ false].
     
     "/ key for completion view ? (careful: do not forward too many, it would disturb user's typing)
@@ -123,13 +128,13 @@
             "/never
             eatCursorLeftOrRight := false.
 "/                                    completeImmediate not
-"/                                    or:[ editView sensor shiftDown 
-"/                                    or:[ editView sensor ctrlDown ]].
+"/                                    or:[ sensor shiftDown 
+"/                                    or:[ sensor ctrlDown ]].
             "/ only with shift or ctrl
             eatCursorUpDown := 
                     (UserPreferences current codeCompletionViewKeyboardNavigationNeedsModifier not)
-                    or:[ editView sensor shiftDown 
-                    or:[ editView sensor ctrlDown]].
+                    or:[ sensor shiftDown 
+                    or:[ sensor ctrlDown]].
 
             ((key == #CursorDown and:[eatCursorUpDown])
                 or:[ (key == #CursorUp and:[eatCursorUpDown])
@@ -138,7 +143,7 @@
                 or:[ ((key == #Return) and:[ completionView hasSelection ])
             ]]]]) ifTrue:[
                 "/ forward to completion view
-                completionView sensor pushUserEvent:#value for:[ completionView keyPress:key x:0 y:0 ].
+                completionView sensor pushAction:[ completionView keyPress:key x:0 y:0 ].
                 ^ true.
             ].
 
@@ -182,9 +187,12 @@
     "/ (completionView notNil and:[completionView realized]) ifTrue:[^ self].
     editView hasSelection ifTrue:[^ self].
 
+false ifTrue:[
     ch := editView characterBeforeCursor.
-    (ch notNil and:[ch isLetterOrDigitOrUnderline]) ifFalse:[^ self].
-
+    (ch notNil and:[ch isLetterOrDigitOrUnderline]) ifFalse:[
+        ^ self
+    ].
+].
     (key == #BackSpace or:[key == #BasicBackspace]) ifTrue:[
         autoSelect := false.
         self updateCompletionList.
@@ -227,12 +235,21 @@
 !EditTextViewCompletionSupport methodsFor:'private'!
 
 computeAndShowCompletions
-    "compute completions, then push an event to show them"
+    "compute completions, then push an event to show them.
+     Notice: this is interrupted and terminated if the user presses another key
+     within delayTime"
     
-    |completions|
+    |delayTime completions startTime restTime|
 
+    delayTime := 0.4 seconds.
+
+    startTime := Timestamp now.
     completions := self computeCompletions.
     completions notEmptyOrNil ifTrue:[
+        restTime := (startTime + delayTime) - Timestamp now.
+        restTime positive ifTrue:[
+            Delay waitFor:restTime
+        ].
         self assert:completions isArray.
         self assert:completions size == 4.
         editView sensor
@@ -283,14 +300,11 @@
         ^ self
     ].
 
-    completionView isNil ifTrue:[
-        initialList := #( 'Busy...' ).
-        "/ 'op1' printCR.
-    ] ifFalse:[
-        initialList := completionView list.
-        "/ 'op2' printCR.
+    initialList := #( 'Busy...' ).
+    completionView notNil ifTrue:[
+"/        initialList := completionView list.
     ].
-    self openCompletionView:initialList.
+    "/ self openCompletionView:initialList.
 
     completionProcess := p := 
         [
@@ -302,13 +316,14 @@
                     ].
                 ] do:[ 
                     |startTime|
-                    
+
+false ifTrue:[
                     startTime := Timestamp now.
                     "/ Wait a while to give user chance finish typing.
                     "/ This also reduces CPU consumption by avoiding
                     "/ useless computation
                     Delay waitForMilliseconds: 200.
-
+].
                     (editView topView isDebugView) ifTrue:[
                         ControlInterrupt ignoreIn:[
                             self computeAndShowCompletions.
@@ -353,6 +368,62 @@
 
 !EditTextViewCompletionSupport methodsFor:'private-API'!
 
+adjustSizeOfCompletionView:topView
+    |screenBounds screenBoundsCorner 
+     helpViewsExtent helpViewsWidth helpViewsHeight
+     textCursorPosInTextView textCursorPosOnScreen 
+     newX newY cursorX cursorY distanceFromCursorIfBelow distanceFromCursorIfAbove |
+
+    textCursorPosInTextView := editView xOfCursor @ editView yOfCursor.
+    textCursorPosOnScreen := editView device 
+                    translatePoint:textCursorPosInTextView 
+                    fromView:editView toView:nil.
+
+    cursorX := textCursorPosOnScreen x.
+    cursorY := textCursorPosOnScreen y.
+    distanceFromCursorIfAbove := editView font height.
+    distanceFromCursorIfBelow := distanceFromCursorIfAbove * 2.
+
+    topView resizeToFit.
+
+    "/ make sure, the window is visible
+    screenBounds := topView device monitorBoundsAt:topView origin.
+    screenBoundsCorner := screenBounds corner.
+
+    helpViewsExtent := topView extent.
+    helpViewsWidth := helpViewsExtent x.
+    helpViewsHeight := helpViewsExtent y.
+
+
+    newX := cursorX + 20.
+    newY := cursorY + distanceFromCursorIfBelow.
+
+    "/ if it does not lie completely inside the screen, move it     
+    (newX + helpViewsWidth) > screenBoundsCorner x ifTrue:[
+        newX := screenBoundsCorner x - helpViewsWidth.
+    ].
+    (newY + helpViewsHeight) > screenBoundsCorner y ifTrue:[
+        newY := screenBoundsCorner y - helpViewsHeight.
+    ].
+    newX < 0 ifTrue:[
+        newX := 0
+    ].    
+    newY < 0 ifTrue:[
+        newY := 0
+    ].
+
+    "/ topView origin:(newX @ newY).
+    (cursorY between:newY and:(newY + helpViewsHeight)) ifTrue:[
+        "/ lift it towards the top
+        newY := cursorY - distanceFromCursorIfAbove - helpViewsHeight.
+    ] ifFalse:[
+        "/ (cursorX between:newX and:(newX + helpViewsWidth)) ifTrue:[
+        "/     self halt.
+        "/ ].
+    ].
+    topView origin:(newX @ newY).
+!
+
 closeCompletionView
     |v|
 
@@ -360,9 +431,7 @@
         completionView := nil.
 
         "/ let it close itself - avoids synchronization problems
-        v sensor
-            pushUserEvent:#value
-            for:[ v topView destroy ]
+        v sensor pushAction:[ v topView destroy ]
     ].
 
     "Modified (format): / 14-09-2018 / 22:08:05 / Claus Gittinger"
@@ -380,9 +449,7 @@
 openCompletionView: list
     "Makes sure the completion view is opened and with given `list`."
     
-    | textCursorPosInTextView textCursorPosOnScreen movePos topView 
-      screenBounds screenBoundsCorner 
-      helpViewsExtent helpViewsWidth helpViewsHeight|
+    | textCursorPosInTextView textCursorPosOnScreen movePos topView|
 
     "/ move the window away from the text cursor (to not cover what user types in)
     "/ get the screen-relative position of the text cursor
@@ -407,7 +474,8 @@
         completionView enable:false.
         completionView extent:completionView preferredExtentForContents.
         "/ completionView font: editView font.
-        topView := CodeCompletionHelpView with:completionView.
+        topView := CodeCompletionHelpView with:(HVScrollableView forView:completionView).
+        "/ topView := CodeCompletionHelpView with:completionView.
         topView editView:editView.
     ] ifFalse:[
         completionView list:list.
@@ -415,27 +483,7 @@
     ].
     
     topView ~~ completionView ifTrue:[
-        topView resizeToFit.
-
-        "/ make sure, the window is visible
-        screenBounds := topView device monitorBoundsAt:topView origin.
-        screenBoundsCorner := screenBounds corner.
-
-        helpViewsExtent := topView extent.
-        helpViewsWidth := helpViewsExtent x.
-        helpViewsHeight := helpViewsExtent y.
-
-        "/ if it does not lie completely inside the screen, move it     
-        (movePos x + helpViewsWidth) > screenBoundsCorner x ifTrue:[
-            movePos := (textCursorPosOnScreen x - 60 - helpViewsWidth) @ movePos y.
-        ].
-        (movePos y + helpViewsHeight) > screenBoundsCorner y ifTrue:[
-            movePos := movePos x @ (textCursorPosOnScreen y - helpViewsHeight).
-        ].
-        movePos y < 0 ifTrue:[
-            movePos := movePos x @ 0
-        ].    
-        topView origin:movePos.
+        self adjustSizeOfCompletionView:topView.
     ].
 
     "Created: / 26-09-2013 / 17:07:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"