1 /*
   2  * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.awt.X11;
  27 
  28 import java.awt.*;
  29 import java.awt.event.MouseEvent;
  30 import java.awt.event.MouseWheelEvent;
  31 import java.awt.event.AdjustmentEvent;
  32 import java.util.ArrayList;
  33 import java.util.Iterator;
  34 import sun.util.logging.PlatformLogger;
  35 
  36 // FIXME: implement multi-select
  37 /*
  38  * Class to paint a list of items, possibly with scrollbars
  39  * This class paints all items with the same font
  40  * For now, this class manages the list of items and painting thereof, but not
  41  * posting of Item or ActionEvents
  42  */
  43 final class ListHelper implements XScrollbarClient {
  44     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.ListHelper");
  45 
  46     private final int FOCUS_INSET = 1;
  47 
  48     private final int BORDER_WIDTH; // Width of border drawn around the list
  49                                     // of items
  50     private final int ITEM_MARGIN;  // Margin between the border of the list
  51                                     // of items and and item's bg, and between
  52                                     // items
  53     private final int TEXT_SPACE;   // Space between the edge of an item and
  54                                     // the text
  55 
  56     private final int SCROLLBAR_WIDTH;  // Width of a scrollbar
  57 
  58     private java.util.List<String> items;        // List of items
  59 
  60     // TODO: maybe this would be better as a simple int[]
  61     private java.util.List<Integer> selected;     // List of selected items
  62     private boolean multiSelect;         // Can multiple items be selected
  63                                          // at once?
  64     private int focusedIndex;
  65 
  66     private int maxVisItems;             // # items visible without a vsb
  67     private XVerticalScrollbar vsb;      // null if unsupported
  68     private boolean vsbVis;
  69     private XHorizontalScrollbar hsb;    // null if unsupported
  70     private boolean hsbVis;
  71 
  72     private Font font;
  73     private FontMetrics fm;
  74 
  75     private XWindow peer;   // So far, only needed for painting
  76                             // on notifyValue()
  77     private Color[] colors; // Passed in for painting on notifyValue()
  78 
  79     // Holds the true if mouse is dragging outside of the area of the list
  80     // The flag is used at the moment of the dragging and releasing mouse
  81     // See 6243382 for more information
  82     private boolean mouseDraggedOutVertically = false;
  83     private volatile boolean vsbVisibilityChanged = false;
  84 
  85     /*
  86      * Comment
  87      */
  88     ListHelper(XWindow peer, Color[] colors, int initialSize,
  89                boolean multiSelect, boolean scrollVert, boolean scrollHoriz,
  90                Font font, int maxVisItems, int SPACE, int MARGIN, int BORDER,
  91                int SCROLLBAR) {
  92         this.peer = peer;
  93         this.colors = colors;
  94         this.multiSelect = multiSelect;
  95         items = new ArrayList<>(initialSize);
  96         selected = new ArrayList<>(1);
  97         selected.add(Integer.valueOf(-1));
  98 
  99         this.maxVisItems = maxVisItems;
 100         if (scrollVert) {
 101             vsb = new XVerticalScrollbar(this);
 102             vsb.setValues(0, 0, 0, 0, 1, maxVisItems - 1);
 103         }
 104         if (scrollHoriz) {
 105             hsb = new XHorizontalScrollbar(this);
 106             hsb.setValues(0, 0, 0, 0, 1, 1);
 107         }
 108 
 109         setFont(font);
 110         TEXT_SPACE = SPACE;
 111         ITEM_MARGIN = MARGIN;
 112         BORDER_WIDTH = BORDER;
 113         SCROLLBAR_WIDTH = SCROLLBAR;
 114     }
 115 
 116     @Override
 117     public Component getEventSource() {
 118         return peer.getEventSource();
 119     }
 120 
 121     /**********************************************************************/
 122     /* List management methods                                            */
 123     /**********************************************************************/
 124 
 125     void add(String item) {
 126         items.add(item);
 127         updateScrollbars();
 128     }
 129 
 130     void add(String item, int index) {
 131         items.add(index, item);
 132         updateScrollbars();
 133     }
 134 
 135     void remove(String item) {
 136         // FIXME: need to clean up select list, too?
 137         items.remove(item);
 138         updateScrollbars();
 139         // Is vsb visible now?
 140     }
 141 
 142     void remove(int index) {
 143         // FIXME: need to clean up select list, too?
 144         items.remove(index);
 145         updateScrollbars();
 146         // Is vsb visible now?
 147     }
 148 
 149     void removeAll() {
 150         items.removeAll(items);
 151         updateScrollbars();
 152     }
 153 
 154     void setMultiSelect(boolean ms) {
 155         multiSelect = ms;
 156     }
 157 
 158     /*
 159      * docs.....definitely docs
 160      * merely keeps internal track of which items are selected for painting
 161      * dealing with target Components happens elsewhere
 162      */
 163     void select(int index) {
 164         if (index > getItemCount() - 1) {
 165             index = (isEmpty() ? -1 : 0);
 166         }
 167         if (multiSelect) {
 168             assert false : "Implement ListHelper.select() for multiselect";
 169         }
 170         else if (getSelectedIndex() != index) {
 171             selected.remove(0);
 172             selected.add(Integer.valueOf(index));
 173             makeVisible(index);
 174         }
 175     }
 176 
 177     /* docs */
 178     void deselect(int index) {
 179         assert(false);
 180     }
 181 
 182     /* docs */
 183     /* if called for multiselect, return -1 */
 184     int getSelectedIndex() {
 185         if (!multiSelect) {
 186             Integer val = selected.get(0);
 187             return val.intValue();
 188         }
 189         return -1;
 190     }
 191 
 192     int[] getSelectedIndexes() { assert(false); return null;}
 193 
 194     /*
 195      * A getter method for XChoicePeer.
 196      * Returns vsbVisiblityChanged value and sets it to false.
 197      */
 198     boolean checkVsbVisibilityChangedAndReset(){
 199         boolean returnVal = vsbVisibilityChanged;
 200         vsbVisibilityChanged = false;
 201         return returnVal;
 202     }
 203 
 204     boolean isEmpty() {
 205         return items.isEmpty();
 206     }
 207 
 208     int getItemCount() {
 209         return items.size();
 210     }
 211 
 212     String getItem(int index) {
 213         return items.get(index);
 214     }
 215 
 216     /**********************************************************************/
 217     /* GUI-related methods                                                */
 218     /**********************************************************************/
 219 
 220     void setFocusedIndex(int index) {
 221         focusedIndex = index;
 222     }
 223 
 224     private boolean isFocusedIndex(int index) {
 225         return index == focusedIndex;
 226     }
 227 
 228     void setFont(Font newFont) {
 229         if (newFont != font) {
 230             font = newFont;
 231             fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
 232             // Also cache stuff like fontHeight?
 233         }
 234     }
 235 
 236     /*
 237      * Returns width of the text of the longest item
 238      */
 239     int getMaxItemWidth() {
 240         int m = 0;
 241         int end = getItemCount();
 242         for(int i = 0 ; i < end ; i++) {
 243             int l = fm.stringWidth(getItem(i));
 244             m = Math.max(m, l);
 245         }
 246         return m;
 247     }
 248 
 249     /*
 250      * Height of an item (this doesn't include ITEM_MARGIN)
 251      */
 252     int getItemHeight() {
 253         return fm.getHeight() + (2*TEXT_SPACE);
 254     }
 255 
 256     int y2index(int y) {
 257         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 258             log.fine("y=" + y +", firstIdx=" + firstDisplayedIndex() +", itemHeight=" + getItemHeight()
 259                      + ",item_margin=" + ITEM_MARGIN);
 260         }
 261         // See 6243382 for more information
 262         int newIdx = firstDisplayedIndex() + ((y - 2*ITEM_MARGIN) / (getItemHeight() + 2*ITEM_MARGIN));
 263         return newIdx;
 264     }
 265 
 266     /* write these
 267     int index2y(int);
 268     public int numItemsDisplayed() {}
 269     */
 270 
 271     int firstDisplayedIndex() {
 272         if (vsbVis) {
 273             return vsb.getValue();
 274         }
 275         return 0;
 276     }
 277 
 278     int lastDisplayedIndex() {
 279         // FIXME: need to account for horiz scroll bar
 280         if (hsbVis) {
 281             assert false : "Implement for horiz scroll bar";
 282         }
 283 
 284         return vsbVis ? vsb.getValue() + maxVisItems - 1: getItemCount() - 1;
 285     }
 286 
 287     /*
 288      * If the given index is not visible in the List, scroll so that it is.
 289      */
 290     private void makeVisible(int index) {
 291         if (vsbVis) {
 292             if (index < firstDisplayedIndex()) {
 293                 vsb.setValue(index);
 294             }
 295             else if (index > lastDisplayedIndex()) {
 296                 vsb.setValue(index - maxVisItems + 1);
 297             }
 298         }
 299     }
 300 
 301     // FIXME: multi-select needs separate focused index
 302     void up() {
 303         int curIdx = getSelectedIndex();
 304         int numItems = getItemCount();
 305         int newIdx;
 306 
 307         assert curIdx >= 0;
 308 
 309         if (curIdx == 0) {
 310             newIdx = numItems - 1;
 311         }
 312         else {
 313             newIdx = --curIdx;
 314         }
 315         // focus(newIdx);
 316         select(newIdx);
 317     }
 318 
 319     void down() {
 320         int newIdx = (getSelectedIndex() + 1) % getItemCount();
 321         select(newIdx);
 322     }
 323 
 324     void pageUp() {
 325         // FIXME: for multi-select, move the focused item, not the selected item
 326         if (vsbVis && firstDisplayedIndex() > 0) {
 327             if (multiSelect) {
 328                 assert false : "Implement pageUp() for multiSelect";
 329             }
 330             else {
 331                 int selectionOffset = getSelectedIndex() - firstDisplayedIndex();
 332                 // the vsb does bounds checking
 333                 int newIdx = firstDisplayedIndex() - vsb.getBlockIncrement();
 334                 vsb.setValue(newIdx);
 335                 select(firstDisplayedIndex() + selectionOffset);
 336             }
 337         }
 338     }
 339     void pageDown() {
 340         if (vsbVis && lastDisplayedIndex() < getItemCount() - 1) {
 341             if (multiSelect) {
 342                 assert false : "Implement pageDown() for multiSelect";
 343             }
 344             else {
 345                 int selectionOffset = getSelectedIndex() - firstDisplayedIndex();
 346                 // the vsb does bounds checking
 347                 int newIdx = lastDisplayedIndex();
 348                 vsb.setValue(newIdx);
 349                 select(firstDisplayedIndex() + selectionOffset);
 350             }
 351         }
 352     }
 353     void home() {}
 354     void end() {}
 355 
 356 
 357     boolean isVSBVisible() { return vsbVis; }
 358     boolean isHSBVisible() { return hsbVis; }
 359 
 360     XVerticalScrollbar getVSB() { return vsb; }
 361     XHorizontalScrollbar getHSB() { return hsb; }
 362 
 363     boolean isInVertSB(Rectangle bounds, int x, int y) {
 364         if (vsbVis) {
 365             assert vsb != null : "Vert scrollbar is visible, yet is null?";
 366             int sbHeight = hsbVis ? bounds.height - SCROLLBAR_WIDTH : bounds.height;
 367             return (x <= bounds.width) &&
 368                    (x >= bounds.width - SCROLLBAR_WIDTH) &&
 369                    (y >= 0) &&
 370                    (y <= sbHeight);
 371         }
 372         return false;
 373     }
 374 
 375     boolean isInHorizSB(Rectangle bounds, int x, int y) {
 376         if (hsbVis) {
 377             assert hsb != null : "Horiz scrollbar is visible, yet is null?";
 378 
 379             int sbWidth = vsbVis ? bounds.width - SCROLLBAR_WIDTH : bounds.width;
 380             return (x <= sbWidth) &&
 381                    (x >= 0) &&
 382                    (y >= bounds.height - SCROLLBAR_WIDTH) &&
 383                    (y <= bounds.height);
 384         }
 385         return false;
 386     }
 387 
 388     void handleVSBEvent(MouseEvent e, Rectangle bounds, int x, int y) {
 389         int sbHeight = hsbVis ? bounds.height - SCROLLBAR_WIDTH : bounds.height;
 390 
 391         vsb.handleMouseEvent(e.getID(),
 392                              e.getModifiers(),
 393                              x - (bounds.width - SCROLLBAR_WIDTH),
 394                              y);
 395     }
 396 
 397     /*
 398      * Called when items are added/removed.
 399      * Update whether the scrollbar is visible or not, scrollbar values
 400      */
 401     private void updateScrollbars() {
 402         boolean oldVsbVis = vsbVis;
 403         vsbVis = vsb != null && items.size() > maxVisItems;
 404         if (vsbVis) {
 405             vsb.setValues(vsb.getValue(), getNumItemsDisplayed(),
 406                           vsb.getMinimum(), items.size());
 407         }
 408 
 409         // 6405689. If Vert Scrollbar gets disappeared from the dropdown menu we should repaint whole dropdown even if
 410         // no actual resize gets invoked. This is needed because some painting artifacts remained between dropdown items
 411         // but draw3DRect doesn't clear the area inside. Instead it just paints lines as borders.
 412         vsbVisibilityChanged = (vsbVis != oldVsbVis);
 413         // FIXME: check if added item makes a hsb necessary (if supported, that of course)
 414     }
 415 
 416     private int getNumItemsDisplayed() {
 417         return items.size() > maxVisItems ? maxVisItems : items.size();
 418     }
 419 
 420     @Override
 421     public void repaintScrollbarRequest(XScrollbar sb) {
 422         Graphics g = peer.getGraphics();
 423         Rectangle bounds = peer.getBounds();
 424         if ((sb == vsb) && vsbVis) {
 425             paintVSB(g, XComponentPeer.getSystemColors(), bounds);
 426         }
 427         else if ((sb == hsb) && hsbVis) {
 428             paintHSB(g, XComponentPeer.getSystemColors(), bounds);
 429         }
 430         g.dispose();
 431     }
 432 
 433     @Override
 434     public void notifyValue(XScrollbar obj, int type, int v, boolean isAdjusting) {
 435         if (obj == vsb) {
 436             int oldScrollValue = vsb.getValue();
 437             vsb.setValue(v);
 438             boolean needRepaint = (oldScrollValue != vsb.getValue());
 439             // See 6243382 for more information
 440             if (mouseDraggedOutVertically){
 441                 int oldItemValue = getSelectedIndex();
 442                 int newItemValue = getSelectedIndex() + v - oldScrollValue;
 443                 select(newItemValue);
 444                 needRepaint = needRepaint || (getSelectedIndex() != oldItemValue);
 445             }
 446 
 447             // FIXME: how are we going to paint!?
 448             Graphics g = peer.getGraphics();
 449             Rectangle bounds = peer.getBounds();
 450             int first = v;
 451             int last = Math.min(getItemCount() - 1,
 452                                 v + maxVisItems);
 453             if (needRepaint) {
 454                 paintItems(g, colors, bounds, first, last);
 455             }
 456             g.dispose();
 457 
 458         }
 459         else if ((XHorizontalScrollbar)obj == hsb) {
 460             hsb.setValue(v);
 461             // FIXME: how are we going to paint!?
 462         }
 463     }
 464 
 465     void updateColors(Color[] newColors) {
 466         colors = newColors;
 467     }
 468 
 469     /*
 470     public void paintItems(Graphics g,
 471                            Color[] colors,
 472                            Rectangle bounds,
 473                            Font font,
 474                            int first,
 475                            int last,
 476                            XVerticalScrollbar vsb,
 477                            XHorizontalScrollbar hsb) {
 478     */
 479     void paintItems(Graphics g,
 480                            Color[] colors,
 481                            Rectangle bounds) {
 482         // paint border
 483         // paint items
 484         // paint scrollbars
 485         // paint focus?
 486 
 487     }
 488     void paintAllItems(Graphics g,
 489                            Color[] colors,
 490                            Rectangle bounds) {
 491         paintItems(g, colors, bounds,
 492                    firstDisplayedIndex(), lastDisplayedIndex());
 493     }
 494     private void paintItems(Graphics g, Color[] colors, Rectangle bounds,
 495                             int first, int last) {
 496         peer.flush();
 497         int x = BORDER_WIDTH + ITEM_MARGIN;
 498         int width = bounds.width - 2*ITEM_MARGIN - 2*BORDER_WIDTH - (vsbVis ? SCROLLBAR_WIDTH : 0);
 499         int height = getItemHeight();
 500         int y = BORDER_WIDTH + ITEM_MARGIN;
 501 
 502         for (int i = first; i <= last ; i++) {
 503             paintItem(g, colors, getItem(i),
 504                       x, y, width, height,
 505                       isItemSelected(i),
 506                       isFocusedIndex(i));
 507             y += height + 2*ITEM_MARGIN;
 508         }
 509 
 510         if (vsbVis) {
 511             paintVSB(g, XComponentPeer.getSystemColors(), bounds);
 512         }
 513         if (hsbVis) {
 514             paintHSB(g, XComponentPeer.getSystemColors(), bounds);
 515         }
 516         peer.flush();
 517         // FIXME: if none of the items were focused, paint focus around the
 518         // entire list.  This is how java.awt.List should work.
 519     }
 520 
 521     /*
 522      * comment about what is painted (i.e. the focus rect
 523      */
 524     private void paintItem(Graphics g, Color[] colors, String string, int x,
 525                            int y, int width, int height, boolean selected,
 526                            boolean focused) {
 527         //System.out.println("LP.pI(): x="+x+" y="+y+" w="+width+" h="+height);
 528         //g.setColor(colors[BACKGROUND_COLOR]);
 529 
 530         // FIXME: items shouldn't draw into the scrollbar
 531 
 532         if (selected) {
 533             g.setColor(colors[XComponentPeer.FOREGROUND_COLOR]);
 534         }
 535         else {
 536             g.setColor(colors[XComponentPeer.BACKGROUND_COLOR]);
 537         }
 538         g.fillRect(x, y, width, height);
 539 
 540         if (focused) {
 541             //g.setColor(colors[XComponentPeer.FOREGROUND_COLOR]);
 542             g.setColor(Color.BLACK);
 543             g.drawRect(x + FOCUS_INSET,
 544                        y + FOCUS_INSET,
 545                        width - 2*FOCUS_INSET,
 546                        height - 2*FOCUS_INSET);
 547         }
 548 
 549         if (selected) {
 550             g.setColor(colors[XComponentPeer.BACKGROUND_COLOR]);
 551         }
 552         else {
 553             g.setColor(colors[XComponentPeer.FOREGROUND_COLOR]);
 554         }
 555         g.setFont(font);
 556         //Rectangle clip = g.getClipBounds();
 557         //g.clipRect(x, y, width, height);
 558         //g.drawString(string, x + TEXT_SPACE, y + TEXT_SPACE + ITEM_MARGIN);
 559 
 560         int fontAscent = fm.getAscent();
 561         int fontDescent = fm.getDescent();
 562 
 563         g.drawString(string, x + TEXT_SPACE, y + (height + fm.getMaxAscent() - fm.getMaxDescent())/2);
 564         //g.clipRect(clip.x, clip.y, clip.width, clip.height);
 565     }
 566 
 567     private boolean isItemSelected(int index) {
 568         Iterator<Integer> itr = selected.iterator();
 569         while (itr.hasNext()) {
 570             Integer val = itr.next();
 571             if (val.intValue() == index) {
 572                 return true;
 573             }
 574         }
 575         return false;
 576     }
 577 
 578     private void paintVSB(Graphics g, Color colors[], Rectangle bounds) {
 579         int height = bounds.height - 2*BORDER_WIDTH - (hsbVis ? (SCROLLBAR_WIDTH-2) : 0);
 580         Graphics ng = g.create();
 581 
 582         g.setColor(colors[XComponentPeer.BACKGROUND_COLOR]);
 583         try {
 584             ng.translate(bounds.width - BORDER_WIDTH - SCROLLBAR_WIDTH,
 585                          BORDER_WIDTH);
 586             // Update scrollbar's size
 587             vsb.setSize(SCROLLBAR_WIDTH, bounds.height);
 588             vsb.paint(ng, colors, true);
 589         } finally {
 590             ng.dispose();
 591         }
 592     }
 593 
 594     private void paintHSB(Graphics g, Color colors[], Rectangle bounds) {
 595 
 596     }
 597 
 598     /*
 599      * Helper method for Components with integrated scrollbars.
 600      * Pass in the vertical and horizontal scroll bar (or null for none/hidden)
 601      * and the MouseWheelEvent, and the appropriate scrollbar will be scrolled
 602      * correctly.
 603      * Returns whether or not scrolling actually took place.  This will indicate
 604      * whether or not repainting is required.
 605      */
 606     static boolean doWheelScroll(XVerticalScrollbar vsb,
 607                                      XHorizontalScrollbar hsb,
 608                                      MouseWheelEvent e) {
 609         XScrollbar scroll = null;
 610         int wheelRotation;
 611 
 612         // Determine which, if any, sb to scroll
 613         if (vsb != null) {
 614             scroll = vsb;
 615         }
 616         else if (hsb != null) {
 617             scroll = hsb;
 618         }
 619         else { // Neither scrollbar is showing
 620             return false;
 621         }
 622 
 623         wheelRotation = e.getWheelRotation();
 624 
 625         // Check if scroll is necessary
 626         if ((wheelRotation < 0 && scroll.getValue() > scroll.getMinimum()) ||
 627             (wheelRotation > 0 && scroll.getValue() < scroll.getMaximum()) ||
 628             wheelRotation != 0) {
 629 
 630             int type = e.getScrollType();
 631             int incr;
 632             if (type == MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
 633                 incr = wheelRotation * scroll.getBlockIncrement();
 634             }
 635             else { // type is WHEEL_UNIT_SCROLL
 636                 incr = e.getUnitsToScroll() * scroll.getUnitIncrement();
 637             }
 638             scroll.setValue(scroll.getValue() + incr);
 639             return true;
 640         }
 641         return false;
 642     }
 643 
 644     /*
 645      * Helper method for XChoicePeer with integrated vertical scrollbar.
 646      * Start or stop vertical scrolling when mouse dragged in / out the area of the list if it's required
 647      * Restoring Motif behavior
 648      * See 6243382 for more information
 649      */
 650     void trackMouseDraggedScroll(int mouseX, int mouseY, int listWidth, int listHeight){
 651 
 652         if (!mouseDraggedOutVertically){
 653             if (vsb.beforeThumb(mouseX, mouseY)) {
 654                 vsb.setMode(AdjustmentEvent.UNIT_DECREMENT);
 655             } else {
 656                 vsb.setMode(AdjustmentEvent.UNIT_INCREMENT);
 657             }
 658         }
 659 
 660         if(!mouseDraggedOutVertically && (mouseY < 0 || mouseY >= listHeight)){
 661             mouseDraggedOutVertically = true;
 662             vsb.startScrollingInstance();
 663         }
 664 
 665         if (mouseDraggedOutVertically && mouseY >= 0 && mouseY < listHeight && mouseX >= 0 && mouseX < listWidth){
 666             mouseDraggedOutVertically = false;
 667             vsb.stopScrollingInstance();
 668         }
 669     }
 670 
 671     /*
 672      * Helper method for XChoicePeer with integrated vertical scrollbar.
 673      * Stop vertical scrolling when mouse released in / out the area of the list if it's required
 674      * Restoring Motif behavior
 675      * see 6243382 for more information
 676      */
 677     void trackMouseReleasedScroll(){
 678 
 679         if (mouseDraggedOutVertically){
 680             mouseDraggedOutVertically = false;
 681             vsb.stopScrollingInstance();
 682         }
 683 
 684     }
 685 }