/** * */ package photoSpreadUtilities; import java.awt.Color; import java.awt.Component; import java.security.InvalidParameterException; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.border.TitledBorder; import photoSpreadTable.PredictableEquiSizedGridLayout; import photoSpreadUtilities.Const.Alignment; /** * @author paepcke * */ public class SuperPositioner extends JPanel { /** * Takes a component and optionally an enclosing frame, * and superposes the component onto the frame using its * glass pane. * */ public static final int OF_PANEL_WIDTH = 0; public static final int OF_PANEL_HEIGHT = 1; private static final long serialVersionUID = 1L; private static int _defaultAlpha = 255/2; private JPanel _superposeSubstrate = null; private JLayeredPane _superposePane; private Component _itemToShow; private ComputableDimension _initialItemSize = null; private int _initialItemSizePercentage; /**************************************************** * Constructor(s) *****************************************************/ // public SuperPositioner(JFrame frame, Component itemToShow, int alpha, String popupTitle) { public SuperPositioner(JPanel panelToSuperposeOn, Component itemToShow, int alpha, String popupTitle) { if ((panelToSuperposeOn == null) || (itemToShow == null) || (alpha < 0) || (alpha > 255)) throw new InvalidParameterException("One of 'frame', 'itemToshow', or 'alpha' are null."); _itemToShow = itemToShow; _superposeSubstrate = panelToSuperposeOn; _defaultAlpha = alpha; // Clients may call setInitialItemSize() later. But for // the case that they don't, we need to initialize // _initialItemSize to something reasaonble: if (_initialItemSize == null) // If we created a default item as part of the constructor, // then that item's preferred size will have been set // to something reasonable: if (_itemToShow.getPreferredSize() != null) _initialItemSize = new ComputableDimension(_itemToShow.getPreferredSize()); // Otherwise we make the image 100% of the surrounding frame, // assuming a 1/1 item aspect ratio: else setInitialItemSizePercentage(100, OF_PANEL_WIDTH, (float) 1.0); if (popupTitle == null) popupTitle = ""; // A LayeredJPane will be the surface onto which // we'll place the item to superimpose: _superposePane = new JLayeredPane(); _superposePane.setOpaque(false); _superposePane.setBackground(new Color ( Color.GRAY.getRed(), Color.GRAY.getGreen(), Color.GRAY.getBlue(), _defaultAlpha)); // _superposePane.setLayout(new FlowLayout(FlowLayout.LEADING)); PredictableEquiSizedGridLayout superposeLayout = new PredictableEquiSizedGridLayout(); _superposePane.setLayout(superposeLayout); superposeLayout.setLayoutAlignmentX(Alignment.LEFT_H_ALIGNED); superposeLayout.setLayoutAlignmentX(Alignment.TOP_V_ALIGNED); // Border around the superposition: TitledBorder superImpositionBorder = BorderFactory.createTitledBorder(popupTitle); superImpositionBorder.setTitleColor(Const.superposePaneTitleColor); _superposePane.setBorder(superImpositionBorder); _superposePane.add(_itemToShow); // ComputableDimension superposePaneSize = new ComputableDimension (_superposePane.getSize()); // ComputableDimension borderSize = new ComputableDimension (superImpositionBorder.getMinimumSize(_superposePane)); // _superposePane.setPreferredSize(superposePaneSize.plus(borderSize)); _superposePane.setPreferredSize(new ComputableDimension(600,600)); _superposePane.setLayer(_itemToShow, JLayeredPane.POPUP_LAYER); _superposeSubstrate.add(_superposePane); // We start invisible, letting the client // manipulate quantities like initial size // of shown item. The client will then need // to call setVisible(true): _superposePane.setVisible(false); // _superposeSubstrate.validate(); } public SuperPositioner (JPanel panelToSuperposeOn, Component itemToShow, int alpha) { this(panelToSuperposeOn, itemToShow, alpha, ""); } public SuperPositioner (JPanel panelToSuperposeOn, Component itemToShow, String popupTitle) { this(panelToSuperposeOn, itemToShow, getDefaultAlpha(), popupTitle); } public SuperPositioner (JPanel panelToSuperposeOn, Component itemToShow) { this(panelToSuperposeOn, itemToShow, getDefaultAlpha(), ""); } public SuperPositioner (JPanel panelToSuperposeOn, String popupTitle) { this(panelToSuperposeOn, prepareSample(panelToSuperposeOn), _defaultAlpha, popupTitle); } public SuperPositioner (JPanel panelToSuperposeOn) { this(panelToSuperposeOn, prepareSample(panelToSuperposeOn), _defaultAlpha, ""); // no popup title } private static Component prepareSample(JPanel panelToSuperposeOn) { Component sample = new JPanel(); sample.setBackground(Const.superposeDefaultSampleColor); ComputableDimension sampleDim = new ComputableDimension(panelToSuperposeOn.getSize()); sample.setPreferredSize(sampleDim.div(2)); sample.setVisible(true); return sample; } /** * Set width/height of how large the superimposed item is * to be shown initially * * @param initItemSize */ public void setInitialItemSize(ComputableDimension initItemSize) { _initialItemSize = initItemSize; if (_itemToShow != null) _itemToShow.setPreferredSize(initItemSize); resizeItem(initItemSize); } /** * Set width/height of how large the superimposed item is * to be shown initially * * @param initItemWidth * @param initItemHeight */ public void setInitialItemSize(int initItemWidth, int initItemHeight) { setInitialItemSize (new ComputableDimension(initItemWidth, initItemHeight)); } /** * Set width/height of how large the superimposed item is * to be shown initially. The size is passed in as a percentage * of the surrounding panel (which was passed into the constructor * earlier). * @param initItemSizePercentage Percentage of surrounding panel */ public void setInitialItemSizePercentage(int initItemSizePercentage) { _initialItemSizePercentage = initItemSizePercentage; int newInitialItemWidth = _superposeSubstrate.getWidth() * initItemSizePercentage / 100; int newInitialItemHeight = _superposeSubstrate.getHeight() * initItemSizePercentage / 100; setInitialItemSize(new ComputableDimension (newInitialItemWidth, newInitialItemHeight)); } /** * Set width/height of how large the superimposed item is * to be shown initially. The size is computed by either the * width or the height of the surrounding panel. Caller picks * which of these sides is used as the reference by setting * the parameter whichPanelSide to OF_PANEL_WIDTH or * OF_PANEL_HEIGHT. The initItemSizePercentage is is applied * to the thus specified panel side and taken as the displayed * item's width (height). The remaining item's side is then * computed from the parameter ratioWidthOverHeight item aspect * ratio. * * * @param initItemSizePercentage Percentage of panel side * @param whichPanelSide Choice of panel side (width/height) to use as reference for the percentage * @param ratioWidthOverHeight Item aspect ratio */ public void setInitialItemSizePercentage (int initItemSizePercentage, int whichPanelSide, float ratioWidthOverHeight) { int newInitialItemWidth; int newInitialItemHeight; if (! ( (whichPanelSide == OF_PANEL_WIDTH) || (whichPanelSide == OF_PANEL_HEIGHT)) ) throw new InvalidParameterException ("Panel side spec needs to be OF_PANEL_WIDTH or OF_PANEL_HEIGHT"); if (whichPanelSide == OF_PANEL_WIDTH) { newInitialItemWidth = _superposeSubstrate.getWidth() * initItemSizePercentage / 100; newInitialItemHeight = ((int) (newInitialItemWidth / ratioWidthOverHeight)); } else { newInitialItemHeight = _superposeSubstrate.getHeight() * initItemSizePercentage / 100; newInitialItemWidth = ((int) (newInitialItemHeight * ratioWidthOverHeight)); } setInitialItemSize(new ComputableDimension(newInitialItemWidth, newInitialItemHeight)); } public ComputableDimension getInitialItemSize() { return _initialItemSize; } public int getInitialItemSizePercentage() { return _initialItemSizePercentage; } /**************************************************** * Methods *****************************************************/ public void dispose () { _superposePane.setVisible(false); _superposePane.remove(_itemToShow); _superposeSubstrate.remove(_superposePane); _superposePane = null; } /** * Allow UI to display this instance of * superposition. Client needs to call this * method, because instance construction leaves * the superposition hidden. * * @param show * @Override */ public void setVisible(boolean show) { _superposePane.setVisible(show); super.setVisible(show); } // This method doesn't work yet. public void setItemToShow(Component comp) { return; } public ComputableDimension getItemSize() { return new ComputableDimension(_itemToShow.getSize()); } /** * Resize the item to the given dimension * @param dim ComputationalDimension to use */ public void resizeItem (ComputableDimension dim) { _itemToShow.setSize(dim); _superposePane.invalidate(); } /** * Resize the item to the given width/height * * @param width * @param height */ public void resizeItem (int width, int height) { this.resizeItem(new ComputableDimension(width, height)); } /** * Resize the item to a percentage of its initial size * * @param percentage Percentage of superimposed item's initial size */ public void resizeItem (int percentage) { resizeItem(_initialItemSize.percent(percentage)); } public static void setDefaultAlpha(int newAlpha) { if (!((newAlpha >= 0) && (newAlpha <= 255))) throw new InvalidParameterException("Alpha values for superimposition must be between 0 and 255, incl."); _defaultAlpha = newAlpha; } public static int getDefaultAlpha() { return _defaultAlpha; } /**************************************************** * Main and/or Testing Methods * @throws InterruptedException *****************************************************/ public static void main (String[] args) throws InterruptedException { JFrame frame = new JFrame("Glass Writing Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(1000,1000); JButton contentLayerButton = new JButton("Content Layer"); JPanel panel = new JPanel(); panel.setPreferredSize(frame.getSize()); panel.setBackground(Color.blue); panel.add(contentLayerButton); frame.add(panel); frame.setVisible(true); new JButton("Glass Layer"); // SuperPositioner superPos = new SuperPositioner(panel, glassLayerButton, "Sample image"); SuperPositioner superPos = new SuperPositioner(panel); superPos.setVisible(true); for (int i = 0; i < 2; i++) { superPos.resizeItem(120); superPos.resizeItem(120); ComputableDimension currSize = superPos.getItemSize(); superPos.resizeItem(currSize.width, currSize.height + 40); } // next i superPos.resizeItem(70); // superPos.dispose(); // JButton newButton = new JButton("New Sample"); // newButton.setVisible(true); // superPos.setItemToShow(newButton); } }