/plugins/Substance/trunk/substance-6.1/substance/src/org/pushingpixels/substance/internal/utils/SubstanceDropDownButton.java

# · Java · 200 lines · 133 code · 27 blank · 40 comment · 13 complexity · db3c06d2370cc3a1de315752a408c1a1 MD5 · raw file

  1. /*
  2. * Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. *
  7. * o Redistributions of source code must retain the above copyright notice,
  8. * this list of conditions and the following disclaimer.
  9. *
  10. * o Redistributions in binary form must reproduce the above copyright notice,
  11. * this list of conditions and the following disclaimer in the documentation
  12. * and/or other materials provided with the distribution.
  13. *
  14. * o Neither the name of Substance Kirill Grouchnikov nor the names of
  15. * its contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  20. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  21. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  22. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  25. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  26. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  27. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  28. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. package org.pushingpixels.substance.internal.utils;
  31. import java.awt.*;
  32. import java.awt.image.BufferedImage;
  33. import java.util.Map;
  34. import javax.swing.*;
  35. import javax.swing.border.Border;
  36. import org.pushingpixels.lafwidget.LafWidgetUtilities;
  37. import org.pushingpixels.lafwidget.animation.AnimationConfigurationManager;
  38. import org.pushingpixels.lafwidget.animation.AnimationFacet;
  39. import org.pushingpixels.substance.api.*;
  40. import org.pushingpixels.substance.internal.animation.StateTransitionTracker;
  41. import org.pushingpixels.substance.internal.animation.TransitionAwareUI;
  42. /**
  43. * Drop down button in <b>Substance</b> look and feel.
  44. *
  45. * @author Kirill Grouchnikov
  46. */
  47. public final class SubstanceDropDownButton extends JButton implements
  48. SubstanceInternalArrowButton {
  49. static {
  50. AnimationConfigurationManager.getInstance().disallowAnimations(
  51. AnimationFacet.GHOSTING_BUTTON_PRESS,
  52. SubstanceDropDownButton.class);
  53. AnimationConfigurationManager.getInstance().disallowAnimations(
  54. AnimationFacet.GHOSTING_ICON_ROLLOVER,
  55. SubstanceDropDownButton.class);
  56. }
  57. /**
  58. * Simple constructor.
  59. *
  60. * @param parent
  61. * The parent component.
  62. */
  63. public SubstanceDropDownButton(JComponent parent) {
  64. super("");
  65. this.setModel(new DefaultButtonModel() {
  66. @Override
  67. public void setArmed(boolean armed) {
  68. super.setArmed(this.isPressed() || armed);
  69. }
  70. });
  71. this.setEnabled(parent.isEnabled());
  72. this.setFocusable(false);
  73. this.setRequestFocusEnabled(parent.isEnabled());
  74. int fontSize = SubstanceSizeUtils.getComponentFontSize(parent);
  75. int tbInset = SubstanceSizeUtils.getAdjustedSize(fontSize, 1, 2, 1,
  76. false);
  77. int lrInset = 0;
  78. this.setMargin(new Insets(tbInset, lrInset, tbInset, tbInset));
  79. this.setBorderPainted(false);
  80. this.putClientProperty(SubstanceLookAndFeel.FLAT_PROPERTY, Boolean.TRUE);
  81. this.setOpaque(false);
  82. }
  83. @Override
  84. public void setBorder(Border border) {
  85. }
  86. @Override
  87. protected void paintBorder(Graphics g) {
  88. if (SubstanceCoreUtilities.isButtonNeverPainted(this)) {
  89. return;
  90. }
  91. TransitionAwareUI transitionAwareUI = (TransitionAwareUI) this.getUI();
  92. StateTransitionTracker stateTransitionTracker = transitionAwareUI
  93. .getTransitionTracker();
  94. StateTransitionTracker.ModelStateInfo modelStateInfo = stateTransitionTracker
  95. .getModelStateInfo();
  96. Map<ComponentState, StateTransitionTracker.StateContributionInfo> activeStates = modelStateInfo
  97. .getStateContributionMap();
  98. ComponentState currState = modelStateInfo.getCurrModelState();
  99. float extraAlpha = stateTransitionTracker.getActiveStrength();
  100. if (currState == ComponentState.DISABLED_UNSELECTED)
  101. extraAlpha = 0.0f;
  102. if (extraAlpha == 0.0f)
  103. return;
  104. int componentFontSize = SubstanceSizeUtils.getComponentFontSize(this);
  105. int borderDelta = (int) Math.floor(1.5 * SubstanceSizeUtils
  106. .getBorderStrokeWidth(componentFontSize));
  107. float radius = Math.max(0, 2.0f
  108. * SubstanceSizeUtils
  109. .getClassicButtonCornerRadius(componentFontSize)
  110. - borderDelta);
  111. int width = getWidth();
  112. int height = getHeight();
  113. int offsetX = this.getX();
  114. int offsetY = this.getY();
  115. JComponent parent = (JComponent) this.getParent();
  116. SubstanceColorScheme baseBorderScheme = SubstanceColorSchemeUtilities
  117. .getColorScheme(this, ColorSchemeAssociationKind.BORDER,
  118. currState);
  119. BufferedImage offscreen = SubstanceCoreUtilities.getBlankImage(width,
  120. height);
  121. Graphics2D g2offscreen = offscreen.createGraphics();
  122. SubstanceImageCreator.paintTextComponentBorder(this, g2offscreen, 0, 0,
  123. width, height, radius, baseBorderScheme);
  124. g2offscreen.translate(-offsetX, -offsetY);
  125. SubstanceImageCreator.paintTextComponentBorder(parent, g2offscreen, 0,
  126. 0, parent.getWidth(), parent.getHeight(), radius,
  127. baseBorderScheme);
  128. g2offscreen.translate(offsetX, offsetY);
  129. for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : activeStates
  130. .entrySet()) {
  131. ComponentState activeState = activeEntry.getKey();
  132. if (activeState == currState)
  133. continue;
  134. float contribution = activeEntry.getValue().getContribution();
  135. if (contribution == 0.0f)
  136. continue;
  137. g2offscreen.setComposite(AlphaComposite.SrcOver
  138. .derive(contribution));
  139. SubstanceColorScheme borderScheme = SubstanceColorSchemeUtilities
  140. .getColorScheme(this, ColorSchemeAssociationKind.BORDER,
  141. activeState);
  142. SubstanceImageCreator.paintTextComponentBorder(this, g2offscreen,
  143. 0, 0, width, height, radius, borderScheme);
  144. g2offscreen.translate(-offsetX, -offsetY);
  145. SubstanceImageCreator.paintTextComponentBorder(parent, g2offscreen,
  146. 0, 0, parent.getWidth(), parent.getHeight(), radius,
  147. borderScheme);
  148. g2offscreen.translate(offsetX, offsetY);
  149. }
  150. g2offscreen.dispose();
  151. Graphics2D g2d = (Graphics2D) g.create();
  152. g2d.setComposite(LafWidgetUtilities.getAlphaComposite(this, extraAlpha,
  153. g));
  154. g2d.drawImage(offscreen, 0, 0, null);
  155. g2d.dispose();
  156. }
  157. @Override
  158. public void paint(Graphics g) {
  159. Graphics2D g2d = (Graphics2D) g.create();
  160. int componentFontSize = SubstanceSizeUtils.getComponentFontSize(this);
  161. int width = getWidth();
  162. int height = getHeight();
  163. int clipDelta = (int) SubstanceSizeUtils
  164. .getBorderStrokeWidth(componentFontSize);
  165. if (this.getComponentOrientation().isLeftToRight()) {
  166. g2d.clipRect(clipDelta, 0, width - clipDelta, height);
  167. } else {
  168. g2d.clipRect(0, 0, width - clipDelta, height);
  169. }
  170. super.paint(g2d);
  171. g2d.dispose();
  172. }
  173. }