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

com.formdev.flatlaf.ui.FlatDropShadowBorder Maven / Gradle / Ivy

There is a newer version: 3.5.2
Show newest version
/*
 * Copyright 2020 FormDev Software GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.formdev.flatlaf.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.RadialGradientPaint;
import java.awt.image.BufferedImage;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale;

/**
 * Paints a drop shadow border around the component.
 * Supports 1-sided, 2-side, 3-sided or 4-sided drop shadows.
 * 

* The shadow insets allow specifying drop shadow thickness for each side. * A zero or negative value hides the drop shadow on that side. * A negative value can be used to indent the drop shadow on corners. * E.g. -4 on left indents drop shadow at top-left and bottom-left corners by 4 pixels. * * @author Karl Tauber */ public class FlatDropShadowBorder extends FlatEmptyBorder { private final Color shadowColor; private final Insets shadowInsets; private final float shadowOpacity; private final int shadowSize; private Image shadowImage; private Color lastShadowColor; private double lastSystemScaleFactor; private float lastUserScaleFactor; public FlatDropShadowBorder() { this( null ); } public FlatDropShadowBorder( Color shadowColor ) { this( shadowColor, 4, 0.5f ); } public FlatDropShadowBorder( Color shadowColor, int shadowSize, float shadowOpacity ) { this( shadowColor, new Insets( -shadowSize, -shadowSize, shadowSize, shadowSize ), shadowOpacity ); } public FlatDropShadowBorder( Color shadowColor, Insets shadowInsets, float shadowOpacity ) { super( Math.max( shadowInsets.top, 0 ), Math.max( shadowInsets.left, 0 ), Math.max( shadowInsets.bottom, 0 ), Math.max( shadowInsets.right, 0 ) ); this.shadowColor = shadowColor; this.shadowInsets = shadowInsets; this.shadowOpacity = shadowOpacity; shadowSize = Math.max( Math.max( shadowInsets.left, shadowInsets.right ), Math.max( shadowInsets.top, shadowInsets.bottom ) ); } @Override public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { if( shadowSize <= 0 ) return; HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl ); } private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { Color shadowColor = (this.shadowColor != null) ? this.shadowColor : g.getColor(); int shadowSize = scale( this.shadowSize, scaleFactor ); // create and cache shadow image float userScaleFactor = UIScale.getUserScaleFactor(); if( shadowImage == null || !shadowColor.equals( lastShadowColor ) || lastSystemScaleFactor != scaleFactor || lastUserScaleFactor != userScaleFactor ) { shadowImage = createShadowImage( shadowColor, shadowSize, shadowOpacity, (float) (scaleFactor * userScaleFactor) ); lastShadowColor = shadowColor; lastSystemScaleFactor = scaleFactor; lastUserScaleFactor = userScaleFactor; } /*debug int m = shadowImage.getWidth( null ); Color oldColor = g.getColor(); g.setColor( Color.lightGray ); g.drawRect( x - m - 1, y - m - 1, m + 1, m + 1 ); g.setColor( Color.white ); g.fillRect( x - m, y - m, m, m ); g.drawImage( shadowImage, x - m, y - m, null ); g.setColor( oldColor ); debug*/ int left = scale( shadowInsets.left, scaleFactor ); int right = scale( shadowInsets.right, scaleFactor ); int top = scale( shadowInsets.top, scaleFactor ); int bottom = scale( shadowInsets.bottom, scaleFactor ); // shadow outer coordinates int x1o = x - Math.min( left, 0 ); int y1o = y - Math.min( top, 0 ); int x2o = x + width + Math.min( right, 0 ); int y2o = y + height + Math.min( bottom, 0 ); // shadow inner coordinates int x1i = x1o + shadowSize; int y1i = y1o + shadowSize; int x2i = x2o - shadowSize; int y2i = y2o - shadowSize; int wh = (shadowSize * 2) - 1; int center = shadowSize - 1; // left-top edge if( left > 0 || top > 0 ) { g.drawImage( shadowImage, x1o, y1o, x1i, y1i, 0, 0, center, center, null ); } // top shadow if( top > 0 ) { g.drawImage( shadowImage, x1i, y1o, x2i, y1i, center, 0, center + 1, center, null ); } // right-top edge if( right > 0 || top > 0 ) { g.drawImage( shadowImage, x2i, y1o, x2o, y1i, center, 0, wh, center, null ); } // left shadow if( left > 0 ) { g.drawImage( shadowImage, x1o, y1i, x1i, y2i, 0, center, center, center + 1, null ); } // right shadow if( right > 0 ) { g.drawImage( shadowImage, x2i, y1i, x2o, y2i, center, center, wh, center + 1, null ); } // left-bottom edge if( left > 0 || bottom > 0 ) { g.drawImage( shadowImage, x1o, y2i, x1i, y2o, 0, center, center, wh, null ); } // bottom shadow if( bottom > 0 ) { g.drawImage( shadowImage, x1i, y2i, x2i, y2o, center, center, center + 1, wh, null ); } // right-bottom edge if( right > 0 || bottom > 0 ) { g.drawImage( shadowImage, x2i, y2i, x2o, y2o, center, center, wh, wh, null ); } } private int scale( int value, double scaleFactor ) { return (int) Math.ceil( UIScale.scale( value ) * scaleFactor ); } private static BufferedImage createShadowImage( Color shadowColor, int shadowSize, float shadowOpacity, float scaleFactor ) { int shadowRGB = shadowColor.getRGB() & 0xffffff; int shadowAlpha = (int) (255 * shadowOpacity); Color startColor = new Color( shadowRGB | ((shadowAlpha & 0xff) << 24), true ); Color midColor = new Color( shadowRGB | (((shadowAlpha / 2) & 0xff) << 24), true ); Color endColor = new Color( shadowRGB, true ); /*debug startColor = Color.red; midColor = Color.green; endColor = Color.blue; debug*/ int wh = (shadowSize * 2) - 1; int center = shadowSize - 1; RadialGradientPaint p = new RadialGradientPaint( center, center, shadowSize - (0.75f * scaleFactor), new float[] { 0, 0.35f, 1 }, new Color[] { startColor, midColor, endColor } ); BufferedImage image = new BufferedImage( wh, wh, BufferedImage.TYPE_INT_ARGB ); Graphics2D g = image.createGraphics(); try { g.setPaint( p ); g.fillRect( 0, 0, wh, wh ); } finally { g.dispose(); } return image; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy