1 /* 2 * Copyright (c) 2002, 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.*; 30 import java.awt.peer.*; 31 import java.lang.reflect.*; 32 33 import sun.awt.AWTAccessor; 34 35 class XScrollPanePeer extends XComponentPeer implements ScrollPanePeer, XScrollbarClient { 36 37 public static final int MARGIN = 1; 38 public static final int SCROLLBAR; 39 public static final int SPACE = 2; 40 public static final int SCROLLBAR_INSET = 2; 41 42 public static final int VERTICAL = 1 << 0; 43 public static final int HORIZONTAL = 1 << 1; 44 45 static { 46 SCROLLBAR = XToolkit.getUIDefaults().getInt("ScrollBar.defaultWidth"); 47 } 48 49 XVerticalScrollbar vsb; 50 XHorizontalScrollbar hsb; 51 XWindow clip; 52 53 int active=VERTICAL; 54 int hsbSpace; 55 int vsbSpace; 56 57 static class XScrollPaneContentWindow extends XWindow { 58 XScrollPaneContentWindow(ScrollPane target, long parentWindow) { 59 super(target, parentWindow); 60 } 61 public String getWMName() { 62 return "ScrollPane content"; 63 } 64 } 65 66 XScrollPanePeer(ScrollPane target) { 67 super(target); 68 69 // Create the clip window. The field "clip" must be null when 70 // we call winCreate, or the parent of clip will be set to itself! 71 clip = null; 72 73 74 XWindow c = new XScrollPaneContentWindow(target,window); 75 clip = c; 76 77 vsb = new XVerticalScrollbar(this); 78 79 hsb = new XHorizontalScrollbar(this); 80 81 if (target.getScrollbarDisplayPolicy() == ScrollPane.SCROLLBARS_ALWAYS) { 82 vsbSpace = hsbSpace = SCROLLBAR; 83 } else { 84 vsbSpace = hsbSpace = 0; 85 } 86 87 int unitIncrement = 1; 88 Adjustable vAdjustable = target.getVAdjustable(); 89 if (vAdjustable != null){ 90 unitIncrement = vAdjustable.getUnitIncrement(); 91 } 92 int h = height-hsbSpace; 93 vsb.setValues(0, h, 0, h, unitIncrement, Math.max(1, (int)(h * 0.90))); 94 vsb.setSize(vsbSpace-SCROLLBAR_INSET, h); 95 96 unitIncrement = 1; 97 Adjustable hAdjustable = target.getHAdjustable(); 98 if (hAdjustable != null){ 99 unitIncrement = hAdjustable.getUnitIncrement(); 100 } 101 int w = width - vsbSpace; 102 hsb.setValues(0, w, 0, w, unitIncrement, Math.max(1, (int)(w * 0.90))); 103 hsb.setSize(w, hsbSpace-SCROLLBAR_INSET); 104 105 setViewportSize(); 106 clip.xSetVisible(true); 107 108 109 } 110 111 public long getContentWindow() 112 { 113 return (clip == null) ? window : clip.getWindow(); 114 } 115 116 public void setBounds(int x, int y, int w, int h, int op) { 117 super.setBounds(x, y, w, h, op); 118 119 if (clip == null) return; 120 setScrollbarSpace(); 121 setViewportSize(); 122 repaint(); 123 } 124 125 public Insets getInsets() { 126 return new Insets(MARGIN, MARGIN, MARGIN+hsbSpace, MARGIN+vsbSpace); 127 } 128 129 public int getHScrollbarHeight() { 130 return SCROLLBAR; 131 } 132 133 public int getVScrollbarWidth() { 134 return SCROLLBAR; 135 } 136 137 public void childResized(int w, int h) { 138 if (setScrollbarSpace()) { 139 setViewportSize(); 140 } 141 repaint(); 142 } 143 144 @SuppressWarnings("deprecation") 145 Dimension getChildSize() { 146 ScrollPane sp = (ScrollPane)target; 147 if (sp.countComponents() > 0) { 148 Component c = sp.getComponent(0); 149 return c.size(); 150 } else { 151 return new Dimension(0, 0); 152 } 153 } 154 155 @SuppressWarnings("deprecation") 156 boolean setScrollbarSpace() { 157 ScrollPane sp = (ScrollPane)target; 158 boolean changed = false; 159 int sbDisplayPolicy = sp.getScrollbarDisplayPolicy(); 160 161 if (sbDisplayPolicy == ScrollPane.SCROLLBARS_NEVER) { 162 return changed; 163 } 164 Dimension cSize = getChildSize(); 165 166 if (sbDisplayPolicy == ScrollPane.SCROLLBARS_AS_NEEDED) { 167 int oldHsbSpace = hsbSpace; 168 int oldVsbSpace = vsbSpace; 169 hsbSpace = (cSize.width <= (width - 2*MARGIN) ? 0 : SCROLLBAR); 170 vsbSpace = (cSize.height <= (height - 2*MARGIN) ? 0 : SCROLLBAR); 171 172 if (hsbSpace == 0 && vsbSpace != 0) { 173 hsbSpace = (cSize.width <= (width - SCROLLBAR - 2*MARGIN) ? 0 : SCROLLBAR); 174 } 175 if (vsbSpace == 0 && hsbSpace != 0) { 176 vsbSpace = (cSize.height <= (height - SCROLLBAR - 2*MARGIN) ? 0 : SCROLLBAR); 177 } 178 if (oldHsbSpace != hsbSpace || oldVsbSpace != vsbSpace) { 179 changed = true; 180 } 181 } 182 if (vsbSpace > 0) { 183 int vis = height - (2*MARGIN) - hsbSpace; 184 int max = Math.max(cSize.height, vis); 185 vsb.setValues(vsb.getValue(), vis, 0, max); 186 vsb.setBlockIncrement((int)(vsb.getVisibleAmount() * .90)); 187 vsb.setSize(vsbSpace-SCROLLBAR_INSET, height-hsbSpace); 188 // Adjustable vadj = sp.getVAdjustable(); 189 // vadj.setVisibleAmount(vsb.vis); 190 // vadj.setMaximum(vsb.max); 191 // vadj.setBlockIncrement(vsb.page); 192 } 193 if (hsbSpace > 0) { 194 int vis = width - (2*MARGIN) - vsbSpace; 195 int max = Math.max(cSize.width, vis); 196 hsb.setValues(hsb.getValue(), vis, 0, max); 197 hsb.setBlockIncrement((int)(hsb.getVisibleAmount() * .90)); 198 hsb.setSize(width-vsbSpace, hsbSpace-SCROLLBAR_INSET); 199 // Adjustable hadj = sp.getHAdjustable(); 200 // hadj.setVisibleAmount(hsb.vis); 201 // hadj.setMaximum(hsb.max); 202 // hadj.setBlockIncrement(hsb.page); 203 } 204 205 // Check to see if we hid either of the scrollbars but left 206 // ourselves scrolled off of the top and/or right of the pane. 207 // If we did, we need to scroll to the top and/or right of 208 // the pane to make it visible. 209 // 210 // Reminder: see if there is a better place to put this code. 211 boolean must_scroll = false; 212 213 // Get the point at which the ScrollPane is currently located 214 // if number of components > 0 215 Point p = new Point(0, 0); 216 217 if (((ScrollPane)target).getComponentCount() > 0){ 218 219 p = ((ScrollPane)target).getComponent(0).location(); 220 221 if ((vsbSpace == 0) && (p.y < 0)) { 222 p.y = 0; 223 must_scroll = true; 224 } 225 226 if ((hsbSpace == 0) && (p.x < 0)) { 227 p.x = 0; 228 must_scroll = true; 229 } 230 } 231 232 if (must_scroll) 233 scroll(x, y, VERTICAL | HORIZONTAL); 234 235 return changed; 236 } 237 238 void setViewportSize() { 239 clip.xSetBounds(MARGIN, MARGIN, 240 width - (2*MARGIN) - vsbSpace, 241 height - (2*MARGIN) - hsbSpace); 242 } 243 244 public void setUnitIncrement(Adjustable adj, int u) { 245 if (adj.getOrientation() == Adjustable.VERTICAL) { 246 vsb.setUnitIncrement(u); 247 } else { 248 // HORIZONTAL 249 hsb.setUnitIncrement(u); 250 } 251 } 252 253 public void setValue(Adjustable adj, int v) { 254 if (adj.getOrientation() == Adjustable.VERTICAL) { 255 scroll(-1, v, VERTICAL); 256 } else { 257 // HORIZONTAL 258 scroll(v, -1, HORIZONTAL); 259 } 260 } 261 262 public void setScrollPosition(int x, int y) { 263 scroll(x, y, VERTICAL | HORIZONTAL); 264 } 265 266 void scroll(int x, int y, int flag) { 267 scroll(x, y, flag, AdjustmentEvent.TRACK); 268 } 269 270 /** 271 * Scroll the contents to position x, y 272 */ 273 @SuppressWarnings("deprecation") 274 void scroll(int x, int y, int flag, int type) { 275 checkSecurity(); 276 ScrollPane sp = (ScrollPane)target; 277 Component c = getScrollChild(); 278 if (c == null) { 279 return; 280 } 281 int sx, sy; 282 Color[] colors = getGUIcolors(); 283 284 if (sp.getScrollbarDisplayPolicy() == ScrollPane.SCROLLBARS_NEVER) { 285 sx = -x; 286 sy = -y; 287 } else { 288 Point p = c.location(); 289 sx = p.x; 290 sy = p.y; 291 292 if ((flag & HORIZONTAL) != 0) { 293 hsb.setValue(Math.min(x, hsb.getMaximum()-hsb.getVisibleAmount())); 294 ScrollPaneAdjustable hadj = (ScrollPaneAdjustable)sp.getHAdjustable(); 295 setAdjustableValue(hadj, hsb.getValue(), type); 296 sx = -(hsb.getValue()); 297 Graphics g = getGraphics(); 298 if (g != null) { 299 try { 300 paintHorScrollbar(g, colors, true); 301 } finally { 302 g.dispose(); 303 } 304 } 305 } 306 if ((flag & VERTICAL) != 0) { 307 vsb.setValue(Math.min(y, vsb.getMaximum() - vsb.getVisibleAmount())); 308 ScrollPaneAdjustable vadj = (ScrollPaneAdjustable)sp.getVAdjustable(); 309 setAdjustableValue(vadj, vsb.getValue(), type); 310 sy = -(vsb.getValue()); 311 Graphics g = getGraphics(); 312 if (g != null) { 313 try { 314 paintVerScrollbar(g, colors, true); 315 } finally { 316 g.dispose(); 317 } 318 } 319 } 320 } 321 c.move(sx, sy); 322 } 323 324 private void setAdjustableValue(final ScrollPaneAdjustable adj, final int value, 325 final int type) { 326 AWTAccessor.getScrollPaneAdjustableAccessor().setTypedValue(adj, value, 327 type); 328 } 329 @Override 330 void paintPeer(final Graphics g) { 331 final Color[] colors = getGUIcolors(); 332 g.setColor(colors[BACKGROUND_COLOR]); 333 final int h = height - hsbSpace; 334 final int w = width - vsbSpace; 335 g.fillRect(0, 0, w, h); 336 // paint rectangular region between scrollbars 337 g.fillRect(w, h, vsbSpace, hsbSpace); 338 if (MARGIN > 0) { 339 draw3DRect(g, colors, 0, 0, w - 1, h - 1, false); 340 } 341 paintScrollBars(g, colors); 342 } 343 private void paintScrollBars(Graphics g, Color[] colors) { 344 if (vsbSpace > 0) { 345 paintVerScrollbar(g, colors, true); 346 // paint the whole scrollbar 347 } 348 349 if (hsbSpace > 0) { 350 paintHorScrollbar(g, colors, true); 351 // paint the whole scrollbar 352 } 353 } 354 void repaintScrollBars() { 355 Graphics g = getGraphics(); 356 Color[] colors = getGUIcolors(); 357 if (g != null) { 358 try { 359 paintScrollBars(g, colors); 360 } finally { 361 g.dispose(); 362 } 363 } 364 } 365 public void repaintScrollbarRequest(XScrollbar sb) { 366 Graphics g = getGraphics(); 367 Color[] colors = getGUIcolors(); 368 if (g != null) { 369 try { 370 if (sb == vsb) { 371 paintVerScrollbar(g, colors, true); 372 } else if (sb == hsb) { 373 paintHorScrollbar(g, colors, true); 374 } 375 } finally { 376 g.dispose(); 377 } 378 } 379 } 380 public void handleEvent(java.awt.AWTEvent e) { 381 super.handleEvent(e); 382 383 int id = e.getID(); 384 switch(id) { 385 case PaintEvent.PAINT: 386 case PaintEvent.UPDATE: 387 repaintScrollBars(); 388 break; 389 } 390 } 391 392 393 /** 394 * Paint the horizontal scrollbar to the screen 395 * 396 * @param g the graphics context to draw into 397 * @param colors the colors used to draw the scrollbar 398 * @param paintAll paint the whole scrollbar if true, just the thumb if false 399 */ 400 void paintHorScrollbar(Graphics g, Color[] colors, boolean paintAll) { 401 if (hsbSpace <= 0) { 402 return; 403 } 404 Graphics ng = g.create(); 405 g.setColor(colors[BACKGROUND_COLOR]); 406 407 // SCROLLBAR is the height of scrollbar area 408 // but the actual scrollbar is SCROLLBAR-SPACE high; 409 // the rest must be filled with background color 410 int w = width - vsbSpace - (2*MARGIN); 411 g.fillRect(MARGIN, height-SCROLLBAR, w, SPACE); 412 g.fillRect(0, height-SCROLLBAR, MARGIN, SCROLLBAR); 413 g.fillRect(MARGIN + w, height-SCROLLBAR, MARGIN, SCROLLBAR); 414 415 try { 416 ng.translate(MARGIN, height - (SCROLLBAR - SPACE)); 417 hsb.paint(ng, colors, paintAll); 418 } 419 finally { 420 ng.dispose(); 421 } 422 423 424 } 425 426 427 428 429 /** 430 * Paint the vertical scrollbar to the screen 431 * 432 * @param g the graphics context to draw into 433 * @param colors the colors used to draw the scrollbar 434 * @param paintAll paint the whole scrollbar if true, just the thumb if false 435 */ 436 void paintVerScrollbar(Graphics g, Color[] colors, boolean paintAll) { 437 if (vsbSpace <= 0) { 438 return; 439 } 440 Graphics ng = g.create(); 441 g.setColor(colors[BACKGROUND_COLOR]); 442 443 // SCROLLBAR is the width of scrollbar area 444 // but the actual scrollbar is SCROLLBAR-SPACE wide; 445 // the rest must be filled with background color 446 int h = height - hsbSpace - (2*MARGIN); 447 g.fillRect(width-SCROLLBAR, MARGIN, SPACE, h); 448 g.fillRect(width-SCROLLBAR, 0, SCROLLBAR, MARGIN); 449 g.fillRect(width-SCROLLBAR, MARGIN+h, SCROLLBAR, MARGIN); 450 451 try { 452 ng.translate(width - (SCROLLBAR - SPACE), MARGIN); 453 vsb.paint(ng, colors, paintAll); 454 } 455 finally { 456 ng.dispose(); 457 } 458 } 459 460 /** 461 * 462 * @see java.awt.event.MouseEvent 463 * MouseEvent.MOUSE_CLICKED 464 * MouseEvent.MOUSE_PRESSED 465 * MouseEvent.MOUSE_RELEASED 466 * MouseEvent.MOUSE_MOVED 467 * MouseEvent.MOUSE_ENTERED 468 * MouseEvent.MOUSE_EXITED 469 * MouseEvent.MOUSE_DRAGGED 470 */ 471 @SuppressWarnings("deprecation") 472 public void handleJavaMouseEvent( MouseEvent mouseEvent ) { 473 super.handleJavaMouseEvent(mouseEvent); 474 int modifiers = mouseEvent.getModifiers(); 475 int id = mouseEvent.getID(); 476 int x = mouseEvent.getX(); 477 int y = mouseEvent.getY(); 478 479 480 // super.handleMouseEvent(mouseEvent); 481 482 if ((modifiers & InputEvent.BUTTON1_MASK) == 0) { 483 return; 484 } 485 486 switch (id) { 487 case MouseEvent.MOUSE_PRESSED: 488 if (inVerticalScrollbar(x,y )) { 489 active = VERTICAL; 490 int h = height - hsbSpace - (2*MARGIN); 491 vsb.handleMouseEvent(id,modifiers,x - (width - SCROLLBAR + SPACE),y-MARGIN); 492 } else if (inHorizontalScrollbar(x, y) ) { 493 active = HORIZONTAL; 494 int w = width - 2*MARGIN - vsbSpace; 495 hsb.handleMouseEvent(id,modifiers,x-MARGIN,y-(height - SCROLLBAR + SPACE)); 496 } 497 break; 498 499 // On mouse up, pass the event through to the scrollbar to stop 500 // scrolling. The x & y passed do not matter. 501 case MouseEvent.MOUSE_RELEASED: 502 // winReleaseCursorFocus(); 503 if (active == VERTICAL) { 504 vsb.handleMouseEvent(id,modifiers,x,y); 505 } else if (active == HORIZONTAL) { 506 hsb.handleMouseEvent(id,modifiers,x,y); 507 } 508 break; 509 510 511 case MouseEvent.MOUSE_DRAGGED: 512 if ((active == VERTICAL)) { 513 int h = height - 2*MARGIN - hsbSpace; 514 vsb.handleMouseEvent(id,modifiers,x-(width - SCROLLBAR + SPACE),y-MARGIN); 515 } else if ((active == HORIZONTAL)) { 516 int w = width - 2*MARGIN - vsbSpace; 517 hsb.handleMouseEvent(id,modifiers,x-MARGIN,y-(height - SCROLLBAR + SPACE)); 518 } 519 break; 520 } 521 } 522 523 /** 524 * return value from the scrollbar 525 */ 526 public void notifyValue(XScrollbar obj, int type, int v, boolean isAdjusting) { 527 if (obj == vsb) { 528 scroll(-1, v, VERTICAL, type); 529 } else if ((XHorizontalScrollbar)obj == hsb) { 530 scroll(v, -1, HORIZONTAL, type); 531 } 532 } 533 534 /** 535 * return true if the x and y position is in the verticalscrollbar 536 */ 537 boolean inVerticalScrollbar(int x, int y) { 538 if (vsbSpace <= 0) { 539 return false; 540 } 541 int h = height - MARGIN - hsbSpace; 542 return (x >= width - (SCROLLBAR - SPACE)) && (x < width) && (y >= MARGIN) && (y < h); 543 } 544 545 /** 546 * return true if the x and y position is in the horizontal scrollbar 547 */ 548 boolean inHorizontalScrollbar(int x, int y) { 549 if (hsbSpace <= 0) { 550 return false; 551 } 552 int w = width - MARGIN - vsbSpace; 553 return (x >= MARGIN) && (x < w) && (y >= height - (SCROLLBAR - SPACE)) && (y < height); 554 } 555 556 private Component getScrollChild() { 557 ScrollPane sp = (ScrollPane)target; 558 Component child = null; 559 try { 560 child = sp.getComponent(0); 561 } catch (ArrayIndexOutOfBoundsException e) { 562 // do nothing. in this case we return null 563 } 564 return child; 565 } 566 567 int vval; 568 int hval; 569 int vmax; 570 int hmax; 571 /* 572 * Print the native component by rendering the Motif look ourselves. 573 * ToDo(aim): needs to query native motif for more accurate size and 574 * color information. 575 */ 576 @SuppressWarnings("deprecation") 577 public void print(Graphics g) { 578 ScrollPane sp = (ScrollPane)target; 579 Dimension d = sp.size(); 580 Color bg = sp.getBackground(); 581 Color fg = sp.getForeground(); 582 Point p = sp.getScrollPosition(); 583 Component c = getScrollChild(); 584 Dimension cd; 585 if (c != null) { 586 cd = c.size(); 587 } else { 588 cd = new Dimension(0, 0); 589 } 590 int sbDisplay = sp.getScrollbarDisplayPolicy(); 591 int vvis, hvis, vmin, hmin, vmax, hmax, vval, hval; 592 593 switch (sbDisplay) { 594 case ScrollPane.SCROLLBARS_NEVER: 595 hsbSpace = vsbSpace = 0; 596 break; 597 case ScrollPane.SCROLLBARS_ALWAYS: 598 hsbSpace = vsbSpace = SCROLLBAR; 599 break; 600 case ScrollPane.SCROLLBARS_AS_NEEDED: 601 hsbSpace = (cd.width <= (d.width - 2*MARGIN)? 0 : SCROLLBAR); 602 vsbSpace = (cd.height <= (d.height - 2*MARGIN)? 0 : SCROLLBAR); 603 604 if (hsbSpace == 0 && vsbSpace != 0) { 605 hsbSpace = (cd.width <= (d.width - SCROLLBAR - 2*MARGIN)? 0 : SCROLLBAR); 606 } 607 if (vsbSpace == 0 && hsbSpace != 0) { 608 vsbSpace = (cd.height <= (d.height - SCROLLBAR - 2*MARGIN)? 0 : SCROLLBAR); 609 } 610 } 611 612 vvis = hvis = vmin = hmin = vmax = hmax = vval = hval = 0; 613 614 if (vsbSpace > 0) { 615 vmin = 0; 616 vvis = d.height - (2*MARGIN) - hsbSpace; 617 vmax = Math.max(cd.height - vvis, 0); 618 vval = p.y; 619 } 620 if (hsbSpace > 0) { 621 hmin = 0; 622 hvis = d.width - (2*MARGIN) - vsbSpace; 623 hmax = Math.max(cd.width - hvis, 0); 624 hval = p.x; 625 } 626 627 // need to be careful to add the margins back in here because 628 // we're drawing the margin border, after all! 629 int w = d.width - vsbSpace; 630 int h = d.height - hsbSpace; 631 632 g.setColor(bg); 633 g.fillRect(0, 0, d.width, d.height); 634 635 if (hsbSpace > 0) { 636 int sbw = d.width - vsbSpace; 637 g.fillRect(1, d.height - SCROLLBAR - 3, sbw - 1, SCROLLBAR - 3); 638 Graphics ng = g.create(); 639 try { 640 ng.translate(0, d.height - (SCROLLBAR - 2)); 641 drawScrollbar(ng, bg, SCROLLBAR - 2, sbw, 642 hmin, hmax, hval, hvis, true); 643 } finally { 644 ng.dispose(); 645 } 646 } 647 if (vsbSpace > 0) { 648 int sbh = d.height - hsbSpace; 649 g.fillRect(d.width - SCROLLBAR - 3, 1, SCROLLBAR - 3, sbh - 1); 650 Graphics ng = g.create(); 651 try { 652 ng.translate(d.width - (SCROLLBAR - 2), 0); 653 drawScrollbar(ng, bg, SCROLLBAR - 2, sbh, 654 vmin, vmax, vval, vvis, false); 655 } finally { 656 ng.dispose(); 657 } 658 } 659 660 draw3DRect(g, bg, 0, 0, w - 1, h - 1, false); 661 662 target.print(g); 663 sp.printComponents(g); 664 } 665 666 }