Minimizing dockable to nearest flapdockstation

Hi Beni,

is it possible that a dockable minimizes to the flapdockstation which is the nearest one to the dockable instead of the last used/default flapdockstation.

For example:
There are 3 dockables:

+-----------+-----------------+
|   A       |       B         |
|           |                 |
|           +-----------------+
|           |       C         |
|           |                 |
+-----------+-----------------+```

If dockable A gets minized it would go to the west flapdockstation, if dockable C is minized it would go to the south flapdockstation.

Greetz,
Thomas

You can replace the action that is responsible for minimizing Dockables. This way you can implement any behavior you like. The example below should explain everything.


import java.awt.Color;
import java.awt.Component;
import java.awt.Point;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CGrid;
import bibliothek.gui.dock.common.CLocation;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.action.predefined.CMinimizeAction;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.mode.ExtendedMode;
import bibliothek.gui.dock.common.theme.ThemeMap;
 
public class Dock44 {
	public static final boolean MOVE_DOCKABLE_ALONE = false;
	
    public static void main(String[] args) {
    	//Setting up a test frame
        JFrame frame = new JFrame("Demo");
        CControl control = new CControl(  );
        control.setTheme( ThemeMap.KEY_ECLIPSE_THEME );
        
        frame.add(control.getContentArea());
        
        // this is a special action that will replace the normal minimize action
        CustomButton button = new CustomButton( control, control.getContentArea().getCenter().getComponent() );
        
        CGrid grid = new CGrid( control );
        grid.add(0, 0, 1, 1, createDockable( "Red", Color.RED, button ));
        grid.add(0, 1, 1, 1, createDockable( "Blue", Color.BLUE, button ));
        grid.add(1, 0, 1, 1, createDockable( "Green", Color.GREEN, button ));
        grid.add(1, 1, 1, 1, createDockable( "Yellow", Color.YELLOW, button ));
        control.getContentArea().deploy( grid );
 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(20, 20, 400, 400);
        frame.setVisible(true);
    }
    
    public static CDockable createDockable(String title, Color color, CustomButton minimize ) {
        JPanel panel = new JPanel();
        panel.setOpaque(true);
        panel.setBackground(color);
        DefaultSingleCDockable dockable = new DefaultSingleCDockable( title );
        dockable.setTitleText( title );
        dockable.add( panel );
        dockable.setCloseable( false );
       
        // at this point we tell the dockable to use our customized minimize action
        dockable.putAction( CDockable.ACTION_KEY_MINIMIZE, minimize );
        
        return dockable;
    }

    // our customized minimize action will minimize the dockables in a new way
    private static class CustomButton extends CMinimizeAction{
    	private CControl control;
    	private Component base;
    	
    	public CustomButton( CControl control, Component base ){
    		super( control );
    		this.control = control;
    		this.base = base;
    	}
    	
    	@Override
    	public void action( CDockable dockable ){
    		CLocation location = bestDestination( dockable );
    		if( location == null ){
    			super.action( dockable );
    		}
    		else if( MOVE_DOCKABLE_ALONE ){
    			// the easy solution, moves only this dockable
    			dockable.setLocation( location );
    		}
    		else{
    			// the more advanced solution, if there is a stack of dockables then the entire stack
    			// of dockables is moved. Here we just change the default position of "dockable".
    			control.getLocationManager().setLocation( dockable.intern(), ExtendedMode.MINIMIZED, location );
    			super.action( dockable );
    		}
    	}
    	
    	// find the nearest edge for a given dockable
    	private CLocation bestDestination( CDockable dockable ){
    		Component dock = dockable.intern().getComponent();
    		if( !SwingUtilities.isDescendingFrom( dock, base )){
    			return null;
    		}
    		Point middle = new Point( dock.getWidth()/2, dock.getHeight()/2 );
    		middle = SwingUtilities.convertPoint( dock, middle, base );
    		
    		boolean topleft = above( 0, base.getHeight(), base.getWidth(), 0, middle.x, middle.y );
    		boolean topright = above( 0, 0, base.getWidth(), base.getHeight(), middle.x, middle.y );
    		
    		if( topleft && topright ){
    			return CLocation.base().minimalNorth();
    		}
    		else if( topleft && !topright ){
    			return CLocation.base().minimalWest();
    		}
    		else if( !topleft && topright ){
    			return CLocation.base().minimalEast();
    		}
    		else{
    			return CLocation.base().minimalSouth();
    		}
    	}
    	
        public static boolean above( double x1, double y1, double x2, double y2, double x, double y ){
            double a = y1 - y2;
            double b = x2 - x1;
            
            if( b == 0 )
                return false;
            
            double c = a*x1 + b*y1;
            double sy = (c - a*x) / b;
            
            return y < sy;
        }
    }
}

Hi Beni,

thanks for that solution, it works almost the way I wanted. A little tweaking and it is perfect :slight_smile:

Greetz,
Thomas