package tutorial.core.basics; import java.awt.AlphaComposite; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.image.BufferedImage; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.SwingUtilities; import tutorial.support.JTutorialFrame; import tutorial.support.Tutorial; import bibliothek.extension.gui.dock.theme.FlatTheme; import bibliothek.gui.DockController; import bibliothek.gui.DockTheme; import bibliothek.gui.dock.DefaultDockable; import bibliothek.gui.dock.FlapDockStation; import bibliothek.gui.dock.ScreenDockStation; import bibliothek.gui.dock.SplitDockStation; import bibliothek.gui.dock.station.split.SplitDockGrid; import bibliothek.gui.dock.themes.ThemeManager; import bibliothek.gui.dock.util.BackgroundAlgorithm; import bibliothek.gui.dock.util.BackgroundComponent; import bibliothek.gui.dock.util.BackgroundPaint; import bibliothek.gui.dock.util.BackgroundPanel; import bibliothek.gui.dock.util.PaintableComponent; import bibliothek.gui.dock.util.Transparency; @Tutorial( id="Background", title="Background" ) public class BackgroundExample { /* (Almost) all components of the framework use a special strategy to paint their content. Clients * can replace that algorithm and paint the components in any way the like. */ public static void main( String[] args ) throws IOException{ /* setting up frame and controller as usual */ JTutorialFrame frame = new JTutorialFrame( BackgroundExample.class ); DockController controller = new DockController(); controller.setRootWindow( frame ); frame.destroyOnClose( controller ); /* We are going to create a transparency effect with an image shining through the application. While we * keep icons and text solid, we will paint the original background and borders semi-transparent. * We will use an alpha value of 0.5 for decorations like titles and buttons, and a value of 0.75 for * the parts where the user would work on. */ AlphaComposite alphaDecoration = AlphaComposite.getInstance( AlphaComposite.SRC_ATOP, 0.5f ); AlphaComposite alphaWork = AlphaComposite.getInstance( AlphaComposite.SRC_ATOP, 0.75f ); /* The background image we are going to use */ BufferedImage image = ImageIO.read( BackgroundPanel.class.getResource( "/data/tutorial/shadowsAndLight_GregMartin.jpg" ) ); /* There are several possibilities how to apply our custom background. The easiest one is to use the properties * to replace the default strategy. */ controller.getProperties().set( DockTheme.BACKGROUND_PAINT, new CustomPaint( frame.getContentPane(), image, alphaDecoration ) ); /* By accessing the ThemeManager we can set a strategy that is used by only one type of component. In this case * we set a custom identifier which will later be used by our "BackgroundDockable" which is shown later in this * example. */ controller.getThemeManager().setBackgroundPaint( ThemeManager.BACKGROUND_PAINT + ".custom", new CustomPaint( frame.getContentPane(), image, alphaWork ) ); /* We can apply different themes. Depending on the theme we might need to make some additional addjustements * to create a good looking application. */ // controller.setTheme( new EclipseTheme() ); // controller.setTheme( new BubbleTheme() ); // controller.setTheme( new BasicTheme() ); controller.setTheme( new FlatTheme() ); /* And now we set up different DockStations and Dockables */ SplitDockStation splitDockStation = new SplitDockStation(); controller.add( splitDockStation ); frame.add( splitDockStation ); SplitDockGrid grid = new SplitDockGrid(); grid.addDockable( 0, 0, 100, 20, new BackgroundDockable( "Red", Color.RED )); grid.addDockable( 0, 20, 30, 50, new BackgroundDockable( "Blue", Color.BLUE )); grid.addDockable( 0, 70, 30, 30, new BackgroundDockable( "Yellow", Color.YELLOW )); grid.addDockable( 30, 20, 80, 80, new BackgroundDockable( "White", Color.WHITE )); grid.addDockable( 30, 20, 80, 80, new BackgroundDockable( "Black", Color.BLACK )); splitDockStation.dropTree( grid.toTree() ); FlapDockStation flapDockStation = new FlapDockStation(); controller.add( flapDockStation ); flapDockStation.add( new BackgroundDockable( "Green", Color.GREEN )); frame.add( flapDockStation.getComponent(), BorderLayout.NORTH ); ScreenDockStation screenDockStation = new ScreenDockStation( controller.getRootWindowProvider() ); controller.add( screenDockStation ); /* Now we make all frames and windows visible. */ frame.setVisible( true ); screenDockStation.setShowing( true ); } /* This helper method creates an image we use for the background */ private static BufferedImage createBackground( BufferedImage image, int width, int height ){ if( width <= 0 || height <= 0 ){ return null; } BufferedImage result = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB ); Graphics g = result.createGraphics(); g.setColor( Color.BLACK ); g.fillRect( 0, 0, width, height ); int imageWidth = image.getWidth(); int imageHeight = image.getHeight(); int mw = Math.min( width, imageWidth ); int mh = Math.min( height, imageHeight ); g.drawImage( image, width/2-mw/2, height/2-mh/2, width/2+mw/2, height/2+mh/2, imageWidth/2-mw/2, imageHeight/2-mh/2, imageWidth/2+mw/2, imageHeight/2+mh/2, null ); g.dispose(); return result; } /* This is our custom painting algorithm */ private static class CustomPaint implements BackgroundPaint{ /* the entire image as it was read from the disk */ private BufferedImage baseImage; /* an image with the same size as the frame */ private BufferedImage image; /* our anchor point, the location 0/0 of our image and of this component will always match */ private Component content; /* the alpha value we are going to apply for transparency effects */ private AlphaComposite alpha; /* standard constructor */ private CustomPaint( Component content, BufferedImage image, AlphaComposite alpha ){ this.alpha = alpha; this.content = content; this.baseImage = image; } public void install( BackgroundComponent component ){ // ignore } public void uninstall( BackgroundComponent component ){ // ignore } /* gets the image that should be used for painting */ public BufferedImage getImage(){ if( image == null || image.getWidth() != content.getWidth() || image.getHeight() != content.getHeight() ){ image = createBackground( baseImage, content.getWidth(), content.getHeight() ); } return image; } /* this is the method that paints the background */ public void paint( BackgroundComponent background, PaintableComponent paintable, Graphics g ){ if( SwingUtilities.isDescendingFrom( background.getComponent(), content )){ /* If we are painting an non-transparent component we paint our custom background image, otherwise * we just let it shine through */ if( paintable.getTransparency() == Transparency.SOLID ){ Point point = new Point( 0, 0 ); point = SwingUtilities.convertPoint( paintable.getComponent(), point, content ); BufferedImage image = getImage(); if( image != null ){ int w = paintable.getComponent().getWidth(); int h = paintable.getComponent().getHeight(); g.drawImage( image, 0, 0, w, h, point.x, point.y, point.x + w, point.y + h, null ); } } /* and now we paint the original content of the component */ Graphics2D g2 = (Graphics2D)g.create(); g2.setComposite( alpha ); paintable.paintBackground( g2 ); paintable.paintForeground( g ); paintable.paintBorder( g2 ); g2.dispose(); paintable.paintChildren( g ); } } } /* This is a specialized Dockable with a colored panel that seems to be transparent. */ private static class BackgroundDockable extends DefaultDockable{ private BackgroundPanel panel; private BackgroundAlgorithm background; public BackgroundDockable( String title, Color color ){ super( title ); /* We use a BackgroundPanel: it already offers methods to use a replaceable strategy * for painting. */ panel = new BackgroundPanel( Transparency.SOLID ){ @Override protected void configure( Transparency transparency ){ // we ignore transparency settings. These settings are made by the client and since in this // example we do not set transparency this method will never be called anyway } @Override protected void setupRenderingHints( Graphics g ) { // we do not set any rendering hints (like antialising) } }; panel.setBackground( color ); add( panel ); /* And we need a connection between our panel and the framework. The connection has a * type (called "kind") and a unique identifier. The identifier matches the one identifier we * used to register our speical background algorithm. */ background = new BackgroundAlgorithm( BackgroundComponent.KIND.append( "custom" ), ThemeManager.BACKGROUND_PAINT + ".custom" ){ public Component getComponent(){ return panel; } }; panel.setBackground( background ); } @Override public void setController( DockController controller ){ super.setController( controller ); /* The connection between panel and framework needs to know the current DockController in * order to work. */ background.setController( controller ); } } }