modules/javafx.controls/src/main/java/javafx/scene/control/skin/ScrollPaneSkin.java

Print this page




 183             }
 184         }
 185     };
 186 
 187 
 188     /*
 189     ** The content of the ScrollPane has just changed bounds, check scrollBar positions.
 190     */
 191     private final ChangeListener<Bounds> boundsChangeListener = new ChangeListener<Bounds>() {
 192         @Override public void changed(ObservableValue<? extends Bounds> observable, Bounds oldBounds, Bounds newBounds) {
 193 
 194             /*
 195             ** For a height change then we want to reduce
 196             ** viewport vertical jumping as much as possible.
 197             ** We set a new vsb value to try to keep the same
 198             ** content position at the top of the viewport
 199             */
 200             double oldHeight = oldBounds.getHeight();
 201             double newHeight = newBounds.getHeight();
 202             if (oldHeight > 0 && oldHeight != newHeight) {
 203                 double oldPositionY = (snapPosition(snappedTopInset() - posY / (vsb.getMax() - vsb.getMin()) * (oldHeight - contentHeight)));
 204                 double newPositionY = (snapPosition(snappedTopInset() - posY / (vsb.getMax() - vsb.getMin()) * (newHeight - contentHeight)));
 205 
 206                 double newValueY = (oldPositionY/newPositionY)*vsb.getValue();
 207                 if (newValueY < 0.0) {
 208                     vsb.setValue(0.0);
 209                 }
 210                 else if (newValueY < 1.0) {
 211                     vsb.setValue(newValueY);
 212                 }
 213                 else if (newValueY > 1.0) {
 214                     vsb.setValue(1.0);
 215                 }
 216             }
 217 
 218             /*
 219             ** For a width change then we want to reduce
 220             ** viewport horizontal jumping as much as possible.
 221             ** We set a new hsb value to try to keep the same
 222             ** content position to the left of the viewport
 223             */
 224             double oldWidth = oldBounds.getWidth();
 225             double newWidth = newBounds.getWidth();
 226             if (oldWidth > 0 && oldWidth != newWidth) {
 227                 double oldPositionX = (snapPosition(snappedLeftInset() - posX / (hsb.getMax() - hsb.getMin()) * (oldWidth - contentWidth)));
 228                 double newPositionX = (snapPosition(snappedLeftInset() - posX / (hsb.getMax() - hsb.getMin()) * (newWidth - contentWidth)));
 229 
 230                 double newValueX = (oldPositionX/newPositionX)*hsb.getValue();
 231                 if (newValueX < 0.0) {
 232                     hsb.setValue(0.0);
 233                 }
 234                 else if (newValueX < 1.0) {
 235                     hsb.setValue(newValueX);
 236                 }
 237                 else if (newValueX > 1.0) {
 238                     hsb.setValue(1.0);
 239                 }
 240             }
 241         }
 242     };
 243 
 244 
 245 
 246     /***************************************************************************
 247      *                                                                         *
 248      * Constructors                                                            *


 262         // install default input map for the ScrollPane control
 263         behavior = new ScrollPaneBehavior(control);
 264 //        control.setInputMap(behavior.getInputMap());
 265 
 266         initialize();
 267 
 268         // Register listeners
 269         Consumer<ObservableValue<?>> viewportSizeHintConsumer = e -> {
 270             // change affects pref size, so requestLayout on control
 271             getSkinnable().requestLayout();
 272         };
 273         registerChangeListener(control.contentProperty(), e -> {
 274             if (scrollNode != getSkinnable().getContent()) {
 275                 if (scrollNode != null) {
 276                     scrollNode.layoutBoundsProperty().removeListener(nodeListener);
 277                     scrollNode.layoutBoundsProperty().removeListener(boundsChangeListener);
 278                     viewContent.getChildren().remove(scrollNode);
 279                 }
 280                 scrollNode = getSkinnable().getContent();
 281                 if (scrollNode != null) {
 282                     nodeWidth = snapSize(scrollNode.getLayoutBounds().getWidth());
 283                     nodeHeight = snapSize(scrollNode.getLayoutBounds().getHeight());
 284                     viewContent.getChildren().setAll(scrollNode);
 285                     scrollNode.layoutBoundsProperty().addListener(nodeListener);
 286                     scrollNode.layoutBoundsProperty().addListener(boundsChangeListener);
 287                 }
 288             }
 289             getSkinnable().requestLayout();
 290         });
 291         registerChangeListener(control.fitToWidthProperty(), e -> {
 292             getSkinnable().requestLayout();
 293             viewRect.requestLayout();
 294         });
 295         registerChangeListener(control.fitToHeightProperty(), e -> {
 296             getSkinnable().requestLayout();
 297             viewRect.requestLayout();
 298         });
 299         registerChangeListener(control.hbarPolicyProperty(), e -> {
 300             // change might affect pref size, so requestLayout on control
 301             getSkinnable().requestLayout();
 302         });
 303         registerChangeListener(control.vbarPolicyProperty(), e -> {


 461 
 462     /** {@inheritDoc} */
 463     @Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
 464         final ScrollPane sp = getSkinnable();
 465 
 466         double hsbHeight = computeHsbSizeHint(sp);
 467         double minHeight = hsbHeight + snappedTopInset() + snappedBottomInset();
 468 
 469         if (sp.getMinViewportHeight() > 0) {
 470             return (sp.getMinViewportHeight() + minHeight);
 471         } else {
 472             double h = corner.minHeight(-1);
 473             return (h > 0) ? (3 * h) : (DEFAULT_MIN_SIZE);
 474         }
 475     }
 476 
 477     @Override protected void layoutChildren(final double x, final double y,
 478                                             final double w, final double h) {
 479         final ScrollPane control = getSkinnable();
 480         final Insets padding = control.getPadding();
 481         final double rightPadding = snapSize(padding.getRight());
 482         final double leftPadding = snapSize(padding.getLeft());
 483         final double topPadding = snapSize(padding.getTop());
 484         final double bottomPadding = snapSize(padding.getBottom());
 485 
 486         vsb.setMin(control.getVmin());
 487         vsb.setMax(control.getVmax());
 488 
 489         //should only do this on css setup
 490         hsb.setMin(control.getHmin());
 491         hsb.setMax(control.getHmax());
 492 
 493         contentWidth = w;
 494         contentHeight = h;
 495 
 496         /*
 497         ** we want the scrollbars to go right to the border
 498         */
 499         double hsbWidth = 0;
 500         double vsbHeight = 0;
 501 
 502         computeScrollNodeSize(contentWidth, contentHeight);
 503         computeScrollBarSize();
 504 


 569 
 570         hsb.setVisible(hsbvis);
 571         if (hsbvis) {
 572             /*
 573             ** round up position of ScrollBar, round down it's size.
 574             **
 575             ** Positioning the ScrollBar
 576             **  The Padding should go between the content and the edge,
 577             **  otherwise changes in padding move the ScrollBar, and could
 578             **  in extreme cases size the ScrollBar to become unusable.
 579             **  The -1, +1 plus one bit :
 580             **   If padding in => 1 then we allow one pixel to appear as the
 581             **   outside border of the Scrollbar, and the rest on the inside.
 582             **   If padding is < 1 then we just stick to the edge.
 583             */
 584             hsb.resizeRelocate(cx, snappedTopInset() + h - hsbHeight + (bottomPadding < 1 ? 0 : bottomPadding - 1),
 585                     hsbWidth, hsbHeight);
 586         }
 587         updateHorizontalSB();
 588 
 589         viewRect.resizeRelocate(snappedLeftInset(), snappedTopInset(), snapSize(contentWidth), snapSize(contentHeight));
 590         resetClip();
 591 
 592         if (vsbvis && hsbvis) {
 593             corner.setVisible(true);
 594             double cornerWidth = vsbWidth;
 595             double cornerHeight = hsbHeight;
 596             corner.resizeRelocate(snapPosition(vsb.getLayoutX()), snapPosition(hsb.getLayoutY()), snapSize(cornerWidth), snapSize(cornerHeight));
 597         } else {
 598             corner.setVisible(false);
 599         }
 600         control.setViewportBounds(new BoundingBox(snapPosition(viewContent.getLayoutX()), snapPosition(viewContent.getLayoutY()), snapSize(contentWidth), snapSize(contentHeight)));
 601     }
 602 
 603     /** {@inheritDoc} */
 604     @Override protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
 605         switch (attribute) {
 606             case VERTICAL_SCROLLBAR: return vsb;
 607             case HORIZONTAL_SCROLLBAR: return hsb;
 608             default: return super.queryAccessibleAttribute(attribute, parameters);
 609         }
 610     }
 611 
 612 
 613 
 614     /***************************************************************************
 615      *                                                                         *
 616      * Private implementation                                                  *
 617      *                                                                         *
 618      **************************************************************************/
 619 
 620     private void initialize() {


1022                 : 0;
1023     }
1024 
1025     /**
1026      * Computes the size that should be reserved for vertical scrollbar in size hints (min/pref width)
1027      */
1028     private double computeVsbSizeHint(ScrollPane sp) {
1029         return ((sp.getVbarPolicy() == ScrollBarPolicy.ALWAYS) ||
1030                 (sp.getVbarPolicy() == ScrollBarPolicy.AS_NEEDED && (sp.getPrefViewportWidth() > 0
1031                         || sp.getMinViewportWidth() > 0)))
1032                 ? vsb.prefWidth(ScrollBar.USE_COMPUTED_SIZE)
1033                 : 0;
1034     }
1035 
1036     private void computeScrollNodeSize(double contentWidth, double contentHeight) {
1037         if (scrollNode != null) {
1038             if (scrollNode.isResizable()) {
1039                 ScrollPane control = getSkinnable();
1040                 Orientation bias = scrollNode.getContentBias();
1041                 if (bias == null) {
1042                     nodeWidth = snapSize(boundedSize(control.isFitToWidth()? contentWidth : scrollNode.prefWidth(-1),
1043                                                          scrollNode.minWidth(-1),scrollNode.maxWidth(-1)));
1044                     nodeHeight = snapSize(boundedSize(control.isFitToHeight()? contentHeight : scrollNode.prefHeight(-1),
1045                                                           scrollNode.minHeight(-1), scrollNode.maxHeight(-1)));
1046 
1047                 } else if (bias == Orientation.HORIZONTAL) {
1048                     nodeWidth = snapSize(boundedSize(control.isFitToWidth()? contentWidth : scrollNode.prefWidth(-1),
1049                                                          scrollNode.minWidth(-1),scrollNode.maxWidth(-1)));
1050                     nodeHeight = snapSize(boundedSize(control.isFitToHeight()? contentHeight : scrollNode.prefHeight(nodeWidth),
1051                                                           scrollNode.minHeight(nodeWidth),scrollNode.maxHeight(nodeWidth)));
1052 
1053                 } else { // bias == VERTICAL
1054                     nodeHeight = snapSize(boundedSize(control.isFitToHeight()? contentHeight : scrollNode.prefHeight(-1),
1055                                                           scrollNode.minHeight(-1), scrollNode.maxHeight(-1)));
1056                     nodeWidth = snapSize(boundedSize(control.isFitToWidth()? contentWidth : scrollNode.prefWidth(nodeHeight),
1057                                                          scrollNode.minWidth(nodeHeight),scrollNode.maxWidth(nodeHeight)));
1058                 }
1059 
1060             } else {
1061                 nodeWidth = snapSize(scrollNode.getLayoutBounds().getWidth());
1062                 nodeHeight = snapSize(scrollNode.getLayoutBounds().getHeight());
1063             }
1064             nodeSizeInvalid = false;
1065         }
1066     }
1067 
1068     private boolean isReverseNodeOrientation() {
1069         return (scrollNode != null &&
1070                 getSkinnable().getEffectiveNodeOrientation() !=
1071                             scrollNode.getEffectiveNodeOrientation());
1072     }
1073 
1074     private boolean determineHorizontalSBVisible() {
1075         final ScrollPane sp = getSkinnable();
1076 
1077         if (Properties.IS_TOUCH_SUPPORTED) {
1078             return (tempVisibility && (nodeWidth > contentWidth));
1079         }
1080         else {
1081             // RT-17395: ScrollBarPolicy might be null. If so, treat it as "AS_NEEDED", which is the default
1082             ScrollBarPolicy hbarPolicy = sp.getHbarPolicy();


1087         }
1088     }
1089 
1090     private boolean determineVerticalSBVisible() {
1091         final ScrollPane sp = getSkinnable();
1092 
1093         if (Properties.IS_TOUCH_SUPPORTED) {
1094             return (tempVisibility && (nodeHeight > contentHeight));
1095         }
1096         else {
1097             // RT-17395: ScrollBarPolicy might be null. If so, treat it as "AS_NEEDED", which is the default
1098             ScrollBarPolicy vbarPolicy = sp.getVbarPolicy();
1099             return (ScrollBarPolicy.NEVER == vbarPolicy) ? false :
1100                    ((ScrollBarPolicy.ALWAYS == vbarPolicy) ? true :
1101                    ((sp.isFitToHeight() && scrollNode != null ? scrollNode.isResizable() : false) ?
1102                    (nodeHeight > contentHeight && scrollNode.minHeight(-1) > contentHeight) : (nodeHeight > contentHeight)));
1103         }
1104     }
1105 
1106     private void computeScrollBarSize() {
1107         vsbWidth = snapSize(vsb.prefWidth(-1));
1108         if (vsbWidth == 0) {
1109             //            println("*** WARNING ScrollPaneSkin: can't get scroll bar width, using {DEFAULT_SB_BREADTH}");
1110             if (Properties.IS_TOUCH_SUPPORTED) {
1111                 vsbWidth = DEFAULT_EMBEDDED_SB_BREADTH;
1112             }
1113             else {
1114                 vsbWidth = DEFAULT_SB_BREADTH;
1115             }
1116         }
1117         hsbHeight = snapSize(hsb.prefHeight(-1));
1118         if (hsbHeight == 0) {
1119             //            println("*** WARNING ScrollPaneSkin: can't get scroll bar height, using {DEFAULT_SB_BREADTH}");
1120             if (Properties.IS_TOUCH_SUPPORTED) {
1121                 hsbHeight = DEFAULT_EMBEDDED_SB_BREADTH;
1122             }
1123             else {
1124                 hsbHeight = DEFAULT_SB_BREADTH;
1125             }
1126         }
1127     }
1128 
1129     private void updateHorizontalSB() {
1130         double contentRatio = nodeWidth * (hsb.getMax() - hsb.getMin());
1131         if (contentRatio > 0.0) {
1132             hsb.setVisibleAmount(contentWidth / contentRatio);
1133             hsb.setBlockIncrement(0.9 * hsb.getVisibleAmount());
1134             hsb.setUnitIncrement(0.1 * hsb.getVisibleAmount());
1135         }
1136         else {
1137             hsb.setVisibleAmount(0.0);


1161             vsb.setVisibleAmount(0.0);
1162             vsb.setBlockIncrement(0.0);
1163             vsb.setUnitIncrement(0.0);
1164         }
1165 
1166         if (vsb.isVisible()) {
1167             updatePosY();
1168         } else {
1169             if (nodeHeight > contentHeight) {
1170                 updatePosY();
1171             } else {
1172                 viewContent.setLayoutY(0);
1173             }
1174         }
1175     }
1176 
1177     private double updatePosX() {
1178         final ScrollPane sp = getSkinnable();
1179         double x = isReverseNodeOrientation() ? (hsb.getMax() - (posX - hsb.getMin())) : posX;
1180         double minX = Math.min((- x / (hsb.getMax() - hsb.getMin()) * (nodeWidth - contentWidth)), 0);
1181         viewContent.setLayoutX(snapPosition(minX));
1182         if (!sp.hvalueProperty().isBound()) sp.setHvalue(Utils.clamp(sp.getHmin(), posX, sp.getHmax()));
1183         return posX;
1184     }
1185 
1186     private double updatePosY() {
1187         final ScrollPane sp = getSkinnable();
1188         double minY = Math.min((- posY / (vsb.getMax() - vsb.getMin()) * (nodeHeight - contentHeight)), 0);
1189         viewContent.setLayoutY(snapPosition(minY));
1190         if (!sp.vvalueProperty().isBound()) sp.setVvalue(Utils.clamp(sp.getVmin(), posY, sp.getVmax()));
1191         return posY;
1192     }
1193 
1194     private void resetClip() {
1195         clipRect.setWidth(snapSize(contentWidth));
1196         clipRect.setHeight(snapSize(contentHeight));
1197     }
1198 
1199     private void startSBReleasedAnimation() {
1200         if (sbTouchTimeline == null) {
1201             /*
1202             ** timeline to leave the scrollbars visible for a short
1203             ** while after a scroll/drag
1204             */
1205             sbTouchTimeline = new Timeline();
1206             sbTouchKF1 = new KeyFrame(Duration.millis(0), event -> {
1207                 tempVisibility = true;
1208                 if (touchDetected == true || mouseDown == true) {
1209                     sbTouchTimeline.playFromStart();
1210                 }
1211             });
1212 
1213             sbTouchKF2 = new KeyFrame(Duration.millis(1000), event -> {
1214                 tempVisibility = false;
1215                 getSkinnable().requestLayout();
1216             });




 183             }
 184         }
 185     };
 186 
 187 
 188     /*
 189     ** The content of the ScrollPane has just changed bounds, check scrollBar positions.
 190     */
 191     private final ChangeListener<Bounds> boundsChangeListener = new ChangeListener<Bounds>() {
 192         @Override public void changed(ObservableValue<? extends Bounds> observable, Bounds oldBounds, Bounds newBounds) {
 193 
 194             /*
 195             ** For a height change then we want to reduce
 196             ** viewport vertical jumping as much as possible.
 197             ** We set a new vsb value to try to keep the same
 198             ** content position at the top of the viewport
 199             */
 200             double oldHeight = oldBounds.getHeight();
 201             double newHeight = newBounds.getHeight();
 202             if (oldHeight > 0 && oldHeight != newHeight) {
 203                 double oldPositionY = (snapPositionY(snappedTopInset() - posY / (vsb.getMax() - vsb.getMin()) * (oldHeight - contentHeight)));
 204                 double newPositionY = (snapPositionY(snappedTopInset() - posY / (vsb.getMax() - vsb.getMin()) * (newHeight - contentHeight)));
 205 
 206                 double newValueY = (oldPositionY/newPositionY)*vsb.getValue();
 207                 if (newValueY < 0.0) {
 208                     vsb.setValue(0.0);
 209                 }
 210                 else if (newValueY < 1.0) {
 211                     vsb.setValue(newValueY);
 212                 }
 213                 else if (newValueY > 1.0) {
 214                     vsb.setValue(1.0);
 215                 }
 216             }
 217 
 218             /*
 219             ** For a width change then we want to reduce
 220             ** viewport horizontal jumping as much as possible.
 221             ** We set a new hsb value to try to keep the same
 222             ** content position to the left of the viewport
 223             */
 224             double oldWidth = oldBounds.getWidth();
 225             double newWidth = newBounds.getWidth();
 226             if (oldWidth > 0 && oldWidth != newWidth) {
 227                 double oldPositionX = (snapPositionX(snappedLeftInset() - posX / (hsb.getMax() - hsb.getMin()) * (oldWidth - contentWidth)));
 228                 double newPositionX = (snapPositionX(snappedLeftInset() - posX / (hsb.getMax() - hsb.getMin()) * (newWidth - contentWidth)));
 229 
 230                 double newValueX = (oldPositionX/newPositionX)*hsb.getValue();
 231                 if (newValueX < 0.0) {
 232                     hsb.setValue(0.0);
 233                 }
 234                 else if (newValueX < 1.0) {
 235                     hsb.setValue(newValueX);
 236                 }
 237                 else if (newValueX > 1.0) {
 238                     hsb.setValue(1.0);
 239                 }
 240             }
 241         }
 242     };
 243 
 244 
 245 
 246     /***************************************************************************
 247      *                                                                         *
 248      * Constructors                                                            *


 262         // install default input map for the ScrollPane control
 263         behavior = new ScrollPaneBehavior(control);
 264 //        control.setInputMap(behavior.getInputMap());
 265 
 266         initialize();
 267 
 268         // Register listeners
 269         Consumer<ObservableValue<?>> viewportSizeHintConsumer = e -> {
 270             // change affects pref size, so requestLayout on control
 271             getSkinnable().requestLayout();
 272         };
 273         registerChangeListener(control.contentProperty(), e -> {
 274             if (scrollNode != getSkinnable().getContent()) {
 275                 if (scrollNode != null) {
 276                     scrollNode.layoutBoundsProperty().removeListener(nodeListener);
 277                     scrollNode.layoutBoundsProperty().removeListener(boundsChangeListener);
 278                     viewContent.getChildren().remove(scrollNode);
 279                 }
 280                 scrollNode = getSkinnable().getContent();
 281                 if (scrollNode != null) {
 282                     nodeWidth = snapSizeX(scrollNode.getLayoutBounds().getWidth());
 283                     nodeHeight = snapSizeY(scrollNode.getLayoutBounds().getHeight());
 284                     viewContent.getChildren().setAll(scrollNode);
 285                     scrollNode.layoutBoundsProperty().addListener(nodeListener);
 286                     scrollNode.layoutBoundsProperty().addListener(boundsChangeListener);
 287                 }
 288             }
 289             getSkinnable().requestLayout();
 290         });
 291         registerChangeListener(control.fitToWidthProperty(), e -> {
 292             getSkinnable().requestLayout();
 293             viewRect.requestLayout();
 294         });
 295         registerChangeListener(control.fitToHeightProperty(), e -> {
 296             getSkinnable().requestLayout();
 297             viewRect.requestLayout();
 298         });
 299         registerChangeListener(control.hbarPolicyProperty(), e -> {
 300             // change might affect pref size, so requestLayout on control
 301             getSkinnable().requestLayout();
 302         });
 303         registerChangeListener(control.vbarPolicyProperty(), e -> {


 461 
 462     /** {@inheritDoc} */
 463     @Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
 464         final ScrollPane sp = getSkinnable();
 465 
 466         double hsbHeight = computeHsbSizeHint(sp);
 467         double minHeight = hsbHeight + snappedTopInset() + snappedBottomInset();
 468 
 469         if (sp.getMinViewportHeight() > 0) {
 470             return (sp.getMinViewportHeight() + minHeight);
 471         } else {
 472             double h = corner.minHeight(-1);
 473             return (h > 0) ? (3 * h) : (DEFAULT_MIN_SIZE);
 474         }
 475     }
 476 
 477     @Override protected void layoutChildren(final double x, final double y,
 478                                             final double w, final double h) {
 479         final ScrollPane control = getSkinnable();
 480         final Insets padding = control.getPadding();
 481         final double rightPadding = snapSizeX(padding.getRight());
 482         final double leftPadding = snapSizeX(padding.getLeft());
 483         final double topPadding = snapSizeY(padding.getTop());
 484         final double bottomPadding = snapSizeY(padding.getBottom());
 485 
 486         vsb.setMin(control.getVmin());
 487         vsb.setMax(control.getVmax());
 488 
 489         //should only do this on css setup
 490         hsb.setMin(control.getHmin());
 491         hsb.setMax(control.getHmax());
 492 
 493         contentWidth = w;
 494         contentHeight = h;
 495 
 496         /*
 497         ** we want the scrollbars to go right to the border
 498         */
 499         double hsbWidth = 0;
 500         double vsbHeight = 0;
 501 
 502         computeScrollNodeSize(contentWidth, contentHeight);
 503         computeScrollBarSize();
 504 


 569 
 570         hsb.setVisible(hsbvis);
 571         if (hsbvis) {
 572             /*
 573             ** round up position of ScrollBar, round down it's size.
 574             **
 575             ** Positioning the ScrollBar
 576             **  The Padding should go between the content and the edge,
 577             **  otherwise changes in padding move the ScrollBar, and could
 578             **  in extreme cases size the ScrollBar to become unusable.
 579             **  The -1, +1 plus one bit :
 580             **   If padding in => 1 then we allow one pixel to appear as the
 581             **   outside border of the Scrollbar, and the rest on the inside.
 582             **   If padding is < 1 then we just stick to the edge.
 583             */
 584             hsb.resizeRelocate(cx, snappedTopInset() + h - hsbHeight + (bottomPadding < 1 ? 0 : bottomPadding - 1),
 585                     hsbWidth, hsbHeight);
 586         }
 587         updateHorizontalSB();
 588 
 589         viewRect.resizeRelocate(snappedLeftInset(), snappedTopInset(), snapSizeX(contentWidth), snapSizeY(contentHeight));
 590         resetClip();
 591 
 592         if (vsbvis && hsbvis) {
 593             corner.setVisible(true);
 594             double cornerWidth = vsbWidth;
 595             double cornerHeight = hsbHeight;
 596             corner.resizeRelocate(snapPositionX(vsb.getLayoutX()), snapPositionY(hsb.getLayoutY()), snapSizeX(cornerWidth), snapSizeY(cornerHeight));
 597         } else {
 598             corner.setVisible(false);
 599         }
 600         control.setViewportBounds(new BoundingBox(snapPositionX(viewContent.getLayoutX()), snapPositionY(viewContent.getLayoutY()), snapSizeX(contentWidth), snapSizeY(contentHeight)));
 601     }
 602 
 603     /** {@inheritDoc} */
 604     @Override protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
 605         switch (attribute) {
 606             case VERTICAL_SCROLLBAR: return vsb;
 607             case HORIZONTAL_SCROLLBAR: return hsb;
 608             default: return super.queryAccessibleAttribute(attribute, parameters);
 609         }
 610     }
 611 
 612 
 613 
 614     /***************************************************************************
 615      *                                                                         *
 616      * Private implementation                                                  *
 617      *                                                                         *
 618      **************************************************************************/
 619 
 620     private void initialize() {


1022                 : 0;
1023     }
1024 
1025     /**
1026      * Computes the size that should be reserved for vertical scrollbar in size hints (min/pref width)
1027      */
1028     private double computeVsbSizeHint(ScrollPane sp) {
1029         return ((sp.getVbarPolicy() == ScrollBarPolicy.ALWAYS) ||
1030                 (sp.getVbarPolicy() == ScrollBarPolicy.AS_NEEDED && (sp.getPrefViewportWidth() > 0
1031                         || sp.getMinViewportWidth() > 0)))
1032                 ? vsb.prefWidth(ScrollBar.USE_COMPUTED_SIZE)
1033                 : 0;
1034     }
1035 
1036     private void computeScrollNodeSize(double contentWidth, double contentHeight) {
1037         if (scrollNode != null) {
1038             if (scrollNode.isResizable()) {
1039                 ScrollPane control = getSkinnable();
1040                 Orientation bias = scrollNode.getContentBias();
1041                 if (bias == null) {
1042                     nodeWidth = snapSizeX(boundedSize(control.isFitToWidth()? contentWidth : scrollNode.prefWidth(-1),
1043                                                          scrollNode.minWidth(-1),scrollNode.maxWidth(-1)));
1044                     nodeHeight = snapSizeY(boundedSize(control.isFitToHeight()? contentHeight : scrollNode.prefHeight(-1),
1045                                                           scrollNode.minHeight(-1), scrollNode.maxHeight(-1)));
1046 
1047                 } else if (bias == Orientation.HORIZONTAL) {
1048                     nodeWidth = snapSizeX(boundedSize(control.isFitToWidth()? contentWidth : scrollNode.prefWidth(-1),
1049                                                          scrollNode.minWidth(-1),scrollNode.maxWidth(-1)));
1050                     nodeHeight = snapSizeY(boundedSize(control.isFitToHeight()? contentHeight : scrollNode.prefHeight(nodeWidth),
1051                                                           scrollNode.minHeight(nodeWidth),scrollNode.maxHeight(nodeWidth)));
1052 
1053                 } else { // bias == VERTICAL
1054                     nodeHeight = snapSizeY(boundedSize(control.isFitToHeight()? contentHeight : scrollNode.prefHeight(-1),
1055                                                           scrollNode.minHeight(-1), scrollNode.maxHeight(-1)));
1056                     nodeWidth = snapSizeX(boundedSize(control.isFitToWidth()? contentWidth : scrollNode.prefWidth(nodeHeight),
1057                                                          scrollNode.minWidth(nodeHeight),scrollNode.maxWidth(nodeHeight)));
1058                 }
1059 
1060             } else {
1061                 nodeWidth = snapSizeX(scrollNode.getLayoutBounds().getWidth());
1062                 nodeHeight = snapSizeY(scrollNode.getLayoutBounds().getHeight());
1063             }
1064             nodeSizeInvalid = false;
1065         }
1066     }
1067 
1068     private boolean isReverseNodeOrientation() {
1069         return (scrollNode != null &&
1070                 getSkinnable().getEffectiveNodeOrientation() !=
1071                             scrollNode.getEffectiveNodeOrientation());
1072     }
1073 
1074     private boolean determineHorizontalSBVisible() {
1075         final ScrollPane sp = getSkinnable();
1076 
1077         if (Properties.IS_TOUCH_SUPPORTED) {
1078             return (tempVisibility && (nodeWidth > contentWidth));
1079         }
1080         else {
1081             // RT-17395: ScrollBarPolicy might be null. If so, treat it as "AS_NEEDED", which is the default
1082             ScrollBarPolicy hbarPolicy = sp.getHbarPolicy();


1087         }
1088     }
1089 
1090     private boolean determineVerticalSBVisible() {
1091         final ScrollPane sp = getSkinnable();
1092 
1093         if (Properties.IS_TOUCH_SUPPORTED) {
1094             return (tempVisibility && (nodeHeight > contentHeight));
1095         }
1096         else {
1097             // RT-17395: ScrollBarPolicy might be null. If so, treat it as "AS_NEEDED", which is the default
1098             ScrollBarPolicy vbarPolicy = sp.getVbarPolicy();
1099             return (ScrollBarPolicy.NEVER == vbarPolicy) ? false :
1100                    ((ScrollBarPolicy.ALWAYS == vbarPolicy) ? true :
1101                    ((sp.isFitToHeight() && scrollNode != null ? scrollNode.isResizable() : false) ?
1102                    (nodeHeight > contentHeight && scrollNode.minHeight(-1) > contentHeight) : (nodeHeight > contentHeight)));
1103         }
1104     }
1105 
1106     private void computeScrollBarSize() {
1107         vsbWidth = snapSizeX(vsb.prefWidth(-1));
1108         if (vsbWidth == 0) {
1109             //            println("*** WARNING ScrollPaneSkin: can't get scroll bar width, using {DEFAULT_SB_BREADTH}");
1110             if (Properties.IS_TOUCH_SUPPORTED) {
1111                 vsbWidth = DEFAULT_EMBEDDED_SB_BREADTH;
1112             }
1113             else {
1114                 vsbWidth = DEFAULT_SB_BREADTH;
1115             }
1116         }
1117         hsbHeight = snapSizeY(hsb.prefHeight(-1));
1118         if (hsbHeight == 0) {
1119             //            println("*** WARNING ScrollPaneSkin: can't get scroll bar height, using {DEFAULT_SB_BREADTH}");
1120             if (Properties.IS_TOUCH_SUPPORTED) {
1121                 hsbHeight = DEFAULT_EMBEDDED_SB_BREADTH;
1122             }
1123             else {
1124                 hsbHeight = DEFAULT_SB_BREADTH;
1125             }
1126         }
1127     }
1128 
1129     private void updateHorizontalSB() {
1130         double contentRatio = nodeWidth * (hsb.getMax() - hsb.getMin());
1131         if (contentRatio > 0.0) {
1132             hsb.setVisibleAmount(contentWidth / contentRatio);
1133             hsb.setBlockIncrement(0.9 * hsb.getVisibleAmount());
1134             hsb.setUnitIncrement(0.1 * hsb.getVisibleAmount());
1135         }
1136         else {
1137             hsb.setVisibleAmount(0.0);


1161             vsb.setVisibleAmount(0.0);
1162             vsb.setBlockIncrement(0.0);
1163             vsb.setUnitIncrement(0.0);
1164         }
1165 
1166         if (vsb.isVisible()) {
1167             updatePosY();
1168         } else {
1169             if (nodeHeight > contentHeight) {
1170                 updatePosY();
1171             } else {
1172                 viewContent.setLayoutY(0);
1173             }
1174         }
1175     }
1176 
1177     private double updatePosX() {
1178         final ScrollPane sp = getSkinnable();
1179         double x = isReverseNodeOrientation() ? (hsb.getMax() - (posX - hsb.getMin())) : posX;
1180         double minX = Math.min((- x / (hsb.getMax() - hsb.getMin()) * (nodeWidth - contentWidth)), 0);
1181         viewContent.setLayoutX(snapPositionX(minX));
1182         if (!sp.hvalueProperty().isBound()) sp.setHvalue(Utils.clamp(sp.getHmin(), posX, sp.getHmax()));
1183         return posX;
1184     }
1185 
1186     private double updatePosY() {
1187         final ScrollPane sp = getSkinnable();
1188         double minY = Math.min((- posY / (vsb.getMax() - vsb.getMin()) * (nodeHeight - contentHeight)), 0);
1189         viewContent.setLayoutY(snapPositionY(minY));
1190         if (!sp.vvalueProperty().isBound()) sp.setVvalue(Utils.clamp(sp.getVmin(), posY, sp.getVmax()));
1191         return posY;
1192     }
1193 
1194     private void resetClip() {
1195         clipRect.setWidth(snapSizeX(contentWidth));
1196         clipRect.setHeight(snapSizeY(contentHeight));
1197     }
1198 
1199     private void startSBReleasedAnimation() {
1200         if (sbTouchTimeline == null) {
1201             /*
1202             ** timeline to leave the scrollbars visible for a short
1203             ** while after a scroll/drag
1204             */
1205             sbTouchTimeline = new Timeline();
1206             sbTouchKF1 = new KeyFrame(Duration.millis(0), event -> {
1207                 tempVisibility = true;
1208                 if (touchDetected == true || mouseDown == true) {
1209                     sbTouchTimeline.playFromStart();
1210                 }
1211             });
1212 
1213             sbTouchKF2 = new KeyFrame(Duration.millis(1000), event -> {
1214                 tempVisibility = false;
1215                 getSkinnable().requestLayout();
1216             });