com.jgoodies.looks.windows.WindowsSplitPaneDivider Maven / Gradle / Ivy
Show all versions of jgoodies-looks Show documentation
/*
* Copyright (c) 2001-2012 JGoodies Karsten Lentzsch. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of JGoodies Karsten Lentzsch nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jgoodies.looks.windows;
import java.awt.*;
import javax.swing.JButton;
import javax.swing.JSplitPane;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;
/**
* Paints nicely rendered one touch triangles.
*
* @author Karsten Lentzsch
* @version $Revision: 1.9 $
*
* @see WindowsSplitPaneUI
*/
final class WindowsSplitPaneDivider extends BasicSplitPaneDivider {
private static final int EXT_ONE_TOUCH_SIZE = 5;
private static final int EXT_ONE_TOUCH_OFFSET = 2;
private static final int EXT_BLOCKSIZE = 6;
/**
* Used to lay out a WindowsSplitPaneDivider. Layout for the divider
* involves appropriately moving the left/right buttons around.
*
* This inner class is marked "public" due to a compiler bug.
* This class should be treated as a "protected" inner class.
* Instantiate it only within subclasses of MetalSplitPaneDivider.
*/
public final class ExtWindowsDividerLayout implements LayoutManager {
@Override
public void layoutContainer(Container c) {
JButton theLeftButton = getLeftButtonFromSuper();
JButton theRightButton = getRightButtonFromSuper();
JSplitPane theSplitPane = getSplitPaneFromSuper();
int theOrientation = getOrientationFromSuper();
int oneTouchSize = getOneTouchSize();
int oneTouchOffset = getOneTouchOffset();
int blockSize = 5;
//getBlockSize(); //Math.min(getDividerSize(), oneTouchSize);
// This layout differs from the one used in BasicSplitPaneDivider.
// It does not center justify the oneTouchExpadable buttons.
// This was necessary in order to meet the spec of the Metal
// splitpane divider.
if (theLeftButton != null
&& theRightButton != null
&& c == WindowsSplitPaneDivider.this) {
if (theSplitPane.isOneTouchExpandable()) {
if (theOrientation == JSplitPane.VERTICAL_SPLIT) {
theLeftButton.setBounds(
oneTouchOffset,
0,
blockSize * 2,
blockSize);
theRightButton.setBounds(
oneTouchOffset + oneTouchSize * 2,
0,
blockSize * 2,
blockSize);
} else {
theLeftButton.setBounds(
0,
oneTouchOffset,
blockSize,
blockSize * 2);
theRightButton.setBounds(
0,
oneTouchOffset + oneTouchSize * 2,
blockSize,
blockSize * 2);
}
} else {
theLeftButton.setBounds(-5, -5, 1, 1);
theRightButton.setBounds(-5, -5, 1, 1);
}
}
}
@Override
public Dimension minimumLayoutSize(Container c) {
return new Dimension(0, 0);
}
@Override
public Dimension preferredLayoutSize(Container c) {
return new Dimension(0, 0);
}
@Override
public void removeLayoutComponent(Component c) {
// Unused method; implements LayoutManager.
}
@Override
public void addLayoutComponent(String string, Component c) {
// Unused method; implements LayoutManager.
}
}
public WindowsSplitPaneDivider(BasicSplitPaneUI ui) {
super(ui);
setLayout(new ExtWindowsDividerLayout());
}
/**
* Creates and return an instance of JButton that can be used to
* collapse the left component in the metal split pane.
*/
@Override
protected JButton createLeftOneTouchButton() {
JButton b = new JButton() {
// Sprite buffer for the arrow image of the left button
int[][] buffer = { { 0, 0, 0, 2, 2, 0, 0, 0, 0 }, {
0, 0, 2, 1, 1, 1, 0, 0, 0 }, {
0, 2, 1, 1, 1, 1, 1, 0, 0 }, {
2, 1, 1, 1, 1, 1, 1, 1, 0 }, {
0, 3, 3, 3, 3, 3, 3, 3, 3 }
};
@Override
public void setBorder(Border border) {
// Ignore borders
}
@Override
public void paint(Graphics g) {
JSplitPane theSplitPane = getSplitPaneFromSuper();
if (theSplitPane != null) {
int theOrientation = getOrientationFromSuper();
int blockSize = buffer.length + 1;
//Math.min(getDividerSize(), oneTouchSize);
// Initialize the color array
Color[] colors =
{
this.getBackground(),
UIManager.getColor("controlDkShadow"),
Color.black,
//UIManager.getColor(),
UIManager.getColor("controlLtHighlight")};
// Fill the background first ...
g.setColor(this.getBackground());
g.fillRect(0, 0, this.getWidth(), this.getHeight());
// ... then draw the arrow.
if (getModel().isPressed()) {
// Adjust color mapping for pressed button state
colors[1] = colors[2];
}
if (theOrientation == JSplitPane.VERTICAL_SPLIT) {
// Draw the image for a vertical split
for (int i = 1; i <= buffer[0].length; i++) {
for (int j = 1; j < blockSize; j++) {
if (buffer[j - 1][i - 1] == 0) {
continue;
}
g.setColor(colors[buffer[j - 1][i - 1]]);
g.drawLine(i - 1, j, i - 1, j);
}
}
} else {
// Draw the image for a horizontal split
// by simply swaping the i and j axis.
// Except the drawLine() call this code is
// identical to the code block above. This was done
// in order to remove the additional orientation
// check for each pixel.
for (int i = 1; i <= buffer[0].length; i++) {
for (int j = 1; j < blockSize; j++) {
if (buffer[j - 1][i - 1] == 0) {
// Nothing needs
// to be drawn
continue;
}
// Set the color from the
// color map
g.setColor(colors[buffer[j - 1][i - 1]]);
// Draw a pixel
g.drawLine(j - 1, i, j - 1, i);
}
}
}
}
}
};
b.setFocusPainted(false);
b.setBorderPainted(false);
b.setFocusable(false);
b.setOpaque(false);
return b;
}
/**
* Creates and return an instance of JButton that can be used to
* collapse the right component in the metal split pane.
*/
@Override
protected JButton createRightOneTouchButton() {
JButton b = new JButton() {
// Sprite buffer for the arrow image of the right button
int[][] buffer = { { 2, 2, 2, 2, 2, 2, 2, 2 }, {
0, 1, 1, 1, 1, 1, 1, 3 }, {
0, 0, 1, 1, 1, 1, 3, 0 }, {
0, 0, 0, 1, 1, 3, 0, 0 }, {
0, 0, 0, 0, 3, 0, 0, 0 }
};
@Override
public void setBorder(Border border) {
// Ignore borders
}
@Override
public void paint(Graphics g) {
JSplitPane theSplitPane = getSplitPaneFromSuper();
if (theSplitPane != null) {
int theOrientation = getOrientationFromSuper();
int blockSize = buffer.length + 1;
//Math.min(getDividerSize(), oneTouchSize);
// Initialize the color array
Color[] colors =
{
this.getBackground(),
UIManager.getColor("controlDkShadow"),
Color.black,
//UIManager.getColor("controlDkShadow"),
UIManager.getColor("controlLtHighlight")};
// Fill the background first ...
g.setColor(this.getBackground());
g.fillRect(0, 0, this.getWidth(), this.getHeight());
// ... then draw the arrow.
if (getModel().isPressed()) {
// Adjust color mapping for pressed button state
colors[1] = colors[2];
}
if (theOrientation == JSplitPane.VERTICAL_SPLIT) {
// Draw the image for a vertical split
for (int i = 1; i <= buffer[0].length; i++) {
for (int j = 1; j < blockSize; j++) {
if (buffer[j - 1][i - 1] == 0) {
continue;
}
g.setColor(colors[buffer[j - 1][i - 1]]);
g.drawLine(i, j, i, j);
}
}
} else {
// Draw the image for a horizontal split
// by simply swaping the i and j axis.
// Except the drawLine() call this code is
// identical to the code block above. This was done
// in order to remove the additional orientation
// check for each pixel.
for (int i = 1; i <= buffer[0].length; i++) {
for (int j = 1; j < blockSize; j++) {
if (buffer[j - 1][i - 1] == 0) {
// Nothing needs
// to be drawn
continue;
}
// Set the color from the
// color map
g.setColor(colors[buffer[j - 1][i - 1]]);
// Draw a pixel
g.drawLine(j - 1, i, j - 1, i);
}
}
}
}
}
};
b.setFocusPainted(false);
b.setBorderPainted(false);
b.setFocusable(false);
b.setOpaque(false);
return b;
}
static int getBlockSize() {
return EXT_BLOCKSIZE;
}
static int getOneTouchOffset() {
return EXT_ONE_TOUCH_OFFSET;
}
static int getOneTouchSize() {
return EXT_ONE_TOUCH_SIZE;
}
int getOrientationFromSuper() {
return super.orientation;
}
JButton getLeftButtonFromSuper() {
return super.leftButton;
}
JButton getRightButtonFromSuper() {
return super.rightButton;
}
JSplitPane getSplitPaneFromSuper() {
return super.splitPane;
}
@Override
public void paint(Graphics g) {
if (splitPane.isOpaque()) {
Color bgColor = splitPane.hasFocus()
? UIManager.getColor("SplitPane.shadow")
: getBackground();
if (bgColor != null) {
g.setColor(bgColor);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
super.paint(g);
}
}