Package org.jvnet.substance.utils

Source Code of org.jvnet.substance.utils.ButtonBackgroundDelegate

/*
* Copyright (c) 2005-2009 Substance Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  o Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
*  o Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
*  o Neither the name of Substance Kirill Grouchnikov nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jvnet.substance.utils;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Set;

import javax.swing.*;
import javax.swing.JInternalFrame.JDesktopIcon;

import org.jvnet.lafwidget.animation.*;
import org.jvnet.lafwidget.layout.TransitionLayout;
import org.jvnet.substance.SubstanceLookAndFeel;
import org.jvnet.substance.api.*;
import org.jvnet.substance.api.SubstanceConstants.Side;
import org.jvnet.substance.painter.border.SubstanceBorderPainter;
import org.jvnet.substance.painter.gradient.SubstanceGradientPainter;
import org.jvnet.substance.shaper.*;

/**
* Delegate class for painting backgrounds of buttons in <b>Substance </b> look
* and feel. This class is <b>for internal use only</b>.
*
* @author Kirill Grouchnikov
*/
public class ButtonBackgroundDelegate {
  /**
   * Cache for background images. Each time
   * {@link #getBackground(AbstractButton, SubstanceButtonShaper, SubstanceGradientPainter, int, int)}
   * is called, it checks <code>this</code> map to see if it already contains
   * such background. If so, the background from the map is returned.
   */
  private static LazyResettableHashMap<BufferedImage> regularBackgrounds = new LazyResettableHashMap<BufferedImage>(
      "ButtonBackgroundDelegate");

  /**
   * Retrieves the background for the specified button.
   *
   * @param button
   *            Button.
   * @param model
   *            Button model.
   * @param shaper
   *            Button shaper.
   * @param painter
   *            Button gradient painter.
   * @param borderPainter
   *            Button border painter.
   * @param width
   *            Button width.
   * @param height
   *            Button height.
   * @return Button background.
   */
  public static BufferedImage getFullAlphaBackground(AbstractButton button,
      ButtonModel model, SubstanceButtonShaper shaper,
      SubstanceGradientPainter painter,
      SubstanceBorderPainter borderPainter, int width, int height) {
    ComponentState state = ComponentState.getState(model, button);
    ComponentState prevState = SubstanceCoreUtilities
        .getPrevComponentState(button, null);

    // compute cycle count (for animation)
    float cyclePos = state.getCyclePosition();
    boolean isPulsating = false;
    if (button instanceof JButton) {
      JButton jb = (JButton) button;
      if (PulseTracker.isPulsating(jb)
          && (state != ComponentState.PRESSED_SELECTED)
          && (state != ComponentState.PRESSED_UNSELECTED)) {
        isPulsating = true;
        cyclePos = (int) (PulseTracker.getCycles(jb) % 20);
        if (cyclePos > 10) {
          cyclePos = 19 - cyclePos;
        }
        cyclePos /= 10.0f;
      }
    }

    // compute color scheme
    SubstanceColorScheme colorScheme = SubstanceColorSchemeUtilities
        .getColorScheme(button, state);
    SubstanceColorScheme colorScheme2 = colorScheme;
    SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
        .getColorScheme(button, ColorSchemeAssociationKind.BORDER,
            state);
    SubstanceColorScheme borderScheme2 = borderScheme;

    // see if need to use attention-drawing animation
    boolean isWindowModified = false;
    if (SubstanceCoreUtilities.isTitleCloseButton(button)) {
      // check if have windowModified property
      Component comp = button;
      while (comp != null) {
        if (comp instanceof JInternalFrame) {
          JInternalFrame jif = (JInternalFrame) comp;
          isWindowModified = Boolean.TRUE
              .equals(jif
                  .getClientProperty(SubstanceLookAndFeel.WINDOW_MODIFIED));
          break;
        }
        if (comp instanceof JRootPane) {
          JRootPane jrp = (JRootPane) comp;
          isWindowModified = Boolean.TRUE
              .equals(jrp
                  .getClientProperty(SubstanceLookAndFeel.WINDOW_MODIFIED));
          break;
        }
        if (comp instanceof JDesktopIcon) {
          JDesktopIcon jdi = (JDesktopIcon) comp;
          JInternalFrame jif = jdi.getInternalFrame();
          isWindowModified = Boolean.TRUE
              .equals(jif
                  .getClientProperty(SubstanceLookAndFeel.WINDOW_MODIFIED));
          break;
        }
        comp = comp.getParent();
      }
      if (isWindowModified) {
        colorScheme2 = SubstanceColorSchemeUtilities.YELLOW;
        colorScheme = SubstanceColorSchemeUtilities.ORANGE;
      }
    }

    // see if need to use fade animation. Important - don't do it
    // on pulsating buttons (such as default or close buttons
    // of modified frames).
    if (!isWindowModified && !isPulsating && model.isEnabled()) {
      FadeState fadeState = SubstanceFadeUtilities.getFadeState(button,
          FadeKind.ROLLOVER, FadeKind.SELECTION, FadeKind.PRESS);
      if (fadeState != null) {
        colorScheme = SubstanceColorSchemeUtilities.getColorScheme(
            button, state);
        colorScheme2 = SubstanceColorSchemeUtilities.getColorScheme(
            button, prevState);
        borderScheme = SubstanceColorSchemeUtilities.getColorScheme(
            button, ColorSchemeAssociationKind.BORDER, state);
        borderScheme2 = SubstanceColorSchemeUtilities.getColorScheme(
            button, ColorSchemeAssociationKind.BORDER, prevState);
        cyclePos = fadeState.getFadePosition();

        // System.out.println(extraModelKey + ":" + cyclePos);
        if (fadeState.isFadingIn())
          cyclePos = 1.0f - cyclePos;
      } else {
        // System.out.println(extraModelKey + ":" + state.name());
      }
    }
    // if (colorScheme == colorScheme2) {
    // System.out.println(extraModelKey + ":" + state.name() + ":"
    // + colorScheme.getDisplayName());
    // }

    // compute the straight sides
    Set<SubstanceConstants.Side> straightSides = SubstanceCoreUtilities
        .getSides(button, SubstanceLookAndFeel.BUTTON_SIDE_PROPERTY);
    String straightKey = "";
    for (Side sSide : straightSides) {
      straightKey += sSide.name() + "-";
    }

    boolean isRoundButton = StandardButtonShaper.isRoundButton(button);
    float radius = 0.0f;
    if (shaper instanceof RectangularButtonShaper) {
      radius = ((RectangularButtonShaper) shaper).getCornerRadius(button,
          null);
    }

    Set<Side> openSides = SubstanceCoreUtilities.getSides(button,
        SubstanceLookAndFeel.BUTTON_OPEN_SIDE_PROPERTY);
    // String openKey = "";
    // for (Side oSide : openSides) {
    // openKey += oSide.name() + "-";
    // }
    // String extraModelKey = "";
    // for (String modelKey : extraModelKeys) {
    // extraModelKey += (modelKey + "-");
    // }
    boolean isContentAreaFilled = button.isContentAreaFilled();
    boolean isBorderPainted = button.isBorderPainted();
    HashMapKey key = SubstanceCoreUtilities.getHashKey(width, height,
        prevState.name(), state.name(), cyclePos, colorScheme
            .getDisplayName(), colorScheme2.getDisplayName(),
        borderScheme.getDisplayName(), borderScheme2.getDisplayName(),
        shaper.getDisplayName(), painter.getDisplayName(),
        borderPainter.getDisplayName(), straightKey, openSides, button
            .getClass().getName(), isRoundButton, radius,
        isContentAreaFilled, isBorderPainted, SubstanceSizeUtils
            .getComponentFontSize(button));

    // System.out.println(component.getClass().getSimpleName() + ":"
    // + extraModelKeys + " "
    // + /* button.getText() + ":" + */prevState.name() + "->"
    // + state.name() + " - " + cyclePos);
    // System.out.println("\t" + colorScheme2.getDisplayName() + ":"
    // + colorScheme.getDisplayName());

    BufferedImage existing = regularBackgrounds.get(key);
    if (existing == null) {
      int openDelta = (int) (Math.ceil(3.0 * SubstanceSizeUtils
          .getBorderStrokeWidth(SubstanceSizeUtils
              .getComponentFontSize(button))));
      int deltaLeft = openSides.contains(Side.LEFT) ? openDelta : 0;
      int deltaRight = openSides.contains(Side.RIGHT) ? openDelta : 0;
      int deltaTop = openSides.contains(Side.TOP) ? openDelta : 0;
      int deltaBottom = openSides.contains(Side.BOTTOM) ? openDelta : 0;

      // System.err.println(key);
      int borderDelta = (int) Math.floor(SubstanceSizeUtils
          .getBorderStrokeWidth(SubstanceSizeUtils
              .getComponentFontSize(button)) / 2.0);
      Shape contour = shaper.getButtonOutline(button, new Insets(
          borderDelta, borderDelta, borderDelta, borderDelta), width
          + deltaLeft + deltaRight, height + deltaTop + deltaBottom,
          false);

      BufferedImage newBackground = SubstanceCoreUtilities.getBlankImage(
          width, height);
      Graphics2D finalGraphics = (Graphics2D) newBackground.getGraphics();
      finalGraphics.translate(-deltaLeft, -deltaTop);
      if (isContentAreaFilled) {
        painter.paintContourBackground(finalGraphics, button, width
            + deltaLeft + deltaRight, height + deltaTop
            + deltaBottom, contour, false, colorScheme,
            colorScheme2, cyclePos, true,
            colorScheme != colorScheme2);
      }

      if (isBorderPainted) {
        int borderThickness = (int) SubstanceSizeUtils
            .getBorderStrokeWidth(SubstanceSizeUtils
                .getComponentFontSize(button));
        Shape contourInner = borderPainter.isPaintingInnerContour() ? shaper
            .getButtonOutline(button, new Insets(borderDelta
                + borderThickness, borderDelta
                + borderThickness, borderDelta
                + borderThickness, borderDelta
                + borderThickness), width + deltaLeft
                + deltaRight, height + deltaTop + deltaBottom,
                true)
            : null;
        borderPainter.paintBorder(finalGraphics, button, width
            + deltaLeft + deltaRight, height + deltaTop
            + deltaBottom, contour, contourInner, borderScheme,
            borderScheme2, cyclePos, borderScheme != borderScheme2);
      }

      regularBackgrounds.put(key, newBackground);
    }
    existing = regularBackgrounds.get(key);
    // existing.validate(GraphicsEnvironment.getLocalGraphicsEnvironment()
    // .getDefaultScreenDevice().getDefaultConfiguration());
    return existing;
  }

  /**
   * Simple constructor.
   */
  public ButtonBackgroundDelegate() {
    super();
  }

  /**
   * Updates background of the specified button.
   *
   * @param g
   *            Graphic context.
   * @param button
   *            Button to update.
   */
  public void updateBackground(Graphics g, AbstractButton button) {
    // failsafe for LAF change
    if (!SubstanceLookAndFeel.isCurrentLookAndFeel())
      return;

    if (SubstanceCoreUtilities.isButtonNeverPainted(button))
      return;

    int width = button.getWidth();
    int height = button.getHeight();
    int y = 0;
    if (SubstanceCoreUtilities.isScrollButton(button)
        || SubstanceCoreUtilities.isSpinnerButton(button)) {
      Sideable sideable = (Sideable) button;
      PairwiseButtonBackgroundDelegate.updatePairwiseBackground(g,
          button, width, height, sideable.getSide(), false);
      return;
    }

    SubstanceGradientPainter painter = SubstanceCoreUtilities
        .getGradientPainter(button);
    SubstanceButtonShaper shaper = SubstanceCoreUtilities
        .getButtonShaper(button);
    SubstanceBorderPainter borderPainter = SubstanceCoreUtilities
        .getBorderPainter(button);

    BufferedImage bgImage = getFullAlphaBackground(button, button
        .getModel(), shaper, painter, borderPainter, width, height);
    ComponentState state = ComponentState.getState(button);

    // Two special cases here:
    // 1. Button has flat appearance.
    // 2. Button is disabled.
    // For both cases, we need to set custom translucency.
    boolean isFlat = SubstanceCoreUtilities.hasFlatAppearance(button);
    boolean isSpecial = isFlat || !state.isKindActive(FadeKind.ENABLE);
    float extraAlpha = 1.0f;
    if (isSpecial) {
      if (isFlat) {
        // Special handling of flat buttons
        if (FadeTracker.getInstance().isTracked(button,
            FadeKind.ROLLOVER)
            && !state.isKindActive(FadeKind.SELECTION)
            && state.isKindActive(FadeKind.ENABLE)) {
          extraAlpha = FadeTracker.getInstance().getFade(button,
              FadeKind.ROLLOVER);
        } else {
          if (state == ComponentState.DEFAULT) {
            // flat button in default state and not
            // participating in rollover animation
            extraAlpha = 0.0f;
          }
        }
        if (state == ComponentState.DISABLED_UNSELECTED)
          extraAlpha = 0.0f;
      } else {
        if (!state.isKindActive(FadeKind.ENABLE)) {
          extraAlpha = SubstanceColorSchemeUtilities.getAlpha(button,
              state);
        }
      }
    }
    if (extraAlpha > 0.0f) {
      Graphics2D graphics = (Graphics2D) g.create();
      graphics.setComposite(TransitionLayout.getAlphaComposite(button,
          extraAlpha, g));
      graphics.drawImage(bgImage, 0, y, null);
      graphics.dispose();
    }
  }

  /**
   * Checks whether the specified button has round corners.
   *
   * @param button
   *            Button to check.
   * @return <code>true</code> if the specified button has round corners,
   *         <code>false</code> otherwise.
   */
  public static boolean isRoundButton(AbstractButton button) {
    return (!SubstanceCoreUtilities.isComboBoxButton(button))
        && (!SubstanceCoreUtilities.isScrollButton(button))
        && SubstanceCoreUtilities.hasText(button);
  }

  /**
   * Returns <code>true</code> if the specified <i>x,y </i> location is
   * contained within the look and feel's defined shape of the specified
   * component. <code>x</code> and <code>y</code> are defined to be relative
   * to the coordinate system of the specified component.
   *
   * @param button
   *            the component where the <i>x,y </i> location is being queried;
   * @param x
   *            the <i>x </i> coordinate of the point
   * @param y
   *            the <i>y </i> coordinate of the point
   * @return <code>true</code> if the specified <i>x,y </i> location is
   *         contained within the look and feel's defined shape of the
   *         specified component, <code>false</code> otherwise.
   */
  public static boolean contains(AbstractButton button, int x, int y) {
    // failsafe for LAF change
    if (!SubstanceLookAndFeel.isCurrentLookAndFeel()) {
      return false;
    }
    SubstanceButtonShaper shaper = SubstanceCoreUtilities
        .getButtonShaper(button);
    if (shaper == null)
      return false;
    Shape contour = shaper.getButtonOutline(button, null,
        button.getWidth(), button.getHeight(), false);
    return contour.contains(x, y);
  }

  /**
   * Returns the memory usage string.
   *
   * @return Memory usage string.
   */
  static String getMemoryUsage() {
    StringBuffer sb = new StringBuffer();
    sb.append("SubstanceBackgroundDelegate: \n");
    sb.append("\t" + regularBackgrounds.size() + " regular");
    // + pairwiseBackgrounds.size() + " pairwise");
    return sb.toString();
  }

}
TOP

Related Classes of org.jvnet.substance.utils.ButtonBackgroundDelegate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.