Package com.alee.extended.colorchooser

Source Code of com.alee.extended.colorchooser.WebColorChooserField

/*
* 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 <http://www.gnu.org/licenses/>.
*/

package com.alee.extended.colorchooser;

import com.alee.extended.image.WebImage;
import com.alee.extended.painter.AbstractPainter;
import com.alee.extended.window.PopOverAlignment;
import com.alee.extended.window.PopOverDirection;
import com.alee.extended.window.WebPopOver;
import com.alee.laf.WebLookAndFeel;
import com.alee.laf.button.WebButton;
import com.alee.laf.colorchooser.ColorChooserListener;
import com.alee.laf.colorchooser.WebColorChooserPanel;
import com.alee.laf.label.WebLabel;
import com.alee.laf.panel.WebPanel;
import com.alee.laf.rootpane.WebWindow;
import com.alee.laf.text.WebTextField;
import com.alee.managers.hotkey.Hotkey;
import com.alee.managers.hotkey.HotkeyManager;
import com.alee.managers.hotkey.HotkeyRunnable;
import com.alee.managers.log.Log;
import com.alee.utils.ColorUtils;
import com.alee.utils.ImageUtils;
import com.alee.utils.SwingUtils;
import com.alee.utils.swing.ChooserListener;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

/**
* Custom field that offers various ways to select Color.
* Color can be typed, selected from popup palette or using eyedropper tool.
*
* @author Mikle Garin
*/

public class WebColorChooserField extends WebTextField
{
    /**
     * todo 1. Make possible color's alpha channel selection
     */

    /**
     * Used icons.
     */
    public static final ImageIcon eyedropperIcon = new ImageIcon ( WebColorChooserField.class.getResource ( "icons/eyedropper.png" ) );

    /**
     * Color display type.
     *
     * @see com.alee.extended.colorchooser.ColorDisplayType
     */
    protected ColorDisplayType colorDisplayType;

    /**
     * Whether should display eyedropper tool or not.
     */
    protected boolean displayEyedropper = true;

    /**
     * Size of the eyedropper image side displayed within popup in pixels.
     * Each of these pixels will also be enlarged according to eyedropperImagePixelSize value.
     */
    protected final int eyedropperImageSide = 9;

    /**
     * Size of each pixel of eyedropper image displayed within popup.
     */
    protected final int eyedropperImagePixelSize = 11;

    /**
     * Most recent valid color text.
     */
    protected String lastCorrectColorText = "";

    /**
     * Currently selected color.
     */
    protected Color color;

    /**
     * UI elements.
     */
    protected final WebButton colorButton;
    protected Robot robot;
    protected WebImage eyedropperPicker;
    protected WebPopOver popup;
    protected WebColorChooserPanel colorChooserPanel;

    public WebColorChooserField ()
    {
        this ( Color.WHITE );
    }

    public WebColorChooserField ( final Color color )
    {
        super ();

        // Field settings
        updateMargin ();
        setHorizontalAlignment ( CENTER );

        // Eyedropper tool
        updateEyedropper ();

        // Trailing color choose button
        colorButton = new WebButton ( ImageUtils.createColorChooserIcon ( color ) );
        colorButton.setFocusable ( false );
        colorButton.setShadeWidth ( 0 );
        colorButton.setMoveIconOnPress ( false );
        colorButton.setRolloverDecoratedOnly ( true );
        colorButton.setCursor ( Cursor.getDefaultCursor () );
        colorButton.addActionListener ( new ActionListener ()
        {
            @Override
            public void actionPerformed ( final ActionEvent e )
            {
                showColorChooserPopup ();
            }
        } );
        setTrailingComponent ( colorButton );

        // Color update lsiteners
        addActionListener ( new ActionListener ()
        {
            @Override
            public void actionPerformed ( final ActionEvent e )
            {
                updateColorFromField ();
            }
        } );
        addFocusListener ( new FocusAdapter ()
        {
            @Override
            public void focusLost ( final FocusEvent e )
            {
                updateColorFromField ();
            }
        } );

        // Popup display listeners
        addMouseListener ( new MouseAdapter ()
        {
            @Override
            public void mousePressed ( final MouseEvent e )
            {
                if ( isEnabled () && SwingUtilities.isRightMouseButton ( e ) )
                {
                    showColorChooserPopup ();
                }
            }
        } );
        addKeyListener ( new KeyAdapter ()
        {
            @Override
            public void keyReleased ( final KeyEvent e )
            {
                if ( isEnabled () )
                {
                    if ( Hotkey.ESCAPE.isTriggered ( e ) )
                    {
                        updateViewFromColor ();
                    }
                    else if ( Hotkey.DOWN.isTriggered ( e ) )
                    {
                        showColorChooserPopup ();
                    }
                }
            }
        } );

        // Initial data
        setColorDisplayType ( ColorDisplayType.rgb );
        setColorImpl ( color );
    }

    public boolean isDisplayEyedropper ()
    {
        return displayEyedropper;
    }

    public void setDisplayEyedropper ( final boolean displayEyedropper )
    {
        this.displayEyedropper = displayEyedropper;
        updateEyedropper ();
    }

    public Color getColor ()
    {
        return color;
    }

    public void setColor ( final Color color )
    {
        setColorImpl ( color );
    }

    protected void setColorImpl ( final Color color )
    {
        final Color oldColor = this.color;
        this.color = color;
        updateViewFromColor ();
        fireColorSelected ( oldColor, color );
    }

    public ColorDisplayType getColorDisplayType ()
    {
        return colorDisplayType;
    }

    public void setColorDisplayType ( final ColorDisplayType colorDisplayType )
    {
        this.colorDisplayType = colorDisplayType;
        updateFieldType ();
    }

    @Override
    public void setDrawBorder ( final boolean drawBorder )
    {
        super.setDrawBorder ( drawBorder );
        updateMargin ();
    }

    /**
     * protected update methods
     */

    protected void updateViewFromColor ()
    {
        colorButton.setIcon ( ImageUtils.createColorChooserIcon ( color ) );
        updateText ();
    }

    protected void updateColorFromField ()
    {
        final String current = getText ();
        if ( !current.equals ( lastCorrectColorText ) )
        {
            try
            {
                final boolean hex = colorDisplayType.equals ( ColorDisplayType.hex );
                Color newColor = hex ? ColorUtils.parseHexColor ( current ) : ColorUtils.parseRgbColor ( current );
                if ( newColor != null )
                {
                    // todo Ignoring alpha for now
                    newColor = ColorUtils.removeAlpha ( newColor );

                    // Apply new value
                    setColorImpl ( newColor );
                }
                else
                {
                    // Restore old value
                    updateViewFromColor ();
                }
            }
            catch ( final Throwable e )
            {
                // Restore old value
                updateViewFromColor ();
            }
        }
    }

    protected void updateFieldType ()
    {
        if ( colorDisplayType != null )
        {
            final boolean hex = colorDisplayType.equals ( ColorDisplayType.hex );
            setColumns ( hex ? 6 : 9 );
            updateText ();
        }
    }

    protected void updateText ()
    {
        if ( color != null )
        {
            final String text = getColorText ( color );
            setText ( text );
            lastCorrectColorText = text;
        }
    }

    protected String getColorText ( final Color color )
    {
        final boolean hex = colorDisplayType.equals ( ColorDisplayType.hex );
        return hex ? ColorUtils.getHexColor ( color ) : color.getRed () + "," + color.getGreen () + "," + color.getBlue ();
    }

    protected void updateMargin ()
    {
        setMargin ( isDrawBorder () ? new Insets ( -1, 0, -1, -1 ) : new Insets ( 0, 0, 0, 0 ) );
    }

    /**
     * Eyedropper chooser
     */

    protected void updateEyedropper ()
    {
        if ( displayEyedropper )
        {
            installEyedropper ();
        }
        else
        {
            uninstallEyedropper ();
        }
        revalidate ();
    }

    protected void installEyedropper ()
    {
        if ( eyedropperPicker == null )
        {
            // Eyedropper picker icon
            eyedropperPicker = new WebImage ( eyedropperIcon );
            //            eyedropperPicker.setMargin ( 0, 2, 0, 2 );

            // Eyedropper picker actions
            try
            {
                robot = new Robot ();
            }
            catch ( final AWTException e )
            {
                Log.error ( this, e );
            }
            if ( robot != null )
            {
                final MouseAdapter mouseAdapter = new MouseAdapter ()
                {
                    private boolean shouldUpdateColor;

                    private WebWindow window;
                    private WebPanel screen;
                    private WebLabel info;

                    private boolean updating = false;
                    private BufferedImage screenshot;
                    private Color color;

                    @Override
                    public void mousePressed ( final MouseEvent e )
                    {
                        if ( displayEyedropper && SwingUtils.isLeftMouseButton ( e ) )
                        {
                            // Resetting color update mark
                            shouldUpdateColor = true;

                            // Creating preview window
                            createPreviewWindow ();
                            updateWindowLocation ();

                            // Displaying preview window
                            window.pack ();
                            window.setVisible ( true );

                            // Transferring focus to preview panel
                            screen.requestFocus ();

                            // Updating preview screenshot
                            updateScreenshot ();
                        }
                    }

                    @Override
                    public void mouseDragged ( final MouseEvent e )
                    {
                        if ( displayEyedropper && SwingUtils.isLeftMouseButton ( e ) && window != null )
                        {
                            // Updating preview window location
                            updateWindowLocation ();

                            // Updating preview screenshot
                            updateScreenshot ();
                        }
                    }

                    @Override
                    public void mouseReleased ( final MouseEvent e )
                    {
                        if ( displayEyedropper && SwingUtils.isLeftMouseButton ( e ) && window != null )
                        {
                            // Closing preview window
                            window.dispose ();
                        }
                    }

                    private void updateScreenshot ()
                    {
                        // Simply ignore update if an old one is still running
                        if ( !updating )
                        {
                            // Updating image in a separate thread to avoid UI freezing
                            updating = true;
                            new Thread ( new Runnable ()
                            {
                                @Override
                                public void run ()
                                {
                                    if ( screen != null )
                                    {
                                        final Point p = MouseInfo.getPointerInfo ().getLocation ();
                                        screenshot = robot.createScreenCapture (
                                                new Rectangle ( p.x - eyedropperImageSide / 2, p.y - eyedropperImageSide / 2,
                                                        eyedropperImageSide, eyedropperImageSide )
                                        );
                                        color = new Color ( screenshot.getRGB ( eyedropperImageSide / 2, eyedropperImageSide / 2 ) );
                                        if ( screen != null )
                                        {
                                            screen.repaint ();
                                            info.setText ( getColorText ( color ) );
                                        }
                                        else
                                        {
                                            screenshot.flush ();
                                            screenshot = null;
                                            color = null;
                                        }
                                    }
                                    updating = false;
                                }
                            } ).start ();
                        }
                    }

                    private void createPreviewWindow ()
                    {
                        window = new WebWindow ( eyedropperPicker );
                        window.setLayout ( new BorderLayout () );
                        window.setAlwaysOnTop ( true );
                        window.setFocusableWindowState ( false );

                        window.addWindowListener ( new WindowAdapter ()
                        {
                            @Override
                            public void windowClosed ( final WindowEvent e )
                            {
                                if ( screenshot != null )
                                {
                                    if ( shouldUpdateColor )
                                    {
                                        setColorImpl ( color );
                                    }
                                    screenshot.flush ();
                                    screenshot = null;
                                }
                                HotkeyManager.unregisterHotkeys ( screen );
                                window = null;
                                screen = null;
                            }
                        } );

                        final AbstractPainter<WebPanel> screenPainter = new AbstractPainter<WebPanel> ()
                        {
                            /**
                             * {@inheritDoc}
                             */
                            @Override
                            public void paint ( final Graphics2D g2d, final Rectangle bounds, final WebPanel c )
                            {
                                if ( window.isShowing () && robot != null )
                                {
                                    // Screen
                                    g2d.drawImage ( screenshot, bounds.x + 2, bounds.y + 2, bounds.width - 4, bounds.height - 4, null );

                                    // Border
                                    g2d.setPaint ( Color.BLACK );
                                    g2d.drawRect ( 0, 0, bounds.width - 1, bounds.height - 1 );
                                    g2d.setPaint ( Color.WHITE );
                                    g2d.drawRect ( 1, 1, bounds.width - 3, bounds.height - 3 );

                                    // Cursor
                                    final int mx = bounds.x + bounds.width / 2;
                                    final int my = bounds.y + bounds.height / 2;
                                    g2d.setPaint ( Color.WHITE );
                                    g2d.drawLine ( mx - 1, my - 7, mx - 1, my + 7 );
                                    g2d.drawLine ( mx + 1, my - 7, mx + 1, my + 7 );
                                    g2d.drawLine ( mx - 7, my - 1, mx + 7, my - 1 );
                                    g2d.drawLine ( mx - 7, my + 1, mx + 7, my + 1 );
                                    g2d.setPaint ( Color.BLACK );
                                    g2d.drawLine ( mx, my - 7, mx, my + 7 );
                                    g2d.drawLine ( mx - 7, my, mx + 7, my );
                                }
                            }
                        };

                        screen = new WebPanel ( screenPainter );
                        screen.setFocusable ( true );
                        screen.setPreferredSize ( new Dimension ( eyedropperImageSide * eyedropperImagePixelSize + 4,
                                eyedropperImageSide * eyedropperImagePixelSize + 4 ) );
                        window.add ( screen, BorderLayout.CENTER );

                        info = new WebLabel ( WebLabel.LEADING );
                        info.setMargin ( 4 );
                        info.setIcon ( new Icon ()
                        {
                            @Override
                            public void paintIcon ( final Component c, final Graphics g, final int x, final int y )
                            {
                                if ( color != null )
                                {
                                    final Graphics2D g2d = ( Graphics2D ) g;
                                    g2d.setPaint ( Color.BLACK );
                                    g2d.drawRect ( x, y, 15, 15 );
                                    g2d.setPaint ( Color.WHITE );
                                    g2d.drawRect ( x + 1, y + 1, 13, 13 );
                                    g2d.setPaint ( color );
                                    g2d.fillRect ( x + 2, y + 2, 12, 12 );
                                }
                            }

                            @Override
                            public int getIconWidth ()
                            {
                                return 16;
                            }

                            @Override
                            public int getIconHeight ()
                            {
                                return 16;
                            }
                        } );
                        info.setPainter ( new AbstractPainter<WebLabel> ()
                        {
                            /**
                             * {@inheritDoc}
                             */
                            @Override
                            public Insets getMargin ( final WebLabel c )
                            {
                                return new Insets ( 0, 2, 2, 2 );
                            }

                            /**
                             * {@inheritDoc}
                             */
                            @Override
                            public void paint ( final Graphics2D g2d, final Rectangle bounds, final WebLabel c )
                            {
                                g2d.setPaint ( Color.BLACK );
                                g2d.drawRect ( bounds.x, bounds.y - 1, bounds.width - 1, bounds.height );
                            }
                        } );
                        window.add ( info, BorderLayout.SOUTH );

                        HotkeyManager.registerHotkey ( screen, Hotkey.ESCAPE, new HotkeyRunnable ()
                        {
                            @Override
                            public void run ( final KeyEvent e )
                            {
                                if ( window != null )
                                {
                                    shouldUpdateColor = false;
                                    window.dispose ();
                                }
                            }
                        } );
                    }

                    private void updateWindowLocation ()
                    {
                        final Point p = MouseInfo.getPointerInfo ().getLocation ();
                        final Rectangle b = window.getGraphicsConfiguration ().getDevice ().getDefaultConfiguration ().getBounds ();
                        final int ww = window.getWidth ();
                        final int wh = window.getHeight ();
                        final int x = p.x + 20 + ww < b.x + b.width ? p.x + 20 : p.x - 20 - ww;
                        final int y = p.y + 20 + wh < b.y + b.height ? p.y + 20 : p.y - 20 - wh;
                        window.setLocation ( x, y );
                    }
                };
                eyedropperPicker.addMouseListener ( mouseAdapter );
                eyedropperPicker.addMouseMotionListener ( mouseAdapter );
                eyedropperPicker.setCursor ( Cursor.getDefaultCursor () );
            }
        }

        // Adding field leading component
        setLeadingComponent ( eyedropperPicker );
    }

    protected void uninstallEyedropper ()
    {
        // Removing field leading component
        setLeadingComponent ( null );
    }

    /**
     * Color chooser popup
     */

    protected void showColorChooserPopup ()
    {
        // Checking that component is eligable for focus request
        if ( !requestFocusInWindow () && !isFocusOwner () )
        {
            // Cancel operation if component is not eligable for focus yet
            // This might occur if some other component input verifier holds the focus or in some other rare cases
            return;
        }

        // Update date from field if it was changed
        updateColorFromField ();

        // Create popup if it doesn't exist
        if ( popup == null || colorChooserPanel == null )
        {
            final Window ancestor = SwingUtils.getWindowAncestor ( this );

            // Color chooser
            colorChooserPanel = new WebColorChooserPanel ( true );
            colorChooserPanel.setColor ( color );

            // Popup window
            popup = new WebPopOver ( ancestor );
            popup.setMargin ( 5 );
            popup.setCloseOnFocusLoss ( true );
            popup.add ( colorChooserPanel );

            // Correct popup positioning
            updatePopupLocation ();
            ancestor.addComponentListener ( new ComponentAdapter ()
            {
                @Override
                public void componentMoved ( final ComponentEvent e )
                {
                    if ( popup.isShowing () )
                    {
                        updatePopupLocation ();
                    }
                }

                @Override
                public void componentResized ( final ComponentEvent e )
                {
                    if ( popup.isShowing () )
                    {
                        updatePopupLocation ();
                    }
                }
            } );
            ancestor.addPropertyChangeListener ( WebLookAndFeel.ORIENTATION_PROPERTY, new PropertyChangeListener ()
            {
                @Override
                public void propertyChange ( final PropertyChangeEvent evt )
                {
                    if ( popup.isShowing () )
                    {
                        updatePopupLocation ();
                    }
                }
            } );

            colorChooserPanel.addColorChooserListener ( new ColorChooserListener ()
            {
                @Override
                public void okPressed ( final ActionEvent e )
                {
                    setColorImpl ( colorChooserPanel.getColor () );
                    popup.setVisible ( false );
                }

                @Override
                public void resetPressed ( final ActionEvent e )
                {

                }

                @Override
                public void cancelPressed ( final ActionEvent e )
                {
                    popup.setVisible ( false );
                }
            } );
        }
        else
        {
            // Updating window location
            updatePopupLocation ();

            // Updating color
            colorChooserPanel.setColor ( color );
        }

        // Applying orientation to popup
        SwingUtils.copyOrientation ( WebColorChooserField.this, popup );

        // Showing popup and changing focus
        // popup.setVisible ( true );
        popup.show ( this, PopOverDirection.down, PopOverAlignment.centered );
        colorChooserPanel.requestFocusInWindow ();
    }

    protected void updatePopupLocation ()
    {
        final Point los = WebColorChooserField.this.getLocationOnScreen ();
        final Rectangle gb = popup.getGraphicsConfiguration ().getBounds ();
        final int shadeWidth = isDrawBorder () ? getShadeWidth () : 0;
        final boolean ltr = WebColorChooserField.this.getComponentOrientation ().isLeftToRight ();
        final int w = WebColorChooserField.this.getWidth ();
        final int h = WebColorChooserField.this.getHeight ();

        final int x;
        if ( ltr )
        {
            if ( los.x + shadeWidth + popup.getWidth () <= gb.x + gb.width )
            {
                x = los.x + shadeWidth;
            }
            else
            {
                x = los.x + w - shadeWidth - popup.getWidth ();
            }
        }
        else
        {
            if ( los.x + w - shadeWidth - popup.getWidth () >= gb.x )
            {
                x = los.x + w - shadeWidth - popup.getWidth ();
            }
            else
            {
                x = los.x + shadeWidth;
            }
        }

        final int y;
        if ( los.y + h + popup.getHeight () <= gb.y + gb.height )
        {
            y = los.y + h + ( isDrawBorder () ? 0 : 1 );
        }
        else
        {
            y = los.y - popup.getHeight () - ( isDrawBorder () ? 0 : 1 );
        }

        popup.setLocation ( x, y );
    }

    /**
     * Adds new color selection listener.
     *
     * @param listener new color selection listener
     */
    public void addColorListener ( final ChooserListener<Color> listener )
    {
        listenerList.add ( ChooserListener.class, listener );
    }

    /**
     * Removes color selection listener.
     *
     * @param listener color selection listener to remove
     */
    public void removeColorListener ( final ChooserListener<Color> listener )
    {
        listenerList.remove ( ChooserListener.class, listener );
    }

    /**
     * Informs about color selection.
     *
     * @param oldColor previously selected Color
     * @param newColor new selected Color
     */
    public void fireColorSelected ( final Color oldColor, final Color newColor )
    {
        for ( final ChooserListener listener : listenerList.getListeners ( ChooserListener.class ) )
        {
            listener.selected ( oldColor, newColor );
        }
    }
}
TOP

Related Classes of com.alee.extended.colorchooser.WebColorChooserField

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.