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