1 /* 2 * Copyright (c) 1998, 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 javax.swing.plaf.metal; 27 28 import java.awt.*; 29 import javax.swing.*; 30 import javax.swing.border.*; 31 import javax.swing.plaf.basic.*; 32 33 34 /** 35 * Metal's split pane divider 36 * <p> 37 * <strong>Warning:</strong> 38 * Serialized objects of this class will not be compatible with 39 * future Swing releases. The current serialization support is 40 * appropriate for short term storage or RMI between applications running 41 * the same version of Swing. As of 1.4, support for long term storage 42 * of all JavaBeans™ 43 * has been added to the <code>java.beans</code> package. 44 * Please see {@link java.beans.XMLEncoder}. 45 * 46 * @author Steve Wilson 47 * @author Ralph kar 48 */ 49 class MetalSplitPaneDivider extends BasicSplitPaneDivider 50 { 51 private MetalBumps bumps = new MetalBumps(10, 10, 52 MetalLookAndFeel.getControlHighlight(), 53 MetalLookAndFeel.getControlDarkShadow(), 54 MetalLookAndFeel.getControl() ); 55 56 private MetalBumps focusBumps = new MetalBumps(10, 10, 57 MetalLookAndFeel.getPrimaryControlHighlight(), 58 MetalLookAndFeel.getPrimaryControlDarkShadow(), 59 UIManager.getColor("SplitPane.dividerFocusColor")); 60 61 private int inset = 2; 62 63 private Color controlColor = MetalLookAndFeel.getControl(); 64 private Color primaryControlColor = UIManager.getColor( 65 "SplitPane.dividerFocusColor"); 66 67 public MetalSplitPaneDivider(BasicSplitPaneUI ui) { 68 super(ui); 69 } 70 71 public void paint(Graphics g) { 72 MetalBumps usedBumps; 73 if (splitPane.hasFocus()) { 74 usedBumps = focusBumps; 75 g.setColor(primaryControlColor); 76 } 77 else { 78 usedBumps = bumps; 79 g.setColor(controlColor); 80 } 81 Rectangle clip = g.getClipBounds(); 82 Insets insets = getInsets(); 83 g.fillRect(clip.x, clip.y, clip.width, clip.height); 84 Dimension size = getSize(); 85 size.width -= inset * 2; 86 size.height -= inset * 2; 87 int drawX = inset; 88 int drawY = inset; 89 if (insets != null) { 90 size.width -= (insets.left + insets.right); 91 size.height -= (insets.top + insets.bottom); 92 drawX += insets.left; 93 drawY += insets.top; 94 } 95 usedBumps.setBumpArea(size); 96 usedBumps.paintIcon(this, g, drawX, drawY); 97 super.paint(g); 98 } 99 100 /** 101 * Creates and return an instance of JButton that can be used to 102 * collapse the left component in the metal split pane. 103 */ 104 protected JButton createLeftOneTouchButton() { 105 JButton b = new JButton() { 106 // Sprite buffer for the arrow image of the left button 107 int[][] buffer = {{0, 0, 0, 2, 2, 0, 0, 0, 0}, 108 {0, 0, 2, 1, 1, 1, 0, 0, 0}, 109 {0, 2, 1, 1, 1, 1, 1, 0, 0}, 110 {2, 1, 1, 1, 1, 1, 1, 1, 0}, 111 {0, 3, 3, 3, 3, 3, 3, 3, 3}}; 112 113 public void setBorder(Border b) { 114 } 115 116 public void paint(Graphics g) { 117 JSplitPane splitPane = getSplitPaneFromSuper(); 118 if(splitPane != null) { 119 int oneTouchSize = getOneTouchSizeFromSuper(); 120 int orientation = getOrientationFromSuper(); 121 int blockSize = Math.min(getDividerSize(), 122 oneTouchSize); 123 124 // Initialize the color array 125 Color[] colors = { 126 this.getBackground(), 127 MetalLookAndFeel.getPrimaryControlDarkShadow(), 128 MetalLookAndFeel.getPrimaryControlInfo(), 129 MetalLookAndFeel.getPrimaryControlHighlight()}; 130 131 // Fill the background first ... 132 g.setColor(this.getBackground()); 133 if (isOpaque()) { 134 g.fillRect(0, 0, this.getWidth(), 135 this.getHeight()); 136 } 137 138 // ... then draw the arrow. 139 if (getModel().isPressed()) { 140 // Adjust color mapping for pressed button state 141 colors[1] = colors[2]; 142 } 143 if(orientation == JSplitPane.VERTICAL_SPLIT) { 144 // Draw the image for a vertical split 145 for (int i=1; i<=buffer[0].length; i++) { 146 for (int j=1; j<blockSize; j++) { 147 if (buffer[j-1][i-1] == 0) { 148 continue; 149 } 150 else { 151 g.setColor( 152 colors[buffer[j-1][i-1]]); 153 } 154 g.drawLine(i, j, i, j); 155 } 156 } 157 } 158 else { 159 // Draw the image for a horizontal split 160 // by simply swaping the i and j axis. 161 // Except the drawLine() call this code is 162 // identical to the code block above. This was done 163 // in order to remove the additional orientation 164 // check for each pixel. 165 for (int i=1; i<=buffer[0].length; i++) { 166 for (int j=1; j<blockSize; j++) { 167 if (buffer[j-1][i-1] == 0) { 168 // Nothing needs 169 // to be drawn 170 continue; 171 } 172 else { 173 // Set the color from the 174 // color map 175 g.setColor( 176 colors[buffer[j-1][i-1]]); 177 } 178 // Draw a pixel 179 g.drawLine(j, i, j, i); 180 } 181 } 182 } 183 } 184 } 185 186 // Don't want the button to participate in focus traversable. 187 public boolean isFocusTraversable() { 188 return false; 189 } 190 }; 191 b.setRequestFocusEnabled(false); 192 b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 193 b.setFocusPainted(false); 194 b.setBorderPainted(false); 195 maybeMakeButtonOpaque(b); 196 return b; 197 } 198 199 /** 200 * If necessary <code>c</code> is made opaque. 201 */ 202 private void maybeMakeButtonOpaque(JComponent c) { 203 Object opaque = UIManager.get("SplitPane.oneTouchButtonsOpaque"); 204 if (opaque != null) { 205 c.setOpaque(((Boolean)opaque).booleanValue()); 206 } 207 } 208 209 /** 210 * Creates and return an instance of JButton that can be used to 211 * collapse the right component in the metal split pane. 212 */ 213 protected JButton createRightOneTouchButton() { 214 JButton b = new JButton() { 215 // Sprite buffer for the arrow image of the right button 216 int[][] buffer = {{2, 2, 2, 2, 2, 2, 2, 2}, 217 {0, 1, 1, 1, 1, 1, 1, 3}, 218 {0, 0, 1, 1, 1, 1, 3, 0}, 219 {0, 0, 0, 1, 1, 3, 0, 0}, 220 {0, 0, 0, 0, 3, 0, 0, 0}}; 221 222 public void setBorder(Border border) { 223 } 224 225 public void paint(Graphics g) { 226 JSplitPane splitPane = getSplitPaneFromSuper(); 227 if(splitPane != null) { 228 int oneTouchSize = getOneTouchSizeFromSuper(); 229 int orientation = getOrientationFromSuper(); 230 int blockSize = Math.min(getDividerSize(), 231 oneTouchSize); 232 233 // Initialize the color array 234 Color[] colors = { 235 this.getBackground(), 236 MetalLookAndFeel.getPrimaryControlDarkShadow(), 237 MetalLookAndFeel.getPrimaryControlInfo(), 238 MetalLookAndFeel.getPrimaryControlHighlight()}; 239 240 // Fill the background first ... 241 g.setColor(this.getBackground()); 242 if (isOpaque()) { 243 g.fillRect(0, 0, this.getWidth(), 244 this.getHeight()); 245 } 246 247 // ... then draw the arrow. 248 if (getModel().isPressed()) { 249 // Adjust color mapping for pressed button state 250 colors[1] = colors[2]; 251 } 252 if(orientation == JSplitPane.VERTICAL_SPLIT) { 253 // Draw the image for a vertical split 254 for (int i=1; i<=buffer[0].length; i++) { 255 for (int j=1; j<blockSize; j++) { 256 if (buffer[j-1][i-1] == 0) { 257 continue; 258 } 259 else { 260 g.setColor( 261 colors[buffer[j-1][i-1]]); 262 } 263 g.drawLine(i, j, i, j); 264 } 265 } 266 } 267 else { 268 // Draw the image for a horizontal split 269 // by simply swaping the i and j axis. 270 // Except the drawLine() call this code is 271 // identical to the code block above. This was done 272 // in order to remove the additional orientation 273 // check for each pixel. 274 for (int i=1; i<=buffer[0].length; i++) { 275 for (int j=1; j<blockSize; j++) { 276 if (buffer[j-1][i-1] == 0) { 277 // Nothing needs 278 // to be drawn 279 continue; 280 } 281 else { 282 // Set the color from the 283 // color map 284 g.setColor( 285 colors[buffer[j-1][i-1]]); 286 } 287 // Draw a pixel 288 g.drawLine(j, i, j, i); 289 } 290 } 291 } 292 } 293 } 294 295 // Don't want the button to participate in focus traversable. 296 public boolean isFocusTraversable() { 297 return false; 298 } 299 }; 300 b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 301 b.setFocusPainted(false); 302 b.setBorderPainted(false); 303 b.setRequestFocusEnabled(false); 304 maybeMakeButtonOpaque(b); 305 return b; 306 } 307 308 /** 309 * Used to layout a MetalSplitPaneDivider. Layout for the divider 310 * involves appropriately moving the left/right buttons around. 311 * <p> 312 * This class should be treated as a "protected" inner class. 313 * Instantiate it only within subclasses of MetalSplitPaneDivider. 314 */ 315 public class MetalDividerLayout implements LayoutManager { 316 317 // NOTE NOTE NOTE NOTE NOTE 318 // This class is no longer used, the functionality has 319 // been rolled into BasicSplitPaneDivider.DividerLayout as a 320 // defaults property 321 322 public void layoutContainer(Container c) { 323 JButton leftButton = getLeftButtonFromSuper(); 324 JButton rightButton = getRightButtonFromSuper(); 325 JSplitPane splitPane = getSplitPaneFromSuper(); 326 int orientation = getOrientationFromSuper(); 327 int oneTouchSize = getOneTouchSizeFromSuper(); 328 int oneTouchOffset = getOneTouchOffsetFromSuper(); 329 Insets insets = getInsets(); 330 331 // This layout differs from the one used in BasicSplitPaneDivider. 332 // It does not center justify the oneTouchExpadable buttons. 333 // This was necessary in order to meet the spec of the Metal 334 // splitpane divider. 335 if (leftButton != null && rightButton != null && 336 c == MetalSplitPaneDivider.this) { 337 if (splitPane.isOneTouchExpandable()) { 338 if (orientation == JSplitPane.VERTICAL_SPLIT) { 339 int extraY = (insets != null) ? insets.top : 0; 340 int blockSize = getDividerSize(); 341 342 if (insets != null) { 343 blockSize -= (insets.top + insets.bottom); 344 } 345 blockSize = Math.min(blockSize, oneTouchSize); 346 leftButton.setBounds(oneTouchOffset, extraY, 347 blockSize * 2, blockSize); 348 rightButton.setBounds(oneTouchOffset + 349 oneTouchSize * 2, extraY, 350 blockSize * 2, blockSize); 351 } 352 else { 353 int blockSize = getDividerSize(); 354 int extraX = (insets != null) ? insets.left : 0; 355 356 if (insets != null) { 357 blockSize -= (insets.left + insets.right); 358 } 359 blockSize = Math.min(blockSize, oneTouchSize); 360 leftButton.setBounds(extraX, oneTouchOffset, 361 blockSize, blockSize * 2); 362 rightButton.setBounds(extraX, oneTouchOffset + 363 oneTouchSize * 2, blockSize, 364 blockSize * 2); 365 } 366 } 367 else { 368 leftButton.setBounds(-5, -5, 1, 1); 369 rightButton.setBounds(-5, -5, 1, 1); 370 } 371 } 372 } 373 374 public Dimension minimumLayoutSize(Container c) { 375 return new Dimension(0,0); 376 } 377 378 public Dimension preferredLayoutSize(Container c) { 379 return new Dimension(0, 0); 380 } 381 382 public void removeLayoutComponent(Component c) {} 383 384 public void addLayoutComponent(String string, Component c) {} 385 } 386 387 /* 388 * The following methods only exist in order to be able to access protected 389 * members in the superclass, because these are otherwise not available 390 * in any inner class. 391 */ 392 393 int getOneTouchSizeFromSuper() { 394 return BasicSplitPaneDivider.ONE_TOUCH_SIZE; 395 } 396 397 int getOneTouchOffsetFromSuper() { 398 return BasicSplitPaneDivider.ONE_TOUCH_OFFSET; 399 } 400 401 int getOrientationFromSuper() { 402 return super.orientation; 403 } 404 405 JSplitPane getSplitPaneFromSuper() { 406 return super.splitPane; 407 } 408 409 JButton getLeftButtonFromSuper() { 410 return super.leftButton; 411 } 412 413 JButton getRightButtonFromSuper() { 414 return super.rightButton; 415 } 416 }