1 /* 2 * Copyright (c) 1997, 2020, 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 com.sun.java.swing.plaf.motif; 27 28 import java.awt.Color; 29 import java.awt.Cursor; 30 import java.awt.Dimension; 31 import java.awt.Graphics; 32 import java.awt.Insets; 33 import java.awt.event.MouseEvent; 34 35 import javax.swing.JSplitPane; 36 import javax.swing.UIManager; 37 import javax.swing.plaf.basic.BasicSplitPaneDivider; 38 import javax.swing.plaf.basic.BasicSplitPaneUI; 39 40 /** 41 * Divider used for Motif split pane. 42 * 43 * @author Jeff Dinkins 44 */ 45 @SuppressWarnings("serial") // Same-version serialization only 46 public class MotifSplitPaneDivider extends BasicSplitPaneDivider 47 { 48 /** 49 * Default cursor, supers is package private, so we have to have one 50 * too. 51 */ 52 private static final Cursor defaultCursor = 53 Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); 54 55 56 public static final int minimumThumbSize = 6; 57 public static final int defaultDividerSize = 18; 58 59 protected static final int pad = 6; 60 61 private int hThumbOffset = 30; 62 private int vThumbOffset = 40; 63 protected int hThumbWidth = 12; 64 protected int hThumbHeight = 18; 65 protected int vThumbWidth = 18; 66 protected int vThumbHeight = 12; 67 68 protected Color highlightColor; 69 protected Color shadowColor; 70 protected Color focusedColor; 71 72 /** 73 * Creates a new Motif SplitPaneDivider 74 */ MotifSplitPaneDivider(BasicSplitPaneUI ui)75 public MotifSplitPaneDivider(BasicSplitPaneUI ui) { 76 super(ui); 77 highlightColor = UIManager.getColor("SplitPane.highlight"); 78 shadowColor = UIManager.getColor("SplitPane.shadow"); 79 focusedColor = UIManager.getColor("SplitPane.activeThumb"); 80 setDividerSize(hThumbWidth + pad); 81 } 82 83 /** 84 * overrides to hardcode the size of the divider 85 * PENDING(jeff) - rewrite JSplitPane so that this ins't needed 86 */ setDividerSize(int newSize)87 public void setDividerSize(int newSize) { 88 Insets insets = getInsets(); 89 int borderSize = 0; 90 if (getBasicSplitPaneUI().getOrientation() == 91 JSplitPane.HORIZONTAL_SPLIT) { 92 if (insets != null) { 93 borderSize = insets.left + insets.right; 94 } 95 } 96 else if (insets != null) { 97 borderSize = insets.top + insets.bottom; 98 } 99 if (newSize < pad + minimumThumbSize + borderSize) { 100 setDividerSize(pad + minimumThumbSize + borderSize); 101 } else { 102 vThumbHeight = hThumbWidth = newSize - pad - borderSize; 103 super.setDividerSize(newSize); 104 } 105 } 106 107 /** 108 * Paints the divider. 109 */ 110 // PENDING(jeff) - the thumb's location and size is currently hard coded. 111 // It should be dynamic. paint(Graphics g)112 public void paint(Graphics g) { 113 Color bgColor = getBackground(); 114 Dimension size = getSize(); 115 116 // fill 117 g.setColor(getBackground()); 118 g.fillRect(0, 0, size.width, size.height); 119 120 if(getBasicSplitPaneUI().getOrientation() == 121 JSplitPane.HORIZONTAL_SPLIT) { 122 int center = size.width/2; 123 int x = center - hThumbWidth/2; 124 int y = hThumbOffset; 125 126 // split line 127 g.setColor(shadowColor); 128 g.drawLine(center-1, 0, center-1, size.height); 129 130 g.setColor(highlightColor); 131 g.drawLine(center, 0, center, size.height); 132 133 // draw thumb 134 g.setColor((splitPane.hasFocus()) ? focusedColor : 135 getBackground()); 136 g.fillRect(x+1, y+1, hThumbWidth-2, hThumbHeight-1); 137 138 g.setColor(highlightColor); 139 g.drawLine(x, y, x+hThumbWidth-1, y); // top 140 g.drawLine(x, y+1, x, y+hThumbHeight-1); // left 141 142 g.setColor(shadowColor); 143 g.drawLine(x+1, y+hThumbHeight-1, 144 x+hThumbWidth-1, y+hThumbHeight-1); // bottom 145 g.drawLine(x+hThumbWidth-1, y+1, 146 x+hThumbWidth-1, y+hThumbHeight-2); // right 147 148 } else { 149 int center = size.height/2; 150 int x = size.width - vThumbOffset; 151 int y = size.height/2 - vThumbHeight/2; 152 153 // split line 154 g.setColor(shadowColor); 155 g.drawLine(0, center-1, size.width, center-1); 156 157 g.setColor(highlightColor); 158 g.drawLine(0, center, size.width, center); 159 160 // draw thumb 161 g.setColor((splitPane.hasFocus()) ? focusedColor : 162 getBackground()); 163 g.fillRect(x+1, y+1, vThumbWidth-1, vThumbHeight-1); 164 165 g.setColor(highlightColor); 166 g.drawLine(x, y, x+vThumbWidth, y); // top 167 g.drawLine(x, y+1, x, y+vThumbHeight); // left 168 169 g.setColor(shadowColor); 170 g.drawLine(x+1, y+vThumbHeight, 171 x+vThumbWidth, y+vThumbHeight); // bottom 172 g.drawLine(x+vThumbWidth, y+1, 173 x+vThumbWidth, y+vThumbHeight-1); // right 174 } 175 super.paint(g); 176 177 } 178 179 /** 180 * The minimums size is the same as the preferredSize 181 */ getMinimumSize()182 public Dimension getMinimumSize() { 183 return getPreferredSize(); 184 } 185 186 /** 187 * Sets the SplitPaneUI that is using the receiver. This is completely 188 * overriden from super to create a different MouseHandler. 189 */ setBasicSplitPaneUI(BasicSplitPaneUI newUI)190 public void setBasicSplitPaneUI(BasicSplitPaneUI newUI) { 191 if (splitPane != null) { 192 splitPane.removePropertyChangeListener(this); 193 if (mouseHandler != null) { 194 splitPane.removeMouseListener(mouseHandler); 195 splitPane.removeMouseMotionListener(mouseHandler); 196 removeMouseListener(mouseHandler); 197 removeMouseMotionListener(mouseHandler); 198 mouseHandler = null; 199 } 200 } 201 splitPaneUI = newUI; 202 if (newUI != null) { 203 splitPane = newUI.getSplitPane(); 204 if (splitPane != null) { 205 if (mouseHandler == null) mouseHandler=new MotifMouseHandler(); 206 splitPane.addMouseListener(mouseHandler); 207 splitPane.addMouseMotionListener(mouseHandler); 208 addMouseListener(mouseHandler); 209 addMouseMotionListener(mouseHandler); 210 splitPane.addPropertyChangeListener(this); 211 if (splitPane.isOneTouchExpandable()) { 212 oneTouchExpandableChanged(); 213 } 214 } 215 } 216 else { 217 splitPane = null; 218 } 219 } 220 221 /** 222 * Returns true if the point at <code>x</code>, <code>y</code> 223 * is inside the thumb. 224 */ isInThumb(int x, int y)225 private boolean isInThumb(int x, int y) { 226 Dimension size = getSize(); 227 int thumbX; 228 int thumbY; 229 int thumbWidth; 230 int thumbHeight; 231 232 if (getBasicSplitPaneUI().getOrientation() == 233 JSplitPane.HORIZONTAL_SPLIT) { 234 int center = size.width/2; 235 thumbX = center - hThumbWidth/2; 236 thumbY = hThumbOffset; 237 thumbWidth = hThumbWidth; 238 thumbHeight = hThumbHeight; 239 } 240 else { 241 int center = size.height/2; 242 thumbX = size.width - vThumbOffset; 243 thumbY = size.height/2 - vThumbHeight/2; 244 thumbWidth = vThumbWidth; 245 thumbHeight = vThumbHeight; 246 } 247 return (x >= thumbX && x < (thumbX + thumbWidth) && 248 y >= thumbY && y < (thumbY + thumbHeight)); 249 } 250 251 // 252 // Two methods are exposed so that MotifMouseHandler can see the 253 // superclass protected ivars 254 // 255 getDragger()256 private DragController getDragger() { 257 return dragger; 258 } 259 getSplitPane()260 private JSplitPane getSplitPane() { 261 return splitPane; 262 } 263 264 265 /** 266 * MouseHandler is subclassed to only pass off to super if the mouse 267 * is in the thumb. Motif only allows dragging when the thumb is clicked 268 * in. 269 */ 270 private class MotifMouseHandler extends MouseHandler { mousePressed(MouseEvent e)271 public void mousePressed(MouseEvent e) { 272 // Constrain the mouse pressed to the thumb. 273 if (e.getSource() == MotifSplitPaneDivider.this && 274 getDragger() == null && getSplitPane().isEnabled() && 275 isInThumb(e.getX(), e.getY())) { 276 super.mousePressed(e); 277 } 278 } 279 mouseMoved(MouseEvent e)280 public void mouseMoved(MouseEvent e) { 281 if (getDragger() != null) { 282 return; 283 } 284 if (!isInThumb(e.getX(), e.getY())) { 285 if (getCursor() != defaultCursor) { 286 setCursor(defaultCursor); 287 } 288 return; 289 } 290 super.mouseMoved(e); 291 } 292 } 293 } 294