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

org.netbeans.swing.tabcontrol.plaf.BusyIcon Maven / Gradle / Ivy

There is a newer version: RELEASE230
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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
 *
 *   http://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 org.netbeans.swing.tabcontrol.plaf;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import javax.swing.Icon;
import javax.swing.UIManager;
import org.openide.util.ImageUtilities;

/**
 * An animated icon to indicate that a tab is 'busy'.
 * @see BusyTabsSupport
 * @author S. Aubrecht
 * @since 1.34
 */
abstract class BusyIcon implements Icon {

    protected final int width;
    protected final int height;

    protected BusyIcon( int width, int height ) {
        this.width = width;
        this.height = height;
    }
    
    /**
     * 

Creates a new instance.

*

* The implementation first checks UIManager defaults and looks for Icon * under keys "nb.tabcontrol.busy.icon.selected" and "nb.tabcontrol.busy.icon.normal". * If there is an Icon under those keys then the created instance will rotate * that Icon to animate it. *

* If there are no icons in UIManager then a default "spinner" icon will be drawn. This default * icon looks very similar to the JProgressBar spinner on the Aqua LAF (when used with the * client property JProgressBar.style=circular), and will scale properly on HiDPI screens. *

* * @param selectedTab Boolean to create icon for selected tab state, false * to create icon for normal tab state. * @return Animated icon. */ public static BusyIcon create( boolean selectedTab ) { Icon img = UIManager.getIcon( "nb.tabcontrol.busy.icon." + (selectedTab ? "selected" : "normal") ); //NOI18N if( null != img ) { return new ImageBusyIcon( ImageUtilities.icon2Image( img ) ); } else { return VectorBusyIcon.create(); } } abstract void tick(); @Override public final int getIconWidth() { return width; } @Override public final int getIconHeight() { return height; } private static class ImageBusyIcon extends BusyIcon { private final Image img; private int state = 0; private AffineTransform at; private static final int STEP = 15; public ImageBusyIcon( Image img ) { super( img.getWidth( null ), img.getHeight( null ) ); this.img = img; } @Override void tick() { state += STEP; if( state >= 360 ) state = 0; at = new AffineTransform(); at.rotate( state * Math.PI / 180.0, width/2, height/2 ); } @Override public void paintIcon( Component c, Graphics g, int x, int y ) { if( g instanceof Graphics2D ) { Graphics2D g2d = ( Graphics2D ) g; //turn on high quality bitmap rendering g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY ); g2d.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC ); g2d.setRenderingHint( RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY ); g2d.translate( x, y ); g2d.drawImage( img, at, null ); g2d.translate( -x, -y ); } } } private static class VectorBusyIcon extends BusyIcon { private static final float MIN_ALPHA = 0.16f; private static final float MAX_ALPHA = 0.89f; private static final int ARMS = 12; private static final float STROKE_WIDTH = 1.25f; private static final double INNER_RADIUS = 4; private static final double OUTER_RADIUS = 7; private int darkestArm = 0; private VectorBusyIcon(int height) { super(height, height); } public static BusyIcon create() { return new VectorBusyIcon(getBusyIconSize()); } @Override void tick() { darkestArm = (darkestArm + 1) % ARMS; } @Override public void paintIcon(Component c, Graphics g0, int x, int y) { Graphics2D g = (Graphics2D) g0.create(); try { g.translate(x, y); paintHelper(g); } finally { g.dispose(); } } private void paintHelper(Graphics2D g) { g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); g.setStroke(new BasicStroke(STROKE_WIDTH, BasicStroke.CAP_ROUND, BasicStroke.CAP_ROUND)); g.translate(getIconWidth() / 2.0, getIconHeight() / 2.0); for (int i = 0; i < ARMS; i++) { g.setColor(new Color(0f, 0f, 0f, MIN_ALPHA + (MAX_ALPHA - MIN_ALPHA) * (float) Math.pow((((darkestArm + i) % ARMS) / (ARMS - 1.0f)), 3.0))); double angle = -(2 * Math.PI / ARMS) * i; double kY = Math.sin(angle); double kX = Math.cos(angle); g.draw(new Line2D.Double( INNER_RADIUS * kX, INNER_RADIUS * kY, OUTER_RADIUS * kX, OUTER_RADIUS * kY)); } } } private static int getBusyIconSize() { int res = UIManager.getInt( "Nb.BusyIcon.Height" ); if( res < 1 ) res = 16; return res; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy