/* * This file is part of WebLookAndFeel library. * * WebLookAndFeel library is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * WebLookAndFeel library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with WebLookAndFeel library. If not, see . */ package com.alee.extended.image; import com.alee.global.StyleConstants; import com.alee.laf.scroll.WebScrollPane; import com.alee.managers.hotkey.Hotkey; import com.alee.utils.GraphicsUtils; import com.alee.utils.ImageUtils; import com.alee.utils.LafUtils; import com.alee.utils.SwingUtils; import com.alee.utils.swing.WebTimer; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.geom.Area; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; /** * User: mgarin Date: 05.09.11 Time: 15:45 */ public class WebImageGallery extends JComponent { private final int spacing = 20; private int imageLength = 200; private final int borderWidth = 3; private final float fadeHeight = 0.7f; private final int opacity = 125; private final Color light = new Color ( 128, 128, 128 ); private final Color selectedLight = new Color ( 255, 255, 255 ); private final Color transparent = new Color ( 128, 128, 128, 0 ); private final Color selectedTransparent = new Color ( 255, 255, 255, 0 ); private int maxWidth = 0; private int maxHeight = 0; private final List images = new ArrayList (); private final List reflections = new ArrayList (); private final List descriptions = new ArrayList (); // private List sizes = new ArrayList ( ); private int preferredColumnCount = 4; private boolean scrollOnSelection = true; private int selectedIndex = -1; private int oldSelectedIndex = -1; private float progress = 0f; private WebTimer reflectionMover = null; private WebScrollPane view; public WebImageGallery () { super (); SwingUtils.setOrientation ( this ); setFocusable ( true ); setFont ( new JLabel ().getFont ().deriveFont ( Font.BOLD ) ); final MouseAdapter mouseAdapter = new MouseAdapter () { @Override public void mousePressed ( final MouseEvent e ) { if ( SwingUtilities.isLeftMouseButton ( e ) ) { WebImageGallery.this.requestFocusInWindow (); for ( int i = 0; i < images.size (); i++ ) { if ( getImageRect ( i ).contains ( e.getPoint () ) ) { setSelectedIndex ( i ); break; } } } } @Override public void mouseWheelMoved ( final MouseWheelEvent e ) { final int index = getSelectedIndex (); final int maxIndex = images.size () - 1; final int wheelRotation = e.getWheelRotation (); int newIndex; if ( wheelRotation > 0 ) { newIndex = index + wheelRotation; while ( newIndex > maxIndex ) { newIndex -= images.size (); } } else { newIndex = index + wheelRotation; while ( newIndex < 0 ) { newIndex += images.size (); } } setSelectedIndex ( newIndex ); } }; addMouseListener ( mouseAdapter ); addMouseWheelListener ( mouseAdapter ); addKeyListener ( new KeyAdapter () { @Override public void keyPressed ( final KeyEvent e ) { if ( images.size () > 0 ) { final int si = getSelectedIndex (); if ( Hotkey.LEFT.isTriggered ( e ) ) { setSelectedIndex ( si == -1 || si == 0 ? images.size () - 1 : si - 1 ); } else if ( Hotkey.RIGHT.isTriggered ( e ) ) { setSelectedIndex ( si == -1 || si == images.size () - 1 ? 0 : si + 1 ); } else if ( Hotkey.HOME.isTriggered ( e ) ) { setSelectedIndex ( 0 ); } else if ( Hotkey.END.isTriggered ( e ) ) { setSelectedIndex ( images.size () - 1 ); } } } } ); } public List getImages () { return images; } public int getPreferredColumnCount () { return preferredColumnCount; } public void setPreferredColumnCount ( final int preferredColumnCount ) { this.preferredColumnCount = preferredColumnCount; } public WebScrollPane getView () { return getView ( true ); } public WebScrollPane getView ( final boolean withBorder ) { if ( view == null ) { view = new WebScrollPane ( WebImageGallery.this, withBorder ) { @Override public Dimension getPreferredSize () { final int columns = Math.min ( images.size (), preferredColumnCount ); final JScrollBar hsb = getHorizontalScrollBar (); final int sbh = hsb != null && hsb.isShowing () ? hsb.getPreferredSize ().height : 0; return new Dimension ( spacing * ( columns + 1 ) + columns * maxWidth, WebImageGallery.this.getPreferredSize ().height + sbh ); } }; view.setHorizontalScrollBarPolicy ( WebScrollPane.HORIZONTAL_SCROLLBAR_NEVER ); view.setVerticalScrollBarPolicy ( WebScrollPane.VERTICAL_SCROLLBAR_NEVER ); final InputMap im = view.getInputMap ( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ); im.put ( KeyStroke.getKeyStroke ( "UP" ), "none" ); im.put ( KeyStroke.getKeyStroke ( "DOWN" ), "none" ); im.put ( KeyStroke.getKeyStroke ( "LEFT" ), "none" ); im.put ( KeyStroke.getKeyStroke ( "RIGHT" ), "none" ); } return view; } public int getImageLength () { return imageLength; } public void setImageLength ( final int imageLength ) { this.imageLength = imageLength; } public boolean isScrollOnSelection () { return scrollOnSelection; } public void setScrollOnSelection ( final boolean scrollOnSelection ) { this.scrollOnSelection = scrollOnSelection; } public int getSelectedIndex () { return selectedIndex; } public void setSelectedIndex ( final int selectedIndex ) { if ( this.selectedIndex == selectedIndex ) { return; } this.oldSelectedIndex = this.selectedIndex; this.selectedIndex = selectedIndex; repaint (); if ( scrollOnSelection ) { final Rectangle rect = getImageRect ( selectedIndex ); SwingUtils.scrollSmoothly ( getView (), rect.x + rect.width / 2 - WebImageGallery.this.getVisibleRect ().width / 2, rect.y ); } moveReflection (); } private void moveReflection () { if ( reflectionMover != null && reflectionMover.isRunning () ) { reflectionMover.stop (); } progress = 0f; reflectionMover = new WebTimer ( "WebImageGallery.reflectionMoveTimer", StyleConstants.fastAnimationDelay, new ActionListener () { @Override public void actionPerformed ( final ActionEvent e ) { if ( progress < 1f ) { progress += 0.08f; progress = Math.min ( progress, 1f ); WebImageGallery.this.repaint (); } else { reflectionMover.stop (); } } } ); reflectionMover.start (); } public Rectangle getImageRect ( final int index ) { final int iconWidth = images.get ( index ).getIconWidth (); final int iconHeight = images.get ( index ).getIconHeight (); final Dimension ps = getPreferredSize (); final int x = ( getWidth () > ps.width ? ( getWidth () - ps.width ) / 2 : 0 ) + spacing + ( maxWidth + spacing ) * index + maxWidth / 2; final int y = getHeight () / 2 - spacing / 2 - iconHeight / 2; return new Rectangle ( x - iconWidth / 2, y - iconHeight / 2, iconWidth, iconHeight ); } public void addImage ( final ImageIcon image ) { addImage ( 0, image ); } public void addImage ( final int index, final ImageIcon image ) { try { final ImageIcon previewIcon = ImageUtils.createPreviewIcon ( image, imageLength ); final int rwidth = previewIcon.getIconWidth (); final int rheight = previewIcon.getIconHeight (); final BufferedImage reflection = ImageUtils.createCompatibleImage ( rwidth, rheight, Transparency.TRANSLUCENT ); final Graphics2D g2d = reflection.createGraphics (); GraphicsUtils.setupAntialias ( g2d ); g2d.drawImage ( previewIcon.getImage (), 0, 0, null ); g2d.setComposite ( AlphaComposite.getInstance ( AlphaComposite.DST_IN ) ); g2d.setPaint ( new GradientPaint ( 0, rheight * ( 1f - fadeHeight ), new Color ( 0, 0, 0, 0 ), 0, rheight, new Color ( 0, 0, 0, opacity ) ) ); g2d.fillRect ( 0, 0, rwidth, rheight ); g2d.dispose (); images.add ( index, previewIcon ); descriptions.add ( index, image.getIconWidth () + " x " + image.getIconHeight () + " px" ); reflections.add ( index, reflection ); } catch ( final Throwable e ) { // todo Handle out of memory } recalcualteMaxSizes (); updateContainer (); } public void removeImage ( final ImageIcon image ) { if ( images.contains ( image ) ) { removeImage ( images.indexOf ( image ) ); } } public void removeImage ( final int index ) { if ( index >= 0 && index < images.size () ) { final boolean wasSelected = getSelectedIndex () == index; images.remove ( index ); descriptions.remove ( index ); reflections.remove ( index ).flush (); recalcualteMaxSizes (); updateContainer (); if ( wasSelected && images.size () > 0 ) { setSelectedIndex ( index < images.size () ? index : index - 1 ); } } } private void updateContainer () { if ( getParent () instanceof JComponent ) { ( ( JComponent ) getParent () ).revalidate (); } repaint (); } private void recalcualteMaxSizes () { for ( final ImageIcon icon : images ) { maxWidth = Math.max ( maxWidth, icon.getIconWidth () ); maxHeight = Math.max ( maxHeight, icon.getIconHeight () ); } } @Override protected void paintComponent ( final Graphics g ) { super.paintComponent ( g ); final int height = getHeight (); final int width = getWidth (); final Graphics2D g2d = ( Graphics2D ) g; final Object aa = GraphicsUtils.setupAntialias ( g2d ); g2d.setPaint ( new GradientPaint ( 0, 0, Color.black, 0, height, Color.darkGray ) ); g2d.fillRect ( 0, 0, width, height ); final Rectangle vr = getVisibleRect (); final Dimension ps = getPreferredSize (); final Composite oldComposite = g2d.getComposite (); for ( int i = 0; i < images.size (); i++ ) { if ( !getImageRect ( i ).intersects ( vr ) ) { continue; } final ImageIcon icon = images.get ( i ); final BufferedImage bi = ImageUtils.getBufferedImage ( icon ); final int imageWidth = icon.getIconWidth (); final int imageHeight = icon.getIconHeight (); final int x = ( getWidth () > ps.width ? ( getWidth () - ps.width ) / 2 : 0 ) + spacing + ( maxWidth + spacing ) * i + maxWidth / 2; final int y = height / 2 - spacing / 2 - imageHeight / 2; final int y2 = height / 2 + spacing / 2 + imageHeight / 2; // Initial image final float add = selectedIndex == i ? progress * 0.4f : ( oldSelectedIndex == i ? 0.4f - progress * 0.4f : 0 ); g2d.setComposite ( AlphaComposite.getInstance ( AlphaComposite.SRC_OVER, 0.6f + add ) ); g2d.drawImage ( bi, x - imageWidth / 2, y - imageHeight / 2, null ); g2d.setPaint ( selectedIndex == i ? Color.WHITE : Color.GRAY ); Area gp = new Area ( new RoundRectangle2D.Double ( x - imageWidth / 2 - borderWidth, y - imageHeight / 2 - borderWidth, imageWidth + borderWidth * 2, imageHeight + borderWidth * 2, borderWidth * 2, borderWidth * 2 ) ); gp.subtract ( new Area ( new Rectangle ( x - imageWidth / 2, y - imageHeight / 2, imageWidth, imageHeight ) ) ); g2d.fill ( gp ); g2d.setComposite ( oldComposite ); // Info text if ( selectedIndex == i || oldSelectedIndex == i ) { final float opacity = selectedIndex == i ? progress : 1f - progress; g2d.setComposite ( AlphaComposite.getInstance ( AlphaComposite.SRC_OVER, opacity ) ); g2d.setPaint ( Color.WHITE ); final String infoText = descriptions.get ( i ); final Point ts = LafUtils.getTextCenterShear ( g2d.getFontMetrics (), infoText ); g2d.drawString ( infoText, x + ts.x, getHeight () / 2 + spacing / 2 + ts.y ); g2d.setComposite ( oldComposite ); } // Reflection final int rwidth = imageWidth + borderWidth * 2; final int rheight = imageHeight + borderWidth * 2; final int addition = selectedIndex == i ? Math.round ( progress * spacing ) : ( oldSelectedIndex == i ? spacing - Math.round ( progress * spacing ) : 0 ); if ( reflections.get ( i ) != null ) { g2d.drawImage ( reflections.get ( i ), x - imageWidth / 2, y2 + imageHeight / 2 + addition, imageWidth, -imageHeight, null ); } gp = new Area ( new RoundRectangle2D.Double ( x - rwidth / 2, y2 - rheight / 2 + addition, rwidth, rheight, borderWidth * 2, borderWidth * 2 ) ); gp.subtract ( new Area ( new Rectangle ( x - rwidth / 2 + borderWidth, y2 - rheight / 2 + addition + borderWidth, rwidth - borderWidth * 2, rheight - borderWidth * 2 ) ) ); g2d.setPaint ( new GradientPaint ( 0, y2 - imageHeight / 2 + addition, selectedIndex == i ? selectedLight : light, 0, y2 - imageHeight / 2 + addition + imageHeight * fadeHeight, selectedIndex == i ? selectedTransparent : transparent ) ); g2d.fill ( gp ); } GraphicsUtils.restoreAntialias ( g2d, aa ); } @Override public Dimension getPreferredSize () { return new Dimension ( spacing * ( images.size () + 1 ) + maxWidth * images.size (), spacing * 3 + maxHeight * 2 ); } }