changeset 1060:03e38b44437a

RT-21435: Scaling UI Controls down to VGA: TextField & PasswordField -- Touch handles for caret and selection
author leifs
date Thu, 17 May 2012 08:40:48 -0700
parents 36b72fb1d022
children 254946092c0a
files javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextAreaBehavior.java javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextFieldBehavior.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextAreaSkin.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextInputControlSkin.java
diffstat 5 files changed, 191 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextAreaBehavior.java	Thu May 17 13:48:36 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextAreaBehavior.java	Thu May 17 08:40:48 2012 -0700
@@ -27,9 +27,12 @@
 
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
+import javafx.event.EventHandler;
+import javafx.scene.control.ContextMenu;
 import javafx.scene.control.TextArea;
 import javafx.scene.input.MouseButton;
 import javafx.scene.input.MouseEvent;
+import javafx.scene.input.TouchEvent;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -124,7 +127,7 @@
      * Constructors                                                           *
      *************************************************************************/
 
-    public TextAreaBehavior(TextArea textArea) {
+    public TextAreaBehavior(final TextArea textArea) {
         super(textArea);
 
         // Register for change events
@@ -144,6 +147,20 @@
             }
         });
 
+
+        if (textArea.getOnTouchStationary() == null) {
+            textArea.setOnTouchStationary(new EventHandler<TouchEvent>() {
+                @Override public void handle(TouchEvent event) {
+                    ContextMenu menu = textArea.getContextMenu();
+                    if (menu != null &&
+                        skin.showContextMenu(menu, event.getTouchPoint().getScreenX(),
+                                        event.getTouchPoint().getScreenY(), false)) {
+                        deferClick = false;
+                        event.consume();
+                    }
+                }
+            });
+        }
     }
 
     // An unholy back-reference!
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextFieldBehavior.java	Thu May 17 13:48:36 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextFieldBehavior.java	Thu May 17 08:40:48 2012 -0700
@@ -32,13 +32,16 @@
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
 import javafx.geometry.HorizontalDirection;
+import javafx.scene.control.ContextMenu;
 import javafx.scene.control.IndexRange;
 import javafx.scene.control.TextField;
 import javafx.scene.input.KeyEvent;
 import javafx.scene.input.MouseEvent;
+import javafx.scene.input.TouchEvent;
 import javafx.util.Duration;
 import java.util.List;
 
+import com.sun.javafx.PlatformUtil;
 import com.sun.javafx.scene.control.skin.TextFieldSkin;
 import com.sun.javafx.scene.text.HitInfo;
 
@@ -87,7 +90,7 @@
         }
     };
 
-    public TextFieldBehavior(TextField textField) {
+    public TextFieldBehavior(final TextField textField) {
         super(textField);
         // Initialize scroll timeline
         scrollSelectionTimeline.setCycleCount(Timeline.INDEFINITE);
@@ -102,6 +105,20 @@
                 handleFocusChange();
             }
         });
+
+        if (textField.getOnTouchStationary() == null) {
+            textField.setOnTouchStationary(new EventHandler<TouchEvent>() {
+                @Override public void handle(TouchEvent event) {
+                    ContextMenu menu = textField.getContextMenu();
+                    if (menu != null &&
+                        skin.showContextMenu(menu, event.getTouchPoint().getScreenX(),
+                                        event.getTouchPoint().getScreenY(), false)) {
+                        deferClick = false;
+                        event.consume();
+                    }
+                }
+            });
+        }
     }
 
     private void handleFocusChange() {
@@ -191,8 +208,9 @@
                 final int anchor = textField.getAnchor();
                 final int caretPosition = textField.getCaretPosition();
                 if (e.getClickCount() < 2 &&
-                        anchor != caretPosition &&
-                        ((i > anchor && i < caretPosition) || (i < anchor && i > caretPosition))) {
+                    (PlatformUtil.isEmbedded() ||
+                     (anchor != caretPosition &&
+                      ((i > anchor && i < caretPosition) || (i < anchor && i > caretPosition))))) {
                     // if there is a selection, then we will NOT handle the
                     // press now, but will defer until the release. If you
                     // select some text and then press down, we change the
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextAreaSkin.java	Thu May 17 13:48:36 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextAreaSkin.java	Thu May 17 08:40:48 2012 -0700
@@ -246,22 +246,13 @@
             if (PlatformUtil.isEmbedded()) {
                 // Install and resize the handles for caret and anchor.
                 if (selection.getLength() > 0) {
-                    contentView.getChildren().remove(caretHandle);
-                    if (!contentView.getChildren().contains(selectionHandle2)) {
-                        contentView.getChildren().addAll(selectionHandle1, selectionHandle2);
-                        selectionHandle1.resize(selectionHandle1.prefWidth(-1),
-                                                selectionHandle1.prefHeight(-1));
-                        selectionHandle2.resize(selectionHandle2.prefWidth(-1),
-                                                selectionHandle2.prefHeight(-1));
-                    }
+                    selectionHandle1.resize(selectionHandle1.prefWidth(-1),
+                                            selectionHandle1.prefHeight(-1));
+                    selectionHandle2.resize(selectionHandle2.prefWidth(-1),
+                                            selectionHandle2.prefHeight(-1));
                 } else {
-                    contentView.getChildren().remove(selectionHandle1);
-                    contentView.getChildren().remove(selectionHandle2);
-                    if (!contentView.getChildren().contains(caretHandle)) {
-                        contentView.getChildren().add(caretHandle);
-                        caretHandle.resize(caretHandle.prefWidth(-1),
-                                                caretHandle.prefHeight(-1));
-                    }
+                    caretHandle.resize(caretHandle.prefWidth(-1),
+                                       caretHandle.prefHeight(-1));
                 }
 
                 // Position the handle for the anchor. This could be handle1 or handle2.
@@ -413,6 +404,8 @@
 
     public static final int SCROLL_RATE = 30;
 
+    private double pressX, pressY; // For dragging handles on embedded
+
     public TextAreaSkin(final TextArea textArea) {
         super(textArea, new TextAreaBehavior(textArea));
         getBehavior().setTextAreaSkin(this);
@@ -461,6 +454,10 @@
         caretPath.visibleProperty().bind(caretVisible);
         contentView.getChildren().add(caretPath);
 
+        if (PlatformUtil.isEmbedded()) {
+            contentView.getChildren().addAll(caretHandle, selectionHandle1, selectionHandle2);
+        }
+
         scrollPane.hvalueProperty().addListener(new ChangeListener<Number>() {
             @Override
             public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
@@ -638,6 +635,8 @@
         if (textArea.isFocused()) setCaretAnimating(true);
 
         if (PlatformUtil.isEmbedded()) {
+            selectionHandle1.setRotate(180);
+
             EventHandler<MouseEvent> handlePressHandler = new EventHandler<MouseEvent>() {
                 @Override public void handle(MouseEvent e) {
                     pressX = e.getX();
@@ -684,7 +683,7 @@
                         // Swap caret and anchor
                         textArea.selectRange(textArea.getCaretPosition(), textArea.getAnchor());
                     }
-                    if (pos > 0) {
+                    if (pos >= 0) {
                         if (pos >= textArea.getAnchor()) {
                             pos = textArea.getAnchor();
                         }
@@ -733,8 +732,6 @@
         }
     }
 
-double pressX, pressY, pressSX, pressSY;
-
     private void createPromptNode() {
         if (promptNode == null && usePromptText.get()) {
             promptNode = new Text();
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Thu May 17 13:48:36 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Thu May 17 08:40:48 2012 -0700
@@ -41,6 +41,7 @@
 import javafx.beans.value.ObservableDoubleValue;
 import javafx.beans.value.ObservableIntegerValue;
 import javafx.beans.value.ObservableValue;
+import javafx.event.EventHandler;
 import javafx.geometry.Bounds;
 import javafx.geometry.Insets;
 import javafx.geometry.Point2D;
@@ -58,6 +59,7 @@
 import javafx.scene.text.Text;
 import java.util.List;
 
+import com.sun.javafx.PlatformUtil;
 import com.sun.javafx.Utils;
 import com.sun.javafx.scene.control.behavior.TextFieldBehavior;
 import com.sun.javafx.scene.text.HitInfo;
@@ -142,6 +144,8 @@
      */
     protected ObservableDoubleValue textRight;
 
+    private double pressX, pressY; // For dragging handles on embedded
+
     @Override public boolean showContextMenu(ContextMenu menu, double x, double y, boolean isKeyboardTrigger) {
         if (isKeyboardTrigger) {
             Bounds caretBounds = caretPath.getLayoutBounds();
@@ -244,6 +248,9 @@
         textGroup.setClip(clip);
         textGroup.getChildren().addAll(selectionHighlightPath, textNode, caretPath);
         getChildren().add(textGroup);
+        if (PlatformUtil.isEmbedded()) {
+            /*textGroup.*/getChildren().addAll(caretHandle, selectionHandle1, selectionHandle2);
+        }
 
         // Add text
         textNode.setManaged(false);
@@ -355,6 +362,77 @@
                 requestLayout();
             }
         });
+
+
+
+        if (PlatformUtil.isEmbedded()) {
+            EventHandler<MouseEvent> handlePressHandler = new EventHandler<MouseEvent>() {
+                @Override public void handle(MouseEvent e) {
+                    pressX = e.getX();
+                    pressY = e.getY();
+                    e.consume();
+                }
+            };
+
+            caretHandle.setOnMousePressed(handlePressHandler);
+            selectionHandle1.setOnMousePressed(handlePressHandler);
+            selectionHandle2.setOnMousePressed(handlePressHandler);
+
+            caretHandle.setOnMouseDragged(new EventHandler<MouseEvent>() {
+                @Override public void handle(MouseEvent e) {
+                    Point2D p = new Point2D(caretHandle.getLayoutX() + e.getX() + pressX - textNode.getLayoutX(),
+                                            caretHandle.getLayoutY() + e.getY() - pressY - 6);
+                    HitInfo hit = textNode.impl_hitTestChar(translateCaretPosition(p));
+                    int pos = hit.getCharIndex();
+                    positionCaret(hit, false);
+                    e.consume();
+                }
+            });
+
+            selectionHandle1.setOnMouseDragged(new EventHandler<MouseEvent>() {
+                @Override public void handle(MouseEvent e) {
+                    TextField textField = getSkinnable();
+                    Point2D tp = textNode.localToScene(0, 0);
+                    Point2D p = new Point2D(e.getSceneX() - tp.getX() + 10/*??*/ - pressX + selectionHandle1.getWidth() / 2,
+                                            e.getSceneY() - tp.getY() - pressY - 6);
+                    HitInfo hit = textNode.impl_hitTestChar(translateCaretPosition(p));
+                    int pos = hit.getCharIndex();
+                    if (textField.getAnchor() < textField.getCaretPosition()) {
+                        // Swap caret and anchor
+                        textField.selectRange(textField.getCaretPosition(), textField.getAnchor());
+                    }
+                    if (pos >= 0) {
+                        if (pos >= textField.getAnchor() - 1) {
+                            hit.setCharIndex(Math.max(0, textField.getAnchor() - 1));
+                        }
+                        positionCaret(hit, true);
+                    }
+                    e.consume();
+                }
+            });
+
+            selectionHandle2.setOnMouseDragged(new EventHandler<MouseEvent>() {
+                @Override public void handle(MouseEvent e) {
+                    TextField textField = getSkinnable();
+                    Point2D tp = textNode.localToScene(0, 0);
+                    Point2D p = new Point2D(e.getSceneX() - tp.getX() + 10/*??*/ - pressX + selectionHandle1.getWidth() / 2,
+                                            e.getSceneY() - tp.getY() - pressY - 6);
+                    HitInfo hit = textNode.impl_hitTestChar(translateCaretPosition(p));
+                    int pos = hit.getCharIndex();
+                    if (textField.getAnchor() > textField.getCaretPosition()) {
+                        // Swap caret and anchor
+                        textField.selectRange(textField.getCaretPosition(), textField.getAnchor());
+                    }
+                    if (pos > 0) {
+                        if (pos <= textField.getAnchor()) {
+                            hit.setCharIndex(Math.min(textField.getAnchor() + 1, textField.getLength()));
+                        }
+                        positionCaret(hit, true);
+                    }
+                    e.consume();
+                }
+            });
+        }
     }
 
     private void createPromptNode() {
@@ -391,6 +469,12 @@
         } else {
             selectionHighlightPath.getElements().setAll(elements);
         }
+
+        if (PlatformUtil.isEmbedded() && newValue != null && newValue.getLength() > 0) {
+            Bounds b = selectionHighlightPath.getBoundsInParent();
+            selectionHandle1.setLayoutX(b.getMinX() - selectionHandle1.getWidth() / 2);
+            selectionHandle2.setLayoutX(b.getMaxX() - selectionHandle2.getWidth() / 2);
+        }
     }
 
     @Override protected void handleControlPropertyChanged(String propertyReference) {
@@ -485,6 +569,9 @@
             textTranslateX.set(Math.min(textTranslateX.get() - delta,
                                         caretWidth / 2));
         }
+        if (PlatformUtil.isEmbedded()) {
+            caretHandle.setLayoutX(caretX - caretHandle.getWidth() / 2 + 1);
+        }
     }
 
     /**
@@ -668,5 +755,23 @@
                 promptNode.setY(textY);
             }
         }
+
+        if (PlatformUtil.isEmbedded()) {
+            TextField textField = getSkinnable();
+
+            // Resize handles for caret and anchor.
+            IndexRange selection = textField.getSelection();
+            selectionHandle1.resize(selectionHandle1.prefWidth(-1),
+                                    selectionHandle1.prefHeight(-1));
+            selectionHandle2.resize(selectionHandle2.prefWidth(-1),
+                                    selectionHandle2.prefHeight(-1));
+            caretHandle.resize(caretHandle.prefWidth(-1),
+                               caretHandle.prefHeight(-1));
+
+            Bounds b = caretPath.getBoundsInParent();
+            selectionHandle1.setLayoutY(b.getMaxY() - 3);
+            selectionHandle2.setLayoutY(b.getMaxY() - 3);
+            caretHandle.setLayoutY(b.getMaxY() - 3);
+        }
     }
 }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextInputControlSkin.java	Thu May 17 13:48:36 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextInputControlSkin.java	Thu May 17 08:40:48 2012 -0700
@@ -55,7 +55,6 @@
 import javafx.scene.input.InputMethodHighlight;
 import javafx.scene.input.InputMethodRequests;
 import javafx.scene.input.InputMethodTextRun;
-import javafx.scene.input.TouchEvent;
 import javafx.scene.layout.StackPane;
 import javafx.scene.paint.Color;
 import javafx.scene.paint.Paint;
@@ -294,16 +293,43 @@
         if (PlatformUtil.isEmbedded()) {
             caretHandle      = new StackPane();
             selectionHandle1 = new StackPane();
-            selectionHandle1.setRotate(180);
             selectionHandle2 = new StackPane();
 
+            caretHandle.setManaged(false);
+            selectionHandle1.setManaged(false);
+            selectionHandle2.setManaged(false);
+
             caretHandle.visibleProperty().bind(new BooleanBinding() {
+                { bind(textInput.focusedProperty(), textInput.anchorProperty(),
+                       textInput.caretPositionProperty(), textInput.disabledProperty(),
+                       textInput.editableProperty(), textInput.lengthProperty(), displayCaret);}
+                @Override protected boolean computeValue() {
+                    return (displayCaret.get() && textInput.isFocused() &&
+                            textInput.getCaretPosition() == textInput.getAnchor() &&
+                            !textInput.isDisabled() && textInput.isEditable() &&
+                            textInput.getLength() > 0);
+                }
+            });
+
+
+            selectionHandle1.visibleProperty().bind(new BooleanBinding() {
                 { bind(textInput.focusedProperty(), textInput.anchorProperty(), textInput.caretPositionProperty(),
-                       textInput.disabledProperty(), textInput.editableProperty(), displayCaret);}
+                       textInput.disabledProperty(), displayCaret);}
                 @Override protected boolean computeValue() {
-                return displayCaret.get() && textInput.isFocused() &&
-                        textInput.getCaretPosition() == textInput.getAnchor() &&
-                        !textInput.isDisabled() && textInput.isEditable();
+                    return (displayCaret.get() && textInput.isFocused() &&
+                            textInput.getCaretPosition() != textInput.getAnchor() &&
+                            !textInput.isDisabled());
+                }
+            });
+
+
+            selectionHandle2.visibleProperty().bind(new BooleanBinding() {
+                { bind(textInput.focusedProperty(), textInput.anchorProperty(), textInput.caretPositionProperty(),
+                       textInput.disabledProperty(), displayCaret);}
+                @Override protected boolean computeValue() {
+                    return (displayCaret.get() && textInput.isFocused() &&
+                            textInput.getCaretPosition() != textInput.getAnchor() &&
+                            !textInput.isDisabled());
                 }
             });
 
@@ -327,19 +353,6 @@
                     }
                 }
             });
-
-            if (textInput.getOnTouchStationary() == null) {
-                textInput.setOnTouchStationary(new EventHandler<TouchEvent>() {
-                    @Override public void handle(TouchEvent event) {
-                        ContextMenu menu = textInput.getContextMenu();
-                        if (menu != null &&
-                            showContextMenu(menu, event.getTouchPoint().getScreenX(),
-                                            event.getTouchPoint().getScreenY(), false)) {
-                            event.consume();
-                        }
-                    }
-                });
-            }
         }
 
         if (textInput.getContextMenu() == null) {