com.jidesoft.swing.Resizable Maven / Gradle / Ivy
Show all versions of jide-oss Show documentation
/*
* @(#)${NAME}.java
*
* Copyright 2002 - 2005 JIDE Software Inc. All rights reserved.
*/
package com.jidesoft.swing;
import com.jidesoft.plaf.UIDefaultsLookup;
import javax.swing.*;
import javax.swing.event.MouseInputListener;
import java.awt.*;
/**
* Resizable
is a class that supports the resizable feature.
*
* To use it and make a component resizable, you just need to create new Resizable(component) and pass in that component
* to the constructor. Resizable
uses {@link #beginResizing(int)}, {@link #resizing(int, int, int, int,
* int)} and {@link #endResizing(int)} to archive the resizing effect. It should work for most cases. However if it
* doesn't work as expected for some layouts, you can override one of all of the three methods to make it working.
*/
public class Resizable {
public static final int NONE = 0x0;
public static final int UPPER_LEFT = 0x1;
public static final int UPPER = 0x2;
public static final int UPPER_RIGHT = 0x4;
public static final int RIGHT = 0x8;
public static final int LOWER_RIGHT = 0x10;
public static final int LOWER = 0x20;
public static final int LOWER_LEFT = 0x40;
public static final int LEFT = 0x80;
public static final int ALL = 0xFF;
private int _resizableCorners = 0xFF;
private int _resizeCornerSize = 16;
public static final String PROPERTY_RESIZABLE_CORNERS = "resizableCorner";
public static final String PROPERTY_RESIZE_CORNER_SIZE = "resizeCornerSize";
protected final JComponent _component;
private Insets _resizeInsets;
private MouseInputListener _mouseInputAdapter;
private int _snapGridSize = 1;
private boolean _topLevel;
/**
* Creates a new Resizable
. This call will make the component to be resizable.
*
* @param component the component that should be resizable.
*/
public Resizable(JComponent component) {
_component = component;
installListeners();
}
/**
* Gets the resizable corners. The value is a bitwise OR of eight constants defined in {@link Resizable}.
*
* @return resizable corners.
*/
public int getResizableCorners() {
return _resizableCorners;
}
/**
* Sets resizable corners.
*
* @param resizableCorners new resizable corners. The value is a bitwise OR of eight constants defined in {@link
* Resizable}.
*/
public void setResizableCorners(int resizableCorners) {
if (_resizableCorners != resizableCorners) {
int old = _resizableCorners;
_resizableCorners = resizableCorners;
_component.firePropertyChange(PROPERTY_RESIZABLE_CORNERS, old, _resizableCorners);
}
}
/**
* Gets resize corner size. This size is the corner's sensitive area which will trigger the resizing from both
* sides.
*
* @return the resize corner size.
*/
public int getResizeCornerSize() {
return _resizeCornerSize;
}
/**
* Sets the resize corner size.
*
* @param resizeCornerSize the resize corner size.
*/
public void setResizeCornerSize(int resizeCornerSize) {
if (_resizeCornerSize != resizeCornerSize) {
int old = _resizeCornerSize;
_resizeCornerSize = resizeCornerSize;
_component.firePropertyChange(PROPERTY_RESIZE_CORNER_SIZE, old, _resizeCornerSize);
}
}
/**
* Installs the listeners needed to perform resizing operations. You do not need to call this method directly.
* Constructor will call this method automatically.
*/
protected void installListeners() {
_mouseInputAdapter = createMouseInputListener();
_component.addMouseListener(_mouseInputAdapter);
_component.addMouseMotionListener(_mouseInputAdapter);
}
/**
* Uninstalls the listeners that created to perform resizing operations. After the uninstallation, the component
* will not be resizable anymore.
*/
public void uninstallListeners() {
_component.removeMouseListener(_mouseInputAdapter);
_component.removeMouseMotionListener(_mouseInputAdapter);
_mouseInputAdapter = null;
}
/**
* Creates the MouseInputListener for resizing. Subclass can override this method to provide its own
* MouseInputListener to customize existing one.
*
* @return the MouseInputListener for resizing.
*/
protected MouseInputListener createMouseInputListener() {
return new ResizableMouseInputAdapter(this);
}
/**
* Gets the mouse adapter for resizing.
*
* @return the mouse adapter for resizing.
*/
public MouseInputListener getMouseInputAdapter() {
return _mouseInputAdapter;
}
/**
* This method is called when resizing operation started.
*
* @param resizeCorner the resize corner.
*/
public void beginResizing(int resizeCorner) {
}
/**
* This method is called during the resizing of ResizablePanel. In default implementation, it call
*
* setPreferredSize(new Dimension(newW, newH));
* getParent().doLayout();
*
* in fact, depending on where you added this ResizablePanel, you may need to override this method to do something
* else. For example, {@link ResizableWindow} uses ResizablePanel
to implement resizable feature in
* JWindow. It overrides this method to call setBounds on JWindow itself.
*
* @param resizeCorner the resize corner.
* @param newX the new x position.
* @param newY the new y position.
* @param newW the new width.
* @param newH the new height.
*/
public void resizing(int resizeCorner, int newX, int newY, int newW, int newH) {
Dimension minimumSize = _component.getMinimumSize();
Dimension maximumSize = _component.getMaximumSize();
if (newW < minimumSize.width) {
newW = minimumSize.width;
}
if (newH < minimumSize.height) {
newW = minimumSize.height;
}
if (newW > maximumSize.width) {
newW = maximumSize.width;
}
if (newH > maximumSize.height) {
newH = maximumSize.height;
}
_component.setPreferredSize(new Dimension(newW, newH));
_component.getParent().doLayout();
}
/**
* The method is called when resizing ends.
*
* @param resizeCorner the resize corner.
*/
public void endResizing(int resizeCorner) {
}
/**
* Checks if the Resizable is added to a top level component. If it's top level component, it will use screen
* coordinates to do all calculations during resizing. If resizing the resizable panel won't affect any top level
* container's position, you can return false here. Otherwise, return true. The default implementation always return
* false. Subclasses can override to return different value. In the case of ResizableWindow or ResizableDialog, this
* method is overridden and returns true.
*
* @return false.
*/
public boolean isTopLevel() {
return _topLevel;
}
/**
* To indicates this Resizable
is installed on a top level component such as JWindow, JDialog and
* JFrame v.s. a JPanel which is not a top level component because a JPanel must be added to another top level
* component in order to be displayed.
*
* @param topLevel true or false.
*/
public void setTopLevel(boolean topLevel) {
_topLevel = topLevel;
}
/**
* Gets the component which has this Resizable object.
*
* @return the component which has this Resizable object.
*/
public JComponent getComponent() {
return _component;
}
/**
* Returns the insets that should be used to calculate the resize area. Unless you have used setResizeInsets or
* overridden this method, it'll return the insets of the component.
*
* @return the insets that should be used to calculate the resize area.
*/
public Insets getResizeInsets() {
if (_resizeInsets != null) {
return _resizeInsets;
}
return getComponent().getInsets();
}
/**
* Sets the insets the be used to calculate the resize area.
*
* @param resizeInsets
*/
public void setResizeInsets(Insets resizeInsets) {
_resizeInsets = resizeInsets;
}
/**
* Gets the snap grid size.
*
* @return the snap grid size.
*
* @see #setSnapGridSize(int)
*/
public int getSnapGridSize() {
return _snapGridSize;
}
/**
* Sets the snap grid size.
*
* Snap grid size is used to make resizing easier.
*
* By default, the size is 1 pixel.
*
* @param snapGridSize the grid size
*/
public void setSnapGridSize(int snapGridSize) {
_snapGridSize = snapGridSize;
}
public static class ResizeCorner extends JComponent {
static final int SIZE = 16;
private int _corner = LOWER_RIGHT;
public ResizeCorner() {
}
public ResizeCorner(int corner) {
_corner = corner;
}
public int getCorner() {
return _corner;
}
public void setCorner(int corner) {
_corner = corner;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(SIZE, SIZE);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int size = Math.min(getWidth(), getHeight());
int count = Math.min(size / 4, 4);
Color old = g.getColor();
int corner = getCorner();
boolean ltr = getComponentOrientation().isLeftToRight();
switch (corner) {
case LOWER_RIGHT: {
g.setColor(UIDefaultsLookup.getColor("controlLtHighlight"));
int delta = 0;
for (int i = 0; i < count; i++) {
delta += 4;
if (ltr) {
g.drawLine(size, size - delta, size - delta, size);
}
else {
g.drawLine(0, delta, size - delta, size);
}
}
g.setColor(UIDefaultsLookup.getColor("controlShadow"));
delta = 0;
for (int i = 0; i < count; i++) {
delta += 4;
if (ltr) {
g.drawLine(size, size - delta + 1, size - delta + 1, size);
g.drawLine(size, size - delta + 2, size - delta + 2, size);
}
else {
g.drawLine(0, delta + 1, size - delta - 1, size);
g.drawLine(0, delta + 2, size - delta - 2, size);
}
}
}
break;
case UPPER_RIGHT: {
g.setColor(UIDefaultsLookup.getColor("controlLtHighlight"));
int delta = 0;
for (int i = 0; i < count; i++) {
delta += 4;
if (ltr) {
g.drawLine(size - delta, 0, size, delta);
}
else {
g.drawLine(delta, 0, size, size - delta);
}
}
g.setColor(UIDefaultsLookup.getColor("controlShadow"));
delta = 0;
for (int i = 0; i < count; i++) {
delta += 4;
if (ltr) {
g.drawLine(size - delta + 1, 0, size, delta - 1);
g.drawLine(size - delta + 2, 0, size, delta - 2);
}
else {
g.drawLine(delta + 1, 0, size, size - delta - 1);
g.drawLine(delta + 2, 0, size, size - delta - 2);
}
}
}
break;
}
g.setColor(old);
}
}
}