All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alee.extended.dock.DockablePaneGlassLayer Maven / Gradle / Ivy

There is a newer version: 1.2.14
Show newest version
/*
 * 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.dock;

import com.alee.extended.behavior.VisibilityBehavior;
import com.alee.extended.dock.data.DockableElement;
import com.alee.extended.dock.data.ResizeData;
import com.alee.extended.dock.drag.FrameDragData;
import com.alee.extended.dock.drag.FrameDragViewHandler;
import com.alee.extended.dock.drag.FrameDropData;
import com.alee.extended.dock.drag.FrameTransferable;
import com.alee.managers.drag.DragAdapter;
import com.alee.managers.drag.DragManager;
import com.alee.utils.GraphicsUtils;
import com.alee.utils.SwingUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * Custom glass layer for {@link com.alee.extended.dock.WebDockablePane}.
 * Unlike {@link javax.swing.JRootPane} glass layer it only covers dockable pane itself.
 *
 * @author Mikle Garin
 * @see How to use WebDockablePane
 * @see com.alee.extended.dock.WebDockablePane
 */
public class DockablePaneGlassLayer extends JComponent
{
    /**
     * todo 1. Maybe create new WebGlassLayer component with its own UI/painter with customizable multi subpainters?
     */

    /**
     * {@link com.alee.extended.dock.WebDockablePane} this glass pane is attached to.
     */
    protected final WebDockablePane dockablePane;

    /**
     * {@link com.alee.extended.dock.drag.FrameDropData} containing information about dragged frame.
     */
    protected FrameDropData frameDropData;

    /**
     * {@link com.alee.extended.dock.data.ResizeData} containting information about resized elements.
     */
    protected ResizeData resizeData;

    /**
     * Constructs new dockable pane glass layer.
     *
     * @param dockablePane {@link com.alee.extended.dock.WebDockablePane}
     */
    public DockablePaneGlassLayer ( final WebDockablePane dockablePane )
    {
        super ();
        this.dockablePane = dockablePane;
        initialize ();
    }

    /**
     * Initializes glass layer settings.
     */
    protected void initialize ()
    {
        // Visual settings
        setOpaque ( false );

        // Resize listener
        final MouseAdapter mouseListener = new MouseAdapter ()
        {
            private Point initialPoint = null;
            private DockableElement left;
            private DockableElement right;
            private Dimension initialLeftSize;
            private Dimension initialRightSize;

            @Override
            public void mousePressed ( final MouseEvent e )
            {
                if ( SwingUtils.isLeftMouseButton ( e ) )
                {
                    initialPoint = e.getPoint ();
                    resizeData = getResizeData ( e.getX (), e.getY () );
                    left = dockablePane.getModel ().getElement ( resizeData.leftElementId () );
                    initialLeftSize = left.getBounds ().getSize ();
                    right = dockablePane.getModel ().getElement ( resizeData.rightElementId () );
                    initialRightSize = right.getBounds ().getSize ();
                }
            }

            @Override
            public void mouseDragged ( final MouseEvent e )
            {
                if ( resizeData != null )
                {
                    // Resizing elements
                    final Dimension minLeft = left.getMinimumSize ( dockablePane );
                    final Dimension minRight = right.getMinimumSize ( dockablePane );
                    if ( resizeData.orientation ().isHorizontal () )
                    {
                        final int m = e.getX () - initialPoint.x;
                        final int change = m < 0 ? Math.max ( minLeft.width - initialLeftSize.width, m ) :
                                Math.min ( initialRightSize.width - minRight.width, m );
                        if ( !left.isContent () )
                        {
                            left.setSize ( new Dimension ( initialLeftSize.width + change, left.getSize ().height ) );
                        }
                        if ( !right.isContent () )
                        {
                            right.setSize ( new Dimension ( initialRightSize.width - change, right.getSize ().height ) );
                        }
                    }
                    else
                    {
                        final int m = e.getY () - initialPoint.y;
                        final int change = m < 0 ? Math.max ( minLeft.height - initialLeftSize.height, m ) :
                                Math.min ( initialRightSize.height - minRight.height, m );
                        if ( !left.isContent () )
                        {
                            left.setSize ( new Dimension ( left.getSize ().width, initialLeftSize.height + change ) );
                        }
                        if ( !right.isContent () )
                        {
                            right.setSize ( new Dimension ( right.getSize ().width, initialRightSize.height - change ) );
                        }
                    }

                    // Updatick dockable layout
                    dockablePane.revalidate ();
                }
            }

            @Override
            public void mouseReleased ( final MouseEvent e )
            {
                if ( SwingUtils.isLeftMouseButton ( e ) && resizeData != null )
                {
                    initialPoint = null;
                    resizeData = null;
                    left = null;
                    right = null;
                }
            }

            @Override
            public void mouseMoved ( final MouseEvent e )
            {
                final ResizeData data = getResizeData ( e.getX (), e.getY () );
                if ( data != null )
                {
                    // todo Decide cursor direction based on resized frames?
                    if ( data.orientation ().isVertical () )
                    {
                        DockablePaneGlassLayer.this.setCursor ( Cursor.getPredefinedCursor ( Cursor.S_RESIZE_CURSOR ) );
                    }
                    else
                    {
                        DockablePaneGlassLayer.this.setCursor ( Cursor.getPredefinedCursor ( Cursor.E_RESIZE_CURSOR ) );
                    }
                }
                else
                {
                    DockablePaneGlassLayer.this.setCursor ( Cursor.getDefaultCursor () );
                }
            }
        };
        addMouseListener ( mouseListener );
        addMouseMotionListener ( mouseListener );

        // Frame drop handler
        setTransferHandler ( new TransferHandler ()
        {
            @Override
            public boolean canImport ( final TransferSupport support )
            {
                final FrameDropData old = frameDropData;
                frameDropData = support.isDataFlavorSupported ( FrameTransferable.dataFlavor ) ?
                        dockablePane.getModel ().dropData ( dockablePane, support ) : null;
                if ( old != frameDropData )
                {
                    repaint ();
                }
                return frameDropData != null;
            }

            @Override
            public boolean importData ( final TransferSupport support )
            {
                return dockablePane.getModel ().drop ( dockablePane, support );
            }
        } );

        // Drag listener
        final DragAdapter dragListener = new DragAdapter ()
        {
            @Override
            public void exited ( final DragSourceEvent event )
            {
                clearDropLocation ();
            }

            @Override
            public void finished ( final DragSourceDropEvent event )
            {
                clearDropLocation ();
            }

            /**
             * Clears frame drop location data.
             */
            private void clearDropLocation ()
            {
                if ( frameDropData != null )
                {
                    frameDropData = null;
                    dockablePane.repaint ();
                }
            }
        };

        // Drag view handler
        final FrameDragViewHandler dragViewHandler = new FrameDragViewHandler ( dockablePane );

        // Visibility listener
        new VisibilityBehavior ( this )
        {
            @Override
            public void displayed ()
            {
                DragManager.addDragListener ( DockablePaneGlassLayer.this, dragListener );
                DragManager.registerViewHandler ( dragViewHandler );
            }

            @Override
            public void hidden ()
            {
                DragManager.unregisterViewHandler ( dragViewHandler );
                DragManager.removeDragListener ( DockablePaneGlassLayer.this, dragListener );
            }
        }.install ();
    }

    @Override
    protected void paintComponent ( final Graphics g )
    {
        if ( frameDropData != null )
        {
            final Graphics2D g2d = ( Graphics2D ) g;
            final int sw = 3;
            final int delta = sw % 2 != 0 ? 1 : 0;
            final int hf = ( int ) Math.round ( Math.floor ( sw / 2f ) );
            final Stroke os = GraphicsUtils.setupStroke ( g2d, new BasicStroke ( sw ) );

            final Rectangle dl = frameDropData.getHighlight ();
            g2d.setPaint ( new Color ( 0, 0, 255, 55 ) );
            g2d.fillRect ( dl.x + sw, dl.y + sw, dl.width - sw * 2 + delta, dl.height - sw * 2 + delta );
            g2d.setPaint ( new Color ( 0, 0, 0, 100 ) );
            g2d.drawRect ( dl.x + hf, dl.y + hf, dl.width - hf * 2, dl.height - hf * 2 );

            GraphicsUtils.restoreStroke ( g2d, os );
        }
    }

    @Override
    public boolean contains ( final int x, final int y )
    {
        return checkDrag () || checkResize ( x, y );
    }

    /**
     * Returns whether or not frame is being dragged.
     *
     * @return true if frame is being dragged, false otherwise
     */
    protected boolean checkDrag ()
    {
        if ( frameDropData != null )
        {
            return true;
        }
        else if ( DragManager.isDragging ( FrameTransferable.dataFlavor ) )
        {
            try
            {
                final Transferable transferable = DragManager.getTransferable ();
                final FrameDragData data = ( FrameDragData ) transferable.getTransferData ( FrameTransferable.dataFlavor );
                return dockablePane.getFrame ( data.getId () ) != null;
            }
            catch ( final Exception ignored )
            {
                //
            }
        }
        return false;
    }

    /**
     * Returns whether or not resize operation is rolling or specified point is on top of resize gripper.
     *
     * @param x X coordinate
     * @param y Y coordinate
     * @return true if resize operation is rolling or specified point is on top of resize gripper, false otherwise
     */
    protected boolean checkResize ( final int x, final int y )
    {
        return resizeData != null || getResizeData ( x, y ) != null;
    }

    /**
     * Returns resize data under specified coordinate or {@code null}.
     *
     * @param x X coordinate
     * @param y Y coordinate
     * @return resize data under specified coordinate or {@code null}
     */
    protected ResizeData getResizeData ( final int x, final int y )
    {
        return dockablePane.getModel ().getResizeData ( x, y );
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy