Is there any way that i can change the behavior of the pushpin button? The one that causes the visible flap-dock panels to stay visible. I would like for the pushpin to cause the panel to become docked in the pane just below it. Or maybe there is already a standard way to do that?
There is no standard way to do something like this, but with a some tricky and some ugly code it is possible.
Down below you have a little example application that replaces the old sticky button with a custom button. This example will put all the Dockable at the top of the frame, but it should be a good starting point for further refinments.
package test;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import javax.swing.Icon;
import javax.swing.JFrame;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.FlapDockStation;
import bibliothek.gui.dock.action.ActionGuard;
import bibliothek.gui.dock.action.DefaultActionOffer;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.FilteredDockActionSource;
import bibliothek.gui.dock.action.LocationHint;
import bibliothek.gui.dock.action.actions.SimpleButtonAction;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CLocation;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.event.CControlListener;
import bibliothek.gui.dock.common.intern.AbstractCDockable;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;
import bibliothek.gui.dock.station.flap.FlapDockHoldToggle;
import bibliothek.gui.dock.station.flap.button.ButtonContentAction;
public class CustomStickyButtonTest {
public static void main( String[] args ) {
JFrame frame = new JFrame();
CControl control = new CControl( frame );
hideStickyButton( control );
installCustomButton( control );
frame.add( control.getContentArea() );
for( int i = 0; i < 10; i++ ) {
DefaultSingleCDockable dockable = new DefaultSingleCDockable( "i" + i, "Title " + i );
control.addDockable( dockable );
dockable.setLocation( CLocation.base().normal().stack() );
dockable.setVisible( true );
}
frame.setBounds( 20, 20, 800, 800 );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );
}
private static void hideStickyButton( CControl control ) {
// it's up to you which solution you like more, personally I would go with the first one
hideStickyButtonSolution1( control );
// hideStickyButtonSolution2( control );
}
private static void hideStickyButtonSolution1( CControl control ) {
// hide the original button by disabling the "sticky" feature on all Dockables
control.addControlListener( new CControlListener() {
@Override
public void removed( CControl control, CDockable dockable ) {
}
@Override
public void opened( CControl control, CDockable dockable ) {
}
@Override
public void closed( CControl control, CDockable dockable ) {
}
@Override
public void added( CControl control, CDockable dockable ) {
if( dockable instanceof AbstractCDockable ) {
((AbstractCDockable) dockable).setStickySwitchable( false );
}
}
} );
}
private static void hideStickyButtonSolution2( CControl control ) {
// hide the original button by filtering the action
control.getController().setDefaultActionOffer( new DefaultActionOffer() {
@Override
public DockActionSource getSource( Dockable dockable, DockActionSource source, DockActionSource[] guards, DockActionSource parent, DockActionSource[] parents ) {
DockActionSource all = super.getSource( dockable, source, guards, parent, parents );
return new FilteredDockActionSource( all ) {
@Override
protected boolean include( DockAction action ) {
return !(action instanceof FlapDockHoldToggle);
}
};
}
} );
}
private static void installCustomButton( CControl control ) {
// installing a new "ActionGuard", which will "inject" an action at the place where the old sticky action was
// showing up
control.getController().addActionGuard( new ActionGuard() {
private DockActionSource customDockAction = createCustomButtonSource();
@Override
public boolean react( Dockable dockable ) {
if( !(dockable instanceof CommonDockable) ) {
return false;
}
DockStation parent = dockable.getDockParent();
while( parent != null ) {
// you might want to compare "parent" with stations like "control.getContentArea().getNorth()" to
// create one button for each of the differnt sides.
if( parent instanceof FlapDockStation ) {
return true;
}
dockable = parent.asDockable();
if( dockable == null ) {
return false;
}
parent = dockable.getDockParent();
}
return false;
}
@Override
public DockActionSource getSource( Dockable dockable ) {
return customDockAction;
}
} );
}
// an "action source" is just a List with DockActions.
private static DockActionSource createCustomButtonSource() {
DockAction action = new MyStickyButton();
DefaultDockActionSource source = new DefaultDockActionSource( new LocationHint( LocationHint.DIRECT_ACTION, LocationHint.LITTLE_LEFT ) );
source.add( action );
return source;
}
@ButtonContentAction
private static class MyStickyButton extends SimpleButtonAction {
public MyStickyButton() {
setText( "my custom button" );
setIcon( new Icon() {
@Override
public void paintIcon( Component c, Graphics g, int x, int y ) {
g.setColor( Color.RED );
g.fillRect( x, y, 16, 16 );
}
@Override
public int getIconWidth() {
return 16;
}
@Override
public int getIconHeight() {
return 16;
}
} );
}
public void action( Dockable dockable ) {
((CommonDockable) dockable).getDockable().setLocation( CLocation.base().normal().north( 0.25 ).stack() );
}
}
}
I just wanted to reply with a thank you. This code snippet totally did the trick!