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