1 /*
2  * Copyright (c) 2003, 2018, 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 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      */
ListHelper(XWindow peer, Color[] colors, int initialSize, boolean multiSelect, boolean scrollVert, boolean scrollHoriz, Font font, int maxVisItems, int SPACE, int MARGIN, int BORDER, int SCROLLBAR)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
getEventSource()117     public Component getEventSource() {
118         return peer.getEventSource();
119     }
120 
121     /**********************************************************************/
122     /* List management methods                                            */
123     /**********************************************************************/
124 
add(String item)125     void add(String item) {
126         items.add(item);
127         updateScrollbars();
128     }
129 
add(String item, int index)130     void add(String item, int index) {
131         items.add(index, item);
132         updateScrollbars();
133     }
134 
remove(String item)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 
remove(int index)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 
removeAll()149     void removeAll() {
150         items.removeAll(items);
151         updateScrollbars();
152     }
153 
setMultiSelect(boolean ms)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      */
select(int index)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 */
deselect(int index)178     void deselect(int index) {
179         assert(false);
180     }
181 
182     /* docs */
183     /* if called for multiselect, return -1 */
getSelectedIndex()184     int getSelectedIndex() {
185         if (!multiSelect) {
186             Integer val = selected.get(0);
187             return val.intValue();
188         }
189         return -1;
190     }
191 
getSelectedIndexes()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      */
checkVsbVisibilityChangedAndReset()198     boolean checkVsbVisibilityChangedAndReset(){
199         boolean returnVal = vsbVisibilityChanged;
200         vsbVisibilityChanged = false;
201         return returnVal;
202     }
203 
isEmpty()204     boolean isEmpty() {
205         return items.isEmpty();
206     }
207 
getItemCount()208     int getItemCount() {
209         return items.size();
210     }
211 
getItem(int index)212     String getItem(int index) {
213         return items.get(index);
214     }
215 
216     /**********************************************************************/
217     /* GUI-related methods                                                */
218     /**********************************************************************/
219 
setFocusedIndex(int index)220     void setFocusedIndex(int index) {
221         focusedIndex = index;
222     }
223 
isFocusedIndex(int index)224     private boolean isFocusedIndex(int index) {
225         return index == focusedIndex;
226     }
227 
228     @SuppressWarnings("deprecation")
setFont(Font newFont)229     void setFont(Font newFont) {
230         if (newFont != font) {
231             font = newFont;
232             fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
233             // Also cache stuff like fontHeight?
234         }
235     }
236 
237     /*
238      * Returns width of the text of the longest item
239      */
getMaxItemWidth()240     int getMaxItemWidth() {
241         int m = 0;
242         int end = getItemCount();
243         for(int i = 0 ; i < end ; i++) {
244             int l = fm.stringWidth(getItem(i));
245             m = Math.max(m, l);
246         }
247         return m;
248     }
249 
250     /*
251      * Height of an item (this doesn't include ITEM_MARGIN)
252      */
getItemHeight()253     int getItemHeight() {
254         return fm.getHeight() + (2*TEXT_SPACE);
255     }
256 
y2index(int y)257     int y2index(int y) {
258         if (log.isLoggable(PlatformLogger.Level.FINE)) {
259             log.fine("y=" + y +", firstIdx=" + firstDisplayedIndex() +", itemHeight=" + getItemHeight()
260                      + ",item_margin=" + ITEM_MARGIN);
261         }
262         // See 6243382 for more information
263         int newIdx = firstDisplayedIndex() + ((y - 2*ITEM_MARGIN) / (getItemHeight() + 2*ITEM_MARGIN));
264         return newIdx;
265     }
266 
267     /* write these
268     int index2y(int);
269     public int numItemsDisplayed() {}
270     */
271 
firstDisplayedIndex()272     int firstDisplayedIndex() {
273         if (vsbVis) {
274             return vsb.getValue();
275         }
276         return 0;
277     }
278 
lastDisplayedIndex()279     int lastDisplayedIndex() {
280         // FIXME: need to account for horiz scroll bar
281         if (hsbVis) {
282             assert false : "Implement for horiz scroll bar";
283         }
284 
285         return vsbVis ? vsb.getValue() + maxVisItems - 1: getItemCount() - 1;
286     }
287 
288     /*
289      * If the given index is not visible in the List, scroll so that it is.
290      */
makeVisible(int index)291     private void makeVisible(int index) {
292         if (vsbVis) {
293             if (index < firstDisplayedIndex()) {
294                 vsb.setValue(index);
295             }
296             else if (index > lastDisplayedIndex()) {
297                 vsb.setValue(index - maxVisItems + 1);
298             }
299         }
300     }
301 
302     // FIXME: multi-select needs separate focused index
up()303     void up() {
304         int curIdx = getSelectedIndex();
305         int numItems = getItemCount();
306         int newIdx;
307 
308         assert curIdx >= 0;
309 
310         if (curIdx == 0) {
311             newIdx = numItems - 1;
312         }
313         else {
314             newIdx = --curIdx;
315         }
316         // focus(newIdx);
317         select(newIdx);
318     }
319 
down()320     void down() {
321         int newIdx = (getSelectedIndex() + 1) % getItemCount();
322         select(newIdx);
323     }
324 
pageUp()325     void pageUp() {
326         // FIXME: for multi-select, move the focused item, not the selected item
327         if (vsbVis && firstDisplayedIndex() > 0) {
328             if (multiSelect) {
329                 assert false : "Implement pageUp() for multiSelect";
330             }
331             else {
332                 int selectionOffset = getSelectedIndex() - firstDisplayedIndex();
333                 // the vsb does bounds checking
334                 int newIdx = firstDisplayedIndex() - vsb.getBlockIncrement();
335                 vsb.setValue(newIdx);
336                 select(firstDisplayedIndex() + selectionOffset);
337             }
338         }
339     }
pageDown()340     void pageDown() {
341         if (vsbVis && lastDisplayedIndex() < getItemCount() - 1) {
342             if (multiSelect) {
343                 assert false : "Implement pageDown() for multiSelect";
344             }
345             else {
346                 int selectionOffset = getSelectedIndex() - firstDisplayedIndex();
347                 // the vsb does bounds checking
348                 int newIdx = lastDisplayedIndex();
349                 vsb.setValue(newIdx);
350                 select(firstDisplayedIndex() + selectionOffset);
351             }
352         }
353     }
home()354     void home() {}
end()355     void end() {}
356 
357 
isVSBVisible()358     boolean isVSBVisible() { return vsbVis; }
isHSBVisible()359     boolean isHSBVisible() { return hsbVis; }
360 
getVSB()361     XVerticalScrollbar getVSB() { return vsb; }
getHSB()362     XHorizontalScrollbar getHSB() { return hsb; }
363 
isInVertSB(Rectangle bounds, int x, int y)364     boolean isInVertSB(Rectangle bounds, int x, int y) {
365         if (vsbVis) {
366             assert vsb != null : "Vert scrollbar is visible, yet is null?";
367             int sbHeight = hsbVis ? bounds.height - SCROLLBAR_WIDTH : bounds.height;
368             return (x <= bounds.width) &&
369                    (x >= bounds.width - SCROLLBAR_WIDTH) &&
370                    (y >= 0) &&
371                    (y <= sbHeight);
372         }
373         return false;
374     }
375 
isInHorizSB(Rectangle bounds, int x, int y)376     boolean isInHorizSB(Rectangle bounds, int x, int y) {
377         if (hsbVis) {
378             assert hsb != null : "Horiz scrollbar is visible, yet is null?";
379 
380             int sbWidth = vsbVis ? bounds.width - SCROLLBAR_WIDTH : bounds.width;
381             return (x <= sbWidth) &&
382                    (x >= 0) &&
383                    (y >= bounds.height - SCROLLBAR_WIDTH) &&
384                    (y <= bounds.height);
385         }
386         return false;
387     }
388     @SuppressWarnings("deprecation")
handleVSBEvent(MouseEvent e, Rectangle bounds, int x, int y)389     void handleVSBEvent(MouseEvent e, Rectangle bounds, int x, int y) {
390         int sbHeight = hsbVis ? bounds.height - SCROLLBAR_WIDTH : bounds.height;
391 
392         vsb.handleMouseEvent(e.getID(),
393                              e.getModifiers(),
394                              x - (bounds.width - SCROLLBAR_WIDTH),
395                              y);
396     }
397 
398     /*
399      * Called when items are added/removed.
400      * Update whether the scrollbar is visible or not, scrollbar values
401      */
updateScrollbars()402     private void updateScrollbars() {
403         boolean oldVsbVis = vsbVis;
404         vsbVis = vsb != null && items.size() > maxVisItems;
405         if (vsbVis) {
406             vsb.setValues(vsb.getValue(), getNumItemsDisplayed(),
407                           vsb.getMinimum(), items.size());
408         }
409 
410         // 6405689. If Vert Scrollbar gets disappeared from the dropdown menu we should repaint whole dropdown even if
411         // no actual resize gets invoked. This is needed because some painting artifacts remained between dropdown items
412         // but draw3DRect doesn't clear the area inside. Instead it just paints lines as borders.
413         vsbVisibilityChanged = (vsbVis != oldVsbVis);
414         // FIXME: check if added item makes a hsb necessary (if supported, that of course)
415     }
416 
getNumItemsDisplayed()417     private int getNumItemsDisplayed() {
418         return items.size() > maxVisItems ? maxVisItems : items.size();
419     }
420 
421     @Override
repaintScrollbarRequest(XScrollbar sb)422     public void repaintScrollbarRequest(XScrollbar sb) {
423         Graphics g = peer.getGraphics();
424         Rectangle bounds = peer.getBounds();
425         if ((sb == vsb) && vsbVis) {
426             paintVSB(g, XComponentPeer.getSystemColors(), bounds);
427         }
428         else if ((sb == hsb) && hsbVis) {
429             paintHSB(g, XComponentPeer.getSystemColors(), bounds);
430         }
431         g.dispose();
432     }
433 
434     @Override
notifyValue(XScrollbar obj, int type, int v, boolean isAdjusting)435     public void notifyValue(XScrollbar obj, int type, int v, boolean isAdjusting) {
436         if (obj == vsb) {
437             int oldScrollValue = vsb.getValue();
438             vsb.setValue(v);
439             boolean needRepaint = (oldScrollValue != vsb.getValue());
440             // See 6243382 for more information
441             if (mouseDraggedOutVertically){
442                 int oldItemValue = getSelectedIndex();
443                 int newItemValue = getSelectedIndex() + v - oldScrollValue;
444                 select(newItemValue);
445                 needRepaint = needRepaint || (getSelectedIndex() != oldItemValue);
446             }
447 
448             // FIXME: how are we going to paint!?
449             Graphics g = peer.getGraphics();
450             Rectangle bounds = peer.getBounds();
451             int first = v;
452             int last = Math.min(getItemCount() - 1,
453                                 v + maxVisItems);
454             if (needRepaint) {
455                 paintItems(g, colors, bounds, first, last);
456             }
457             g.dispose();
458 
459         }
460         else if ((XHorizontalScrollbar)obj == hsb) {
461             hsb.setValue(v);
462             // FIXME: how are we going to paint!?
463         }
464     }
465 
updateColors(Color[] newColors)466     void updateColors(Color[] newColors) {
467         colors = newColors;
468     }
469 
470     /*
471     public void paintItems(Graphics g,
472                            Color[] colors,
473                            Rectangle bounds,
474                            Font font,
475                            int first,
476                            int last,
477                            XVerticalScrollbar vsb,
478                            XHorizontalScrollbar hsb) {
479     */
paintItems(Graphics g, Color[] colors, Rectangle bounds)480     void paintItems(Graphics g,
481                            Color[] colors,
482                            Rectangle bounds) {
483         // paint border
484         // paint items
485         // paint scrollbars
486         // paint focus?
487 
488     }
paintAllItems(Graphics g, Color[] colors, Rectangle bounds)489     void paintAllItems(Graphics g,
490                            Color[] colors,
491                            Rectangle bounds) {
492         paintItems(g, colors, bounds,
493                    firstDisplayedIndex(), lastDisplayedIndex());
494     }
paintItems(Graphics g, Color[] colors, Rectangle bounds, int first, int last)495     private void paintItems(Graphics g, Color[] colors, Rectangle bounds,
496                             int first, int last) {
497         peer.flush();
498         int x = BORDER_WIDTH + ITEM_MARGIN;
499         int width = bounds.width - 2*ITEM_MARGIN - 2*BORDER_WIDTH - (vsbVis ? SCROLLBAR_WIDTH : 0);
500         int height = getItemHeight();
501         int y = BORDER_WIDTH + ITEM_MARGIN;
502 
503         for (int i = first; i <= last ; i++) {
504             paintItem(g, colors, getItem(i),
505                       x, y, width, height,
506                       isItemSelected(i),
507                       isFocusedIndex(i));
508             y += height + 2*ITEM_MARGIN;
509         }
510 
511         if (vsbVis) {
512             paintVSB(g, XComponentPeer.getSystemColors(), bounds);
513         }
514         if (hsbVis) {
515             paintHSB(g, XComponentPeer.getSystemColors(), bounds);
516         }
517         peer.flush();
518         // FIXME: if none of the items were focused, paint focus around the
519         // entire list.  This is how java.awt.List should work.
520     }
521 
522     /*
523      * comment about what is painted (i.e. the focus rect
524      */
paintItem(Graphics g, Color[] colors, String string, int x, int y, int width, int height, boolean selected, boolean focused)525     private void paintItem(Graphics g, Color[] colors, String string, int x,
526                            int y, int width, int height, boolean selected,
527                            boolean focused) {
528         //System.out.println("LP.pI(): x="+x+" y="+y+" w="+width+" h="+height);
529         //g.setColor(colors[BACKGROUND_COLOR]);
530 
531         // FIXME: items shouldn't draw into the scrollbar
532 
533         if (selected) {
534             g.setColor(colors[XComponentPeer.FOREGROUND_COLOR]);
535         }
536         else {
537             g.setColor(colors[XComponentPeer.BACKGROUND_COLOR]);
538         }
539         g.fillRect(x, y, width, height);
540 
541         if (focused) {
542             //g.setColor(colors[XComponentPeer.FOREGROUND_COLOR]);
543             g.setColor(Color.BLACK);
544             g.drawRect(x + FOCUS_INSET,
545                        y + FOCUS_INSET,
546                        width - 2*FOCUS_INSET,
547                        height - 2*FOCUS_INSET);
548         }
549 
550         if (selected) {
551             g.setColor(colors[XComponentPeer.BACKGROUND_COLOR]);
552         }
553         else {
554             g.setColor(colors[XComponentPeer.FOREGROUND_COLOR]);
555         }
556         g.setFont(font);
557         //Rectangle clip = g.getClipBounds();
558         //g.clipRect(x, y, width, height);
559         //g.drawString(string, x + TEXT_SPACE, y + TEXT_SPACE + ITEM_MARGIN);
560 
561         int fontAscent = fm.getAscent();
562         int fontDescent = fm.getDescent();
563 
564         g.drawString(string, x + TEXT_SPACE, y + (height + fm.getMaxAscent() - fm.getMaxDescent())/2);
565         //g.clipRect(clip.x, clip.y, clip.width, clip.height);
566     }
567 
isItemSelected(int index)568     private boolean isItemSelected(int index) {
569         Iterator<Integer> itr = selected.iterator();
570         while (itr.hasNext()) {
571             Integer val = itr.next();
572             if (val.intValue() == index) {
573                 return true;
574             }
575         }
576         return false;
577     }
578 
paintVSB(Graphics g, Color[] colors, Rectangle bounds)579     private void paintVSB(Graphics g, Color[] colors, Rectangle bounds) {
580         int height = bounds.height - 2*BORDER_WIDTH - (hsbVis ? (SCROLLBAR_WIDTH-2) : 0);
581         Graphics ng = g.create();
582 
583         g.setColor(colors[XComponentPeer.BACKGROUND_COLOR]);
584         try {
585             ng.translate(bounds.width - BORDER_WIDTH - SCROLLBAR_WIDTH,
586                          BORDER_WIDTH);
587             // Update scrollbar's size
588             vsb.setSize(SCROLLBAR_WIDTH, bounds.height);
589             vsb.paint(ng, colors, true);
590         } finally {
591             ng.dispose();
592         }
593     }
594 
paintHSB(Graphics g, Color[] colors, Rectangle bounds)595     private void paintHSB(Graphics g, Color[] colors, Rectangle bounds) {
596 
597     }
598 
599     /*
600      * Helper method for Components with integrated scrollbars.
601      * Pass in the vertical and horizontal scroll bar (or null for none/hidden)
602      * and the MouseWheelEvent, and the appropriate scrollbar will be scrolled
603      * correctly.
604      * Returns whether or not scrolling actually took place.  This will indicate
605      * whether or not repainting is required.
606      */
doWheelScroll(XVerticalScrollbar vsb, XHorizontalScrollbar hsb, MouseWheelEvent e)607     static boolean doWheelScroll(XVerticalScrollbar vsb,
608                                      XHorizontalScrollbar hsb,
609                                      MouseWheelEvent e) {
610         XScrollbar scroll = null;
611         int wheelRotation;
612 
613         // Determine which, if any, sb to scroll
614         if (vsb != null) {
615             scroll = vsb;
616         }
617         else if (hsb != null) {
618             scroll = hsb;
619         }
620         else { // Neither scrollbar is showing
621             return false;
622         }
623 
624         wheelRotation = e.getWheelRotation();
625 
626         // Check if scroll is necessary
627         if ((wheelRotation < 0 && scroll.getValue() > scroll.getMinimum()) ||
628             (wheelRotation > 0 && scroll.getValue() < scroll.getMaximum()) ||
629             wheelRotation != 0) {
630 
631             int type = e.getScrollType();
632             int incr;
633             if (type == MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
634                 incr = wheelRotation * scroll.getBlockIncrement();
635             }
636             else { // type is WHEEL_UNIT_SCROLL
637                 incr = e.getUnitsToScroll() * scroll.getUnitIncrement();
638             }
639             scroll.setValue(scroll.getValue() + incr);
640             return true;
641         }
642         return false;
643     }
644 
645     /*
646      * Helper method for XChoicePeer with integrated vertical scrollbar.
647      * Start or stop vertical scrolling when mouse dragged in / out the area of the list if it's required
648      * Restoring Motif behavior
649      * See 6243382 for more information
650      */
trackMouseDraggedScroll(int mouseX, int mouseY, int listWidth, int listHeight)651     void trackMouseDraggedScroll(int mouseX, int mouseY, int listWidth, int listHeight){
652 
653         if (!mouseDraggedOutVertically){
654             if (vsb.beforeThumb(mouseX, mouseY)) {
655                 vsb.setMode(AdjustmentEvent.UNIT_DECREMENT);
656             } else {
657                 vsb.setMode(AdjustmentEvent.UNIT_INCREMENT);
658             }
659         }
660 
661         if(!mouseDraggedOutVertically && (mouseY < 0 || mouseY >= listHeight)){
662             mouseDraggedOutVertically = true;
663             vsb.startScrollingInstance();
664         }
665 
666         if (mouseDraggedOutVertically && mouseY >= 0 && mouseY < listHeight && mouseX >= 0 && mouseX < listWidth){
667             mouseDraggedOutVertically = false;
668             vsb.stopScrollingInstance();
669         }
670     }
671 
672     /*
673      * Helper method for XChoicePeer with integrated vertical scrollbar.
674      * Stop vertical scrolling when mouse released in / out the area of the list if it's required
675      * Restoring Motif behavior
676      * see 6243382 for more information
677      */
trackMouseReleasedScroll()678     void trackMouseReleasedScroll(){
679 
680         if (mouseDraggedOutVertically){
681             mouseDraggedOutVertically = false;
682             vsb.stopScrollingInstance();
683         }
684 
685     }
686 }
687