package Schmortopf.Utility.gui;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.awt.*;
import java.io.*;
import java.util.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.beans.*;
import javax.swing.plaf.metal.*;
import Schmortopf.Utility.themes.*;
public class EFCNToolGradientPanel extends JPanel
{
// The gradient types :
public static int ApplyUpperLeftCornerHighLight = 0;
public static int ApplyVerticalHighLight = 1;
// Some predefined color keystrings :
public static String ActiveTitleBackground = "InternalFrame.activeTitleBackground";
public static String PanelBackground = "Panel.background";
// The gradient strength :
public static int LightGradientStrength = 0;
public static int MediumGradientStrength = 1;
public static int StrongGradientStrength = 2;
private Color lightColor = new Color(190,190,250);
private Color mediumColor = new Color(120,120,180);
private Color darkColor = new Color(80,80,120);
float xGradient;
private Color basisColor; // around this the gradient will be
// gradient look : (defaults)
private int gradientType = ApplyUpperLeftCornerHighLight;
private int gradientStrength = MediumGradientStrength;
private String colorKey = ActiveTitleBackground;
float gradientLength;
private int finalColorOffset;
private int colorOffset;
private boolean displayBackGroundPicture = true;
// this can be turned off/on
private boolean useParentBackGround = false; // when a background color has been assigned
private ImageIcon backgroundImage = null;
// This is set according to the current theme, and changes,
// when the theme changes. It isnt used, if
// displayBackGroundPicture is false.
private ImageIcon customBackgroundImage = null;
// This can be set by using one of the constructors.
// If this is set, this backgroundimage is used always,
// and not the one associated to the current theme.
private boolean readyForSpecialUpdates = false;
// Needed, as some updateUI() calls are too early
// for the special UI updates, cause some components
// could not be existing yet.
/**
* Creates a panel where you can pass
* theGradientType = ApplyUpperLeftCornerHighLight
* or ApplyVerticalHighLight
*
* and
* theGradientStrength = LightGradientStrength
* or MediumGradientStrength
* or StrongGradientStrength
*
* and
* theColorKey = null
* or ActiveTitleBackground
* or PanelBackground
* or any valid theme colorkey.
*
*/
public EFCNToolGradientPanel( final int theGradientType,
final int theGradientStrength,
final String theColorKey )
{
this( new BorderLayout(),true,theGradientType,theGradientStrength,theColorKey );
}
/**
* Creates a panel where you can pass
* theGradientType = ApplyUpperLeftCornerHighLight
* or ApplyVerticalHighLight
*
* and
* theGradientStrength = LightGradientStrength
* or MediumGradientStrength
* or StrongGradientStrength
*
* and
* theColorKey = null
* or ActiveTitleBackground
* or PanelBackground
* or any valid theme colorkey.
*
*/
public EFCNToolGradientPanel( LayoutManager layout,
int theGradientType,
int theGradientStrength,
String theColorKey )
{
this(layout,true,theGradientType,theGradientStrength,theColorKey);
}
/**
* Creates a panel where you can pass
* theGradientType = ApplyUpperLeftCornerHighLight
* or ApplyVerticalHighLight
*
* and
* theGradientStrength = LightGradientStrength
* or MediumGradientStrength
* or StrongGradientStrength
*
* and
* theColorKey = null
* or ActiveTitleBackground
* or PanelBackground
* or any valid theme colorkey.
*
*/
public EFCNToolGradientPanel( LayoutManager layout,
boolean isDoubleBuffered,
int theGradientType,
int theGradientStrength,
String theColorKey )
{
super(layout,isDoubleBuffered);
this.gradientType = theGradientType;
this.gradientStrength = theGradientStrength;
if( colorKey != null )
{
this.colorKey = theColorKey;
} // else use the default
// scale the gradient along with the current font size :
float unitSize = UIManager.getFont("TextField.font").getSize2D();
this.xGradient = unitSize;
this.updateSpecialUI(); // sets basisColor, startColor and endColor
this.colorOffset = 0; // This will increased to the value of
// finalColorOffset in a few steps by the
// startupThread.
this.finalColorOffset = 70; // medium gradient strength
if( this.gradientStrength == LightGradientStrength )
{
this.finalColorOffset = 40;
}
if( this.gradientStrength == StrongGradientStrength )
{
this.finalColorOffset = 90;
}
// Launch the startupthread, which will increase the coloroffset :
final StartupThread startupThread = new StartupThread(this);
// but launch him after all swing work has been done -
// so set it into the swing queue :
EventQueue.invokeLater( new Runnable()
{
public void run()
{
startupThread.start();
}
});
EventQueue.invokeLater( new Runnable()
{
public void run()
{
readyForSpecialUpdates = true;
}
});
} // Constructor
/**
* Just calls <code>paint(g)</code>. This method was overridden to
* prevent an unnecessary call to clear the background.
*
* @param g the Graphics context in which to paint
*/
public void update(Graphics g)
{
this.paint(g);
}
/**
* Overwritten method. Additionally updates special components.
*/
public void updateUI()
{
super.updateUI();
if( this.readyForSpecialUpdates )
{
if( !useParentBackGround ) // only if setBackground was never called
{
updateSpecialUI();
// rescale the gradient along with the current font size :
float unitSize = UIManager.getFont("TextField.font").getSize2D();
xGradient = unitSize;
}
}
}
/**
* This last constructor additionally defines a custom background
* picture. If this constructor is used, the passed backround
* picture will be used for ever, instead of getting or changing
* the background picture with the theme.
*/
public EFCNToolGradientPanel( LayoutManager layout,
int theGradientType,
int theGradientStrength,
String theColorKey,
ImageIcon customBackgroundImage )
{
this( layout,theGradientType,theGradientStrength,theColorKey);
this.customBackgroundImage = customBackgroundImage;
}
/**
* Set a a fixed background color, and with that : turns out the
* UIManager update mechanism.
*/
public void setConstantBackground( Color bgColor )
{
super.setBackground(bgColor);
this.useParentBackGround = true; // turns off UIManager special update
this.basisColor = super.getBackground();
this.calculateColors();
}
/**
* Calculate the start and endcolor of the gradient
* taking the basisColor as center color :
*/
private void calculateColors()
{
int rBase = this.basisColor.getRed();
int gBase = this.basisColor.getGreen();
int bBase = this.basisColor.getBlue();
// start color is lighter :
int rStart = rBase + colorOffset;
int gStart = gBase + colorOffset;
int bStart = bBase + colorOffset;
if( (rStart <= 255) && (gStart <= 255) && (bStart <= 255) )
{
this.lightColor = new Color( rStart,gStart,bStart );
} else
{
if( rStart > 255 ) rStart = 255;
if( gStart > 255 ) gStart = 255;
if( bStart > 255 ) bStart = 255;
this.lightColor = new Color( rStart,gStart,bStart );
}
this.mediumColor = this.basisColor;
rStart = rBase - colorOffset;
gStart = gBase - colorOffset;
bStart = bBase - colorOffset;
if( (rStart >= 0) && (gStart >= 0) && (bStart >= 0) )
{
this.darkColor = new Color( rStart,gStart,bStart );
} else
{
if( rStart < 0 ) rStart = 0;
if( gStart < 0 ) gStart = 0;
if( bStart < 0 ) bStart = 0;
this.darkColor = new Color( rStart,gStart,bStart );
}
// If the current panel has a background image, we use this one and
// set the medium color slightly transparent :
// The background image is valid, when there is a theme with background
// image OR when a custom backgroundimage was set :
// Intro scaling : During the startup thread loops,
// the colorOffset goes from a fraction of finalColorOffset
// in some steps upto this.finalColorOffset. We use this to
// zoom in the transparency :
double introShift = 50.0 * (this.finalColorOffset-this.colorOffset)/(1.0*this.finalColorOffset);
int alphaColor = 170 + (int)introShift;
if( alphaColor > 255 ) alphaColor = 255;
if( alphaColor < 0 ) alphaColor = 0;
if( this.displayBackGroundPicture )
{
if( this.customBackgroundImage != null )
{
// A custom image was set, so set the color a bit transparent :
this.mediumColor = new Color( mediumColor.getRed(),
mediumColor.getGreen(),
mediumColor.getBlue(),
alphaColor );
// and use this one :
this.backgroundImage = this.customBackgroundImage;
} else
{
// Check if we have a background image from the current theme:
sun.awt.AppContext context = sun.awt.AppContext.getAppContext();
if( context != null)
{
MetalTheme currentTheme = (MetalTheme)context.get( "currentMetalTheme" );
if( currentTheme != null )
{
if( currentTheme instanceof EFCNThemesBasis )
{
EFCNThemesBasis efcnTheme = (EFCNThemesBasis)currentTheme;
this.backgroundImage = efcnTheme.getBackgroundImage();
if( this.backgroundImage != null )
{
this.mediumColor = new Color( mediumColor.getRed(),
mediumColor.getGreen(),
mediumColor.getBlue(),
alphaColor );
}
}
}
}
}
}
} // calculateColors
/**
* Must be called, when the lf theme changes.
* Called by the propertychange listener above.
*/
public void updateSpecialUI()
{
// Derive the basisColor :
Color color = UIManager.getColor( this.colorKey );
// give more green and blue
int r = color.getRed() - 5;
int g = color.getGreen() - 5;
int b = color.getBlue() + 10;
// level out grayscale value a bit :
if( r+g+b > 384 )
{
r -= 10;
g -= 10;
b -= 10;
} else
{
r += 10;
g += 10;
b += 10;
}
// keep in range :
if( r < 0 ) r = 0; if( r > 255 ) r = 255;
if( g < 0 ) g = 0; if( g > 255 ) g = 255;
if( b < 0 ) b = 0; if( b > 255 ) b = 255;
// and set it as basis :
this.basisColor = new Color(r,g,b);
// Calculate the start and endColors from that :
this.calculateColors();
}
/**
* Overwritten paint method to have a slight color gradient.
*/
public void paint( Graphics g )
{
Graphics2D graphics2D = (Graphics2D)g;
final Paint savePaint = graphics2D.getPaint();
// draw the background image, if we have one.
// In this panel, we zoom the pic to fit horizontally,
// and tile vertically :
if( ( this.backgroundImage != null ) &&
(this.displayBackGroundPicture ) )
{
int xMax = this.getWidth();
int yMax = this.getHeight();
int imageWidth = this.backgroundImage.getIconWidth();
int imageHeight = this.backgroundImage.getIconHeight();
int x0 = this.getLocation().x;
int y0 = this.getLocation().y;
// Security [prevents endless loop, case an attribute is zero]
if( (xMax > 1 ) &&
(yMax > 1 ) &&
(imageWidth > 1 ) &&
(imageHeight > 1 ) )
{
AffineTransform backupTransform = graphics2D.getTransform();
// zoom the background picture to fit the width, keep aspect ratio :
AffineTransform xform = new AffineTransform();
double scaleFactor = (1.0 * xMax) / (1.0 * imageWidth);
xform.scale(scaleFactor,scaleFactor);
// Tile vertically :
int currentHeight = 0;
int verticalOffset = (int)(scaleFactor*imageHeight);
while( currentHeight < yMax )
{
graphics2D.drawImage( backgroundImage.getImage() ,xform,this );
currentHeight += verticalOffset;
xform.translate(0.0,imageHeight);
}
// Restore the previous graphics2D transformation :
graphics2D.setTransform(backupTransform);
} // if pic is ok
} // if
if( this.gradientType == ApplyUpperLeftCornerHighLight )
{
GradientPaint upperLeftGradientPaint =
new GradientPaint( 0f,0f,
lightColor,
xGradient,xGradient*5.0f,
mediumColor );
graphics2D.setPaint( upperLeftGradientPaint );
graphics2D.fill( graphics2D.getClip() );
}
else if( this.gradientType == ApplyVerticalHighLight )
{
this.gradientLength = xGradient;
if( gradientLength > this.getHeight()/2.5f )
{
gradientLength = this.getHeight()/2.5f;
}
GradientPaint upperVerticalGradientPaint =
new GradientPaint( 0f,0f,
this.lightColor,
0f, gradientLength,
this.mediumColor );
GradientPaint lowerVerticalGradientPaint =
new GradientPaint( 0f,getHeight(),
this.darkColor,
0f,getHeight() - gradientLength,
this.mediumColor );
Shape saveClip = graphics2D.getClip();
Rectangle rLower = new Rectangle( 0,getHeight()/2,getWidth(),1+getHeight()/2 );
graphics2D.setPaint( lowerVerticalGradientPaint );
graphics2D.fill( rLower );
Rectangle rUpper = new Rectangle( 0,0,getWidth(),1+getHeight()/2 );
graphics2D.setPaint( upperVerticalGradientPaint );
graphics2D.fill( rUpper );
graphics2D.setClip(saveClip);
}
graphics2D.setPaint( savePaint );
super.paintChildren(graphics2D);
} // paint
public boolean imageUpdate( Image img, int infoflags,
int x, int y, int width, int height)
{
return true;
}
public float getGradientLength()
{
return this.gradientLength;
}
/**
* Changes the color offset. Must be called inside
* the event dispatch thread.
*/
public void setColorOffset( int newValue )
{
this.colorOffset = newValue;
this.calculateColors();
if( this.isShowing() )
{
this.updateUI();
}
}
public void setDisplayBackgroundPicture( boolean use )
{
this.displayBackGroundPicture = use;
}
public int getFinalColorOffset()
{
return this.finalColorOffset;
}
/**
* The startup thread, which makes this panel shape itself
* in the first 3 seconds of its lifetime
*/
private class StartupThread extends Thread
{
private EFCNToolGradientPanel bgPanel;
public StartupThread( EFCNToolGradientPanel bgPanel )
{
this.bgPanel = bgPanel;
this.setDaemon(true);
}
public void run()
{
int loops = 16;
double offsetStep = (1.0*bgPanel.getFinalColorOffset())/(1.0*loops);
for( int i=1; i <= loops; i++ )
{
final int colorOffset = (int)(i*offsetStep);
SwingUtilities.invokeLater( new Runnable()
{
public void run()
{
bgPanel.setColorOffset(colorOffset);
}
});
if( i==1 )
{
// Wait half a second initially - increases the effect :
try{ Thread.sleep(660); } catch( Exception sdfkjh ){ }
}
else
{
try{ Thread.sleep(90); } catch(Exception wurscht ){}
}
}
}
} // class StartupThread
} // EFCNToolGradientPanel
|